From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.2 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,USER_AGENT_SANE_2 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA5E0C2D0CE for ; Fri, 3 Jan 2020 05:55:20 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6120621734 for ; Fri, 3 Jan 2020 05:55:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="T0ZcriIK"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="L8xYRhmV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6120621734 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Date:To:From:Subject:Message-ID:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=XGFZ0d6qIKhpBMl8e+KrQxsZgbJS+lUHt41pMTLzML0=; b=T0ZcriIKBXiuto NQJt3hEgu3RAcP7CffyL40fxjRP9EXMMZ+AI2JXZQqF2FuYhQCfBC2hrXYY6Jjg/4UbI+34meUUuC Z5zUsMsU0Fo8oANURDVPhS3tDQH+0w5jCbISot1IOrXYqWA8LlnEU2ygefgYy3Ry9hmPLC0r/WdSP TyFRiglYIH8XJUd5ERw1GiOi3tpg6F/7Sk8lUNppGWBJ9obIIBJWCScT3sbTUU2sECdRjqfn53iYm +Wc0tzLlOlzjc8dcvOM5v8Kx3kJdAZWk3Mmg8n5OyDBjy0p+WBPMTwOyliK3XFE/iJtu8vcKhaZM/ EOrHUG5oNUHHcFTykP8A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1inFvb-000753-L1; Fri, 03 Jan 2020 05:55:19 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1inFvV-00074H-AZ; Fri, 03 Jan 2020 05:55:18 +0000 X-UUID: 46dcfd2d8b244249b7953ff7f8117c95-20200102 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=JNRfAfDLAyXxpHtn3SvuzDUGpMWxlxKC54Aay/GuRbs=; b=L8xYRhmVmjczS7o647tyFG651d9sTN8P/sV8/T/YSj0v2qT7yoZJPAGpw1Pu94M9qKLLXLZpaYBIkNlgPiXNi/kLVZkV1+v9/WFnj2qwt06FaRB+VWRox8NcFsuVcXrclSKVvpxP+hDQX8JHW8vIKhjGPLl9SftLG9Hsfw3icQk=; X-UUID: 46dcfd2d8b244249b7953ff7f8117c95-20200102 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 844353794; Thu, 02 Jan 2020 21:55:08 -0800 Received: from MTKMBS01N2.mediatek.inc (172.21.101.79) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 2 Jan 2020 21:45:08 -0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs01n2.mediatek.inc (172.21.101.79) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 3 Jan 2020 13:42:56 +0800 Received: from [172.21.77.4] (172.21.77.4) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Fri, 3 Jan 2020 13:44:49 +0800 Message-ID: <1578030290.10850.45.camel@mtksdaap41> Subject: Re: [PATCH v5 3/3] PM / AVS: SVS: Introduce SVS engine From: Roger Lu To: Kevin Hilman Date: Fri, 3 Jan 2020 13:44:50 +0800 In-Reply-To: <7hpnjmiswn.fsf@baylibre.com> References: <20190906100514.30803-1-roger.lu@mediatek.com> <20190906100514.30803-4-roger.lu@mediatek.com> <7hpnjmiswn.fsf@baylibre.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: D7704B8214DDB3A76E72843BDF025556B78AC5F37EAEF28A2E40DE73002FBEE72000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200102_215514_355820_9BAB1E1B X-CRM114-Status: GOOD ( 25.41 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Nicolas Boichat , Angus Lin , Kevin Hilman , Stephen Boyd , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, HenryC Chen , yt.lee@mediatek.com, Fan Chen , devicetree@vger.kernel.org, Rob Herring , linux-mediatek@lists.infradead.org, Matthias Brugger , Nishanth Menon , linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Dear Kevin Sir, Sorry for the late reply and thanks for the advice to this patch. On Thu, 2019-09-26 at 15:39 -0700, Kevin Hilman wrote: > Hi Roger, > > Roger Lu writes: > > > The SVS (Smart Voltage Scaling) engine is a piece of hardware which is > > used to calculate optimized voltage values of several power domains, e.g. > > CPU/GPU/CCI, according to chip process corner, temperatures, and other > > factors. Then DVFS driver could apply those optimized voltage values to > > reduce power consumption. > > > > Signed-off-by: Roger Lu > > I don't have any documentation on this SVS hardware, so I won't be able > to comment on the specific functionality, so I attempted a first-pass > high-level review... Excuse me, we don't have the documentation for SVS hardware. I'll try my best to introduce SVS online. > > In the absence of documentation, it would be helpful to give a high > level description of how this hardware works. In particular, a > high-level overview of the control loop, which appears to be primarily > interrupt driven, would be helpful. e.g. how often are the interrupts > firing, and why. 1. MT8183 SVS has 4 controllers (banks). One bank for optimizing one power-domain OPP voltages. - 4 power-domain (CPU-little / CPU-BIG / CCI / GPU) OPP voltages will be optimized by SVS banks.. 2. Each SVS bank needs to run its init01/init02 separately so that SVS bank's optimized OPP voltages can be calculated to system. - init01: SVS bank basic init (must) - init02: SVS bank provide high temperature OPP voltages (must) - mon mode: SVS bank dynamically optimizes OPP voltages basing on temperature change. (optional) 3. SVS interrupt behavior - In init01/init02, SVS only fire one interrupt to inform SW that init is finished and optimized OPP voltages are ready. - In mon mode, SVS fire interrupt when temperature changes. Mon mode interrupt is also for informing new optimized OPP voltages are ready. > > It's hard to understand the "init01" vs the "init02" patch since > those names aren't very descriptive. :) > > Also, there are lots of hard-coded constants (masks, shifts, etc.) used > throughout the calculations. #defines could help readability for many > of these, especially the masks. > > > --- > > drivers/power/avs/Kconfig | 10 + > > drivers/power/avs/Makefile | 1 + > > drivers/power/avs/mtk_svs.c | 2075 +++++++++++++++++++++++++++++++++ > > include/linux/power/mtk_svs.h | 23 + > > 4 files changed, 2109 insertions(+) > > create mode 100644 drivers/power/avs/mtk_svs.c > > create mode 100644 include/linux/power/mtk_svs.h > > > > diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig > > index b5a217b828dc..7c72504d5593 100644 > > --- a/drivers/power/avs/Kconfig > > +++ b/drivers/power/avs/Kconfig > > @@ -19,3 +19,13 @@ config ROCKCHIP_IODOMAIN > > Say y here to enable support io domains on Rockchip SoCs. It is > > necessary for the io domain setting of the SoC to match the > > voltage supplied by the regulators. > > + > > +config MTK_SVS > > + bool "MediaTek Smart Voltage Scaling(SVS)" > > + depends on POWER_AVS && MTK_EFUSE > > + help > > + The SVS engine is a piece of hardware which is used to calculate > > + optimized voltage values of several power domains, e.g. > > + CPU clusters/GPU/CCI, according to chip process corner, temperatures, > > + and other factors. Then DVFS driver could apply those optimized voltage > > + values to reduce power consumption. > > diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile > > index a1b8cd453f19..57246b977a93 100644 > > --- a/drivers/power/avs/Makefile > > +++ b/drivers/power/avs/Makefile > > @@ -1,3 +1,4 @@ > > # SPDX-License-Identifier: GPL-2.0-only > > obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o > > obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o > > +obj-$(CONFIG_MTK_SVS) += mtk_svs.o > > diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c > > new file mode 100644 > > index 000000000000..78ec93c3a4a5 > > --- /dev/null > > +++ b/drivers/power/avs/mtk_svs.c > > @@ -0,0 +1,2075 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2018 MediaTek Inc. > > + */ > > + > > +#define pr_fmt(fmt) "[mtk_svs] " fmt > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define SVS_INIT01_VOLT_IGNORE 1 > > +#define SVS_INIT01_VOLT_INC_ONLY 2 > > + > > +#define SVS_PHASE_INIT01 0 > > +#define SVS_PHASE_INIT02 1 > > +#define SVS_PHASE_MON 2 > > +#define SVS_PHASE_ERROR 3 > > + > > +#define SVS_CPU_LITTLE 1 > > +#define SVS_CPU_BIG 2 > > +#define SVS_CCI 3 > > +#define SVS_GPU 4 > > + > > +#define proc_fops_rw(name) \ > > + static int name ## _proc_open(struct inode *inode, \ > > + struct file *file) \ > > + { \ > > + return single_open(file, name ## _proc_show, \ > > + PDE_DATA(inode)); \ > > + } \ > > + static const struct file_operations name ## _proc_fops = { \ > > + .owner = THIS_MODULE, \ > > + .open = name ## _proc_open, \ > > + .read = seq_read, \ > > + .llseek = seq_lseek, \ > > + .release = single_release, \ > > + .write = name ## _proc_write, \ > > + } > > + > > +#define proc_fops_ro(name) \ > > + static int name ## _proc_open(struct inode *inode, \ > > + struct file *file) \ > > + { \ > > + return single_open(file, name ## _proc_show, \ > > + PDE_DATA(inode)); \ > > + } \ > > + static const struct file_operations name ## _proc_fops = { \ > > + .owner = THIS_MODULE, \ > > + .open = name ## _proc_open, \ > > + .read = seq_read, \ > > + .llseek = seq_lseek, \ > > + .release = single_release, \ > > + } > > + > > +#define proc_entry(name) {__stringify(name), &name ## _proc_fops} > > + > > +static DEFINE_SPINLOCK(mtk_svs_lock); > > +struct mtk_svs; > > + > > +enum reg_index { > > + TEMPMONCTL0 = 0, > > + TEMPMONCTL1, > > + TEMPMONCTL2, > > + TEMPMONINT, > > + TEMPMONINTSTS, > > + TEMPMONIDET0, > > + TEMPMONIDET1, > > + TEMPMONIDET2, > > + TEMPH2NTHRE, > > + TEMPHTHRE, > > + TEMPCTHRE, > > + TEMPOFFSETH, > > + TEMPOFFSETL, > > + TEMPMSRCTL0, > > + TEMPMSRCTL1, > > + TEMPAHBPOLL, > > + TEMPAHBTO, > > + TEMPADCPNP0, > > + TEMPADCPNP1, > > + TEMPADCPNP2, > > + TEMPADCMUX, > > + TEMPADCEXT, > > + TEMPADCEXT1, > > + TEMPADCEN, > > + TEMPPNPMUXADDR, > > + TEMPADCMUXADDR, > > + TEMPADCEXTADDR, > > + TEMPADCEXT1ADDR, > > + TEMPADCENADDR, > > + TEMPADCVALIDADDR, > > + TEMPADCVOLTADDR, > > + TEMPRDCTRL, > > + TEMPADCVALIDMASK, > > + TEMPADCVOLTAGESHIFT, > > + TEMPADCWRITECTRL, > > + TEMPMSR0, > > + TEMPMSR1, > > + TEMPMSR2, > > + TEMPADCHADDR, > > + TEMPIMMD0, > > + TEMPIMMD1, > > + TEMPIMMD2, > > + TEMPMONIDET3, > > + TEMPADCPNP3, > > + TEMPMSR3, > > + TEMPIMMD3, > > + TEMPPROTCTL, > > + TEMPPROTTA, > > + TEMPPROTTB, > > + TEMPPROTTC, > > + TEMPSPARE0, > > + TEMPSPARE1, > > + TEMPSPARE2, > > + TEMPSPARE3, > > + TEMPMSR0_1, > > + TEMPMSR1_1, > > + TEMPMSR2_1, > > + TEMPMSR3_1, > > + DESCHAR, > > + 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, > > + reg_num, > > +}; > > + > > +static const u32 svs_regs_v2[] = { > > + [TEMPMONCTL0] = 0x000, > > + [TEMPMONCTL1] = 0x004, > > + [TEMPMONCTL2] = 0x008, > > + [TEMPMONINT] = 0x00c, > > + [TEMPMONINTSTS] = 0x010, > > + [TEMPMONIDET0] = 0x014, > > + [TEMPMONIDET1] = 0x018, > > + [TEMPMONIDET2] = 0x01c, > > + [TEMPH2NTHRE] = 0x024, > > + [TEMPHTHRE] = 0x028, > > + [TEMPCTHRE] = 0x02c, > > + [TEMPOFFSETH] = 0x030, > > + [TEMPOFFSETL] = 0x034, > > + [TEMPMSRCTL0] = 0x038, > > + [TEMPMSRCTL1] = 0x03c, > > + [TEMPAHBPOLL] = 0x040, > > + [TEMPAHBTO] = 0x044, > > + [TEMPADCPNP0] = 0x048, > > + [TEMPADCPNP1] = 0x04c, > > + [TEMPADCPNP2] = 0x050, > > + [TEMPADCMUX] = 0x054, > > + [TEMPADCEXT] = 0x058, > > + [TEMPADCEXT1] = 0x05c, > > + [TEMPADCEN] = 0x060, > > + [TEMPPNPMUXADDR] = 0x064, > > + [TEMPADCMUXADDR] = 0x068, > > + [TEMPADCEXTADDR] = 0x06c, > > + [TEMPADCEXT1ADDR] = 0x070, > > + [TEMPADCENADDR] = 0x074, > > + [TEMPADCVALIDADDR] = 0x078, > > + [TEMPADCVOLTADDR] = 0x07c, > > + [TEMPRDCTRL] = 0x080, > > + [TEMPADCVALIDMASK] = 0x084, > > + [TEMPADCVOLTAGESHIFT] = 0x088, > > + [TEMPADCWRITECTRL] = 0x08c, > > + [TEMPMSR0] = 0x090, > > + [TEMPMSR1] = 0x094, > > + [TEMPMSR2] = 0x098, > > + [TEMPADCHADDR] = 0x09c, > > + [TEMPIMMD0] = 0x0a0, > > + [TEMPIMMD1] = 0x0a4, > > + [TEMPIMMD2] = 0x0a8, > > + [TEMPMONIDET3] = 0x0b0, > > + [TEMPADCPNP3] = 0x0b4, > > + [TEMPMSR3] = 0x0b8, > > + [TEMPIMMD3] = 0x0bc, > > + [TEMPPROTCTL] = 0x0c0, > > + [TEMPPROTTA] = 0x0c4, > > + [TEMPPROTTB] = 0x0c8, > > + [TEMPPROTTC] = 0x0cc, > > + [TEMPSPARE0] = 0x0f0, > > + [TEMPSPARE1] = 0x0f4, > > + [TEMPSPARE2] = 0x0f8, > > + [TEMPSPARE3] = 0x0fc, > > + [TEMPMSR0_1] = 0x190, > > + [TEMPMSR1_1] = 0x194, > > + [TEMPMSR2_1] = 0x198, > > + [TEMPMSR3_1] = 0x1b8, > > + [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 { > > + 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; > > +}; > > + > > +struct svs_bank_ops { > > + void (*set_freqs_pct)(struct mtk_svs *svs); > > + void (*get_vops)(struct mtk_svs *svs); > > +}; > > + > > +struct svs_bank { > > + struct svs_bank_ops *ops; > > + struct completion init_completion; > > + struct device *dev; > > + struct regulator *buck; > > + struct mutex lock; /* lock to protect update voltage process */ > > + bool suspended; > > + bool mtcmos_request; > > + bool init01_support; > > + bool init02_support; > > + bool mon_mode_support; > > + s32 volt_offset; > > + u32 *opp_freqs; > > + u32 *freqs_pct; > > + u32 *opp_volts; > > + u32 *init02_volts; > > + u32 *volts; > > + u32 reg_data[3][reg_num]; > > + u32 freq_base; > > + u32 vboot; > > + u32 volt_step; > > + u32 volt_base; > > + u32 init01_volt_flag; > > + u32 phase; > > + u32 vmax; > > + u32 vmin; > > + 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 chkshift; > > + u32 svs_temp; > > + u32 upper_temp_bound; > > + u32 lower_temp_bound; > > + u32 low_temp_threashold; > > + u32 low_temp_offset; > > + u32 coresel; > > + u32 opp_count; > > + u32 intst; > > + u32 systemclk_en; > > + u32 sw_id; > > + u32 hw_id; > > + u32 ctl0; > > + u8 *of_compatible; > > + u8 *name; > > + u8 *zone_name; > > + u8 *buck_name; > > +}; > > + > > +struct svs_platform { > > + struct svs_bank *banks; > > + int (*efuse_parsing)(struct mtk_svs *svs); > > + bool fake_efuse; > > + const u32 *regs; > > + u32 bank_num; > > + u32 efuse_num; > > + u32 efuse_check; > > + u32 thermal_efuse_num; > > + u8 *name; > > +}; > > + > > +struct mtk_svs { > > + const struct svs_platform *platform; > > + struct svs_bank *bank; > > + struct device *dev; > > + void __iomem *base; > > + struct clk *main_clk; > > + u32 *efuse; > > + u32 *thermal_efuse; > > +}; > > + > > +unsigned long claim_mtk_svs_lock(void) > > +{ > > + unsigned long flags; > > + > > + spin_lock_irqsave(&mtk_svs_lock, flags); > > + > > + return flags; > > +} > > +EXPORT_SYMBOL_GPL(claim_mtk_svs_lock); > > + > > +void release_mtk_svs_lock(unsigned long flags) > > +{ > > + spin_unlock_irqrestore(&mtk_svs_lock, flags); > > +} > > +EXPORT_SYMBOL_GPL(release_mtk_svs_lock); > > I don't see the need for these wrapper functions. You seem to be > declaring this lock in the header which implies there are external > users, but there is none in this series, so this lock should stay local > IMO. This export API is for mtk thermal driver. https://patchwork.kernel.org/patch/10938841/ > > > +static u32 percent(u32 numerator, u32 denominator) > > +{ > > + u32 percent; > > + > > + /* If not divide 1000, "numerator * 100" would be data overflow. */ > > + numerator /= 1000; > > + denominator /= 1000; > > + percent = ((numerator * 100) + denominator - 1) / denominator; > > + > > + return percent; > > +} > > Maybe some math helpers from math64.h would help you not have to > open-code this? Oh, thanks for the reminding. I haven't found the suitable "percent() API" from math64.h and will keep looking suitable API to replace these codes. > > > +static u32 svs_readl(struct mtk_svs *svs, enum reg_index i) > > +{ > > + return readl(svs->base + svs->platform->regs[i]); > > +} > > + > > +static void svs_writel(struct mtk_svs *svs, u32 val, enum reg_index i) > > +{ > > + writel(val, svs->base + svs->platform->regs[i]); > > +} > > + > > +static void svs_switch_bank(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + > > + svs_writel(svs, svsb->coresel, CORESEL); > > +} > > + > > +static u32 svs_volt_to_opp_volt(u32 svsb_volt, > > + u32 svsb_volt_step, u32 svsb_volt_base) > > +{ > > + u32 u_volt; > > + > > + u_volt = (svsb_volt * svsb_volt_step) + svsb_volt_base; > > + > > + return u_volt; > > +} > > + > > +static int svs_get_zone_temperature(struct svs_bank *svsb, int *zone_temp) > > +{ > > + struct thermal_zone_device *tzd; > > + int ret; > > + > > + tzd = thermal_zone_get_zone_by_name(svsb->zone_name); > > + ret = thermal_zone_get_temp(tzd, zone_temp); > > + > > + return ret; > > +} > > + > > +static int svs_set_volts(struct svs_bank *svsb, bool force_update) > > +{ > > + u32 i, svsb_volt, opp_volt, low_temp_offset = 0; > > + int zone_temp, ret; > > + > > + mutex_lock(&svsb->lock); > > + > > + /* If bank is suspended, it means init02 voltage is applied. > > + * Don't need to update opp voltage anymore. > > + */ > > minor nit: fix multi-line comment style Sure. I'll fix it in the next patch.Thanks. > > > + if (svsb->suspended && !force_update) { > > + pr_notice("%s: bank is suspended\n", svsb->name); > > + mutex_unlock(&svsb->lock); > > + return -EPERM; > > + } > > + > > + /* get thermal effect */ > > + if (svsb->phase == SVS_PHASE_MON) { > > + if (svsb->svs_temp > svsb->upper_temp_bound && > > + svsb->svs_temp < svsb->lower_temp_bound) { > > + pr_err("%s: svs_temp is abnormal (0x%x)?\n", > > + svsb->name, svsb->svs_temp); > > + mutex_unlock(&svsb->lock); > > + return -EINVAL; > > + } > > + > > + ret = svs_get_zone_temperature(svsb, &zone_temp); > > + if (ret) { > > + pr_err("%s: cannot get zone \"%s\" temperature\n", > > + svsb->name, svsb->zone_name); > > + pr_err("%s: add low_temp_offset = %u\n", > > + svsb->name, svsb->low_temp_offset); > > + zone_temp = svsb->low_temp_threashold; > > + } > > + > > + if (zone_temp <= svsb->low_temp_threashold) > > + low_temp_offset = svsb->low_temp_offset; > > + } > > + > > + /* vmin <= svsb_volt (opp_volt) <= signed-off voltage */ > > + for (i = 0; i < svsb->opp_count; i++) { > > + if (svsb->phase == SVS_PHASE_MON) { > > + svsb_volt = max((svsb->volts[i] + svsb->volt_offset + > > + low_temp_offset), svsb->vmin); > > + opp_volt = svs_volt_to_opp_volt(svsb_volt, > > + svsb->volt_step, > > + svsb->volt_base); > > + } else if (svsb->phase == SVS_PHASE_INIT02) { > > + svsb_volt = max((svsb->init02_volts[i] + > > + svsb->volt_offset), svsb->vmin); > > + opp_volt = svs_volt_to_opp_volt(svsb_volt, > > + svsb->volt_step, > > + svsb->volt_base); > > + } else if (svsb->phase == SVS_PHASE_ERROR) { > > + opp_volt = svsb->opp_volts[i]; > > + } else { > > + pr_err("%s: unknown phase: %u?\n", > > + svsb->name, svsb->phase); > > + mutex_unlock(&svsb->lock); > > + return -EINVAL; > > + } > > + > > + opp_volt = min(opp_volt, svsb->opp_volts[i]); > > + ret = dev_pm_opp_adjust_voltage(svsb->dev, svsb->opp_freqs[i], > > + opp_volt); > > + if (ret) { > > + pr_err("%s: set voltage failed: %d\n", svsb->name, ret); > > + mutex_unlock(&svsb->lock); > > + return ret; > > + } > > + } > > + > > + mutex_unlock(&svsb->lock); > > + > > + return 0; > > +} > > + > > +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx) > > +{ > > + u32 vy; > > + > > + if (v0 == v1 || f0 == f1) > > + return v0; > > + > > + /* *100 to have decimal fraction factor, +99 for rounding up. */ > > + vy = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx)); > > + vy = (vy + 99) / 100; > > + > > + return vy; > > +} > > + > > +static void svs_get_vops_v2(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + u32 temp, i; > > + > > + temp = svs_readl(svs, VOP30); > > + svsb->volts[6] = (temp >> 24) & 0xff; > > + svsb->volts[4] = (temp >> 16) & 0xff; > > + svsb->volts[2] = (temp >> 8) & 0xff; > > + svsb->volts[0] = (temp & 0xff); > > + > > + temp = svs_readl(svs, VOP74); > > + svsb->volts[14] = (temp >> 24) & 0xff; > > + svsb->volts[12] = (temp >> 16) & 0xff; > > + svsb->volts[10] = (temp >> 8) & 0xff; > > + svsb->volts[8] = (temp & 0xff); > > + > > + for (i = 0; i <= 7; i++) { > > + if (i < 7) { > > + svsb->volts[(i * 2) + 1] = > > + interpolate(svsb->freqs_pct[i * 2], > > + svsb->freqs_pct[(i + 1) * 2], > > + svsb->volts[i * 2], > > + svsb->volts[(i + 1) * 2], > > + svsb->freqs_pct[(i * 2) + 1]); > > + } else if (i == 7) { > > + svsb->volts[(i * 2) + 1] = > > + interpolate(svsb->freqs_pct[(i - 1) * 2], > > + svsb->freqs_pct[i * 2], > > + svsb->volts[(i - 1) * 2], > > + svsb->volts[i * 2], > > + svsb->freqs_pct[(i * 2) + 1]); > > + } > > + } > > +} > > + > > +static void svs_set_freqs_pct_v2(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + > > + svs_writel(svs, > > + ((svsb->freqs_pct[6] << 24) & 0xff000000) | > > + ((svsb->freqs_pct[4] << 16) & 0xff0000) | > > + ((svsb->freqs_pct[2] << 8) & 0xff00) | > > + (svsb->freqs_pct[0] & 0xff), > > + FREQPCT30); > > + svs_writel(svs, > > + ((svsb->freqs_pct[14] << 24) & 0xff000000) | > > + ((svsb->freqs_pct[12] << 16) & 0xff0000) | > > + ((svsb->freqs_pct[10] << 8) & 0xff00) | > > + ((svsb->freqs_pct[8]) & 0xff), > > + FREQPCT74); > > +} > > + > > +static void svs_set_phase(struct mtk_svs *svs, u32 target_phase) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + u32 des_char, temp_char, det_char, limit_vals; > > + u32 init2vals, ts_calcs, val, filter, i; > > + > > + svs_switch_bank(svs); > > + > > + des_char = ((svsb->bdes << 8) & 0xff00) | (svsb->mdes & 0xff); > > + svs_writel(svs, des_char, DESCHAR); > > + > > + temp_char = ((svsb->vco << 16) & 0xff0000) | > > + ((svsb->mtdes << 8) & 0xff00) | > > + (svsb->dvt_fixed & 0xff); > > + svs_writel(svs, temp_char, TEMPCHAR); > > + > > + det_char = ((svsb->dcbdet << 8) & 0xff00) | (svsb->dcmdet & 0xff); > > + svs_writel(svs, det_char, DETCHAR); > > + > > + svs_writel(svs, svsb->dc_config, DCCONFIG); > > + svs_writel(svs, svsb->age_config, AGECONFIG); > > + > > + if (svsb->agem == 0x0) { > > + svs_writel(svs, 0x80000000, RUNCONFIG); > > + } else { > > + val = 0x0; > > + > > + for (i = 0; i < 24; i += 2) { > > + filter = 0x3 << i; > > + > > + if ((svsb->age_config & filter) == 0x0) > > + val |= (0x1 << i); > > + else > > + val |= (svsb->age_config & filter); > > + } > > + svs_writel(svs, val, RUNCONFIG); > > + } > > + > > + svsb->ops->set_freqs_pct(svs); > > + > > + limit_vals = ((svsb->vmax << 24) & 0xff000000) | > > + ((svsb->vmin << 16) & 0xff0000) | > > + ((svsb->dthi << 8) & 0xff00) | > > + (svsb->dtlo & 0xff); > > + svs_writel(svs, limit_vals, LIMITVALS); > > + svs_writel(svs, (svsb->vboot & 0xff), VBOOT); > > + svs_writel(svs, (svsb->det_window & 0xffff), DETWINDOW); > > + svs_writel(svs, (svsb->det_max & 0xffff), CONFIG); > > + > > + if (svsb->chkshift != 0) > > + svs_writel(svs, (svsb->chkshift & 0xff), CHKSHIFT); > > + > > + if (svsb->ctl0 != 0) > > + svs_writel(svs, svsb->ctl0, CTL0); > > + > > + svs_writel(svs, 0x00ffffff, INTSTS); > > + > > + switch (target_phase) { > > + case SVS_PHASE_INIT01: > > + svs_writel(svs, 0x00005f01, INTEN); > > + svs_writel(svs, 0x00000001, SVSEN); > > + break; > > + case SVS_PHASE_INIT02: > > + svs_writel(svs, 0x00005f01, INTEN); > > + init2vals = ((svsb->age_voffset_in << 16) & 0xffff0000) | > > + (svsb->dc_voffset_in & 0xffff); > > + svs_writel(svs, init2vals, INIT2VALS); > > + svs_writel(svs, 0x00000005, SVSEN); > > + break; > > + case SVS_PHASE_MON: > > + ts_calcs = ((svsb->bts << 12) & 0xfff000) | (svsb->mts & 0xfff); > > + svs_writel(svs, ts_calcs, TSCALCS); > > + svs_writel(svs, 0x00FF0000, INTEN); > > + svs_writel(svs, 0x00000002, SVSEN); > > + break; > > + default: > > + WARN_ON(1); > > + break; > > + } > > +} > > lots of magic constants for these register writes. #defines w/bit > descriptions would be very helpful for the reader. Sure, I'll add #define w/bit for these magic constants in the next patch. Thanks. > > > +static inline void svs_init01_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_notice("%s: %s: VDN74:0x%08x, VDN30:0x%08x, DCVALUES:0x%08x\n", > > + svsb->name, __func__, svs_readl(svs, VDESIGN74), > > + svs_readl(svs, VDESIGN30), svs_readl(svs, DCVALUES)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_INIT01][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->dc_voffset_in = ~(svs_readl(svs, DCVALUES) & 0xffff) + 1; > > + if (svsb->init01_volt_flag == SVS_INIT01_VOLT_IGNORE) > > + svsb->dc_voffset_in = 0; > > + else if ((svsb->dc_voffset_in & 0x8000) && > > + (svsb->init01_volt_flag == SVS_INIT01_VOLT_INC_ONLY)) > > + svsb->dc_voffset_in = 0; > > + > > + svsb->age_voffset_in = svs_readl(svs, AGEVALUES) & 0xffff; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x1, INTSTS); > > + > > + /* svs init01 clock gating */ > > + svsb->coresel &= ~svsb->systemclk_en; > > + > > + svsb->phase = SVS_PHASE_INIT01; > > + complete(&svsb->init_completion); > > +} > > + > > +static inline void svs_init02_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_notice("%s: %s: VOP74:0x%08x, VOP30:0x%08x, DCVALUES:0x%08x\n", > > + svsb->name, __func__, svs_readl(svs, VOP74), > > + svs_readl(svs, VOP30), svs_readl(svs, DCVALUES)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_INIT02][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->ops->get_vops(svs); > > + memcpy(svsb->init02_volts, svsb->volts, 4 * svsb->opp_count); > > + svsb->phase = SVS_PHASE_INIT02; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x1, INTSTS); > > + > > + complete(&svsb->init_completion); > > +} > > + > > +static inline void svs_mon_mode_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->svs_temp = svs_readl(svs, TEMP) & 0xff; > > + > > + svsb->ops->get_vops(svs); > > + svsb->phase = SVS_PHASE_MON; > > + > > + svs_writel(svs, 0x00ff0000, INTSTS); > > +} > > + > > +static inline void svs_error_isr_handler(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_err("%s(): %s(%s)", __func__, svsp->name, svsb->name); > > + pr_err("CORESEL(0x%x) = 0x%08x\n", > > + svsp->regs[CORESEL], svs_readl(svs, CORESEL)), > > + pr_err("SVSEN(0x%x) = 0x%08x, INTSTS(0x%x) = 0x%08x\n", > > + svsp->regs[SVSEN], svs_readl(svs, SVSEN), > > + svsp->regs[INTSTS], svs_readl(svs, INTSTS)); > > + pr_err("SMSTATE0(0x%x) = 0x%08x, SMSTATE1(0x%x) = 0x%08x\n", > > + svsp->regs[SMSTATE0], svs_readl(svs, SMSTATE0), > > + svsp->regs[SMSTATE1], svs_readl(svs, SMSTATE1)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->init01_support = false; > > + svsb->init02_support = false; > > + svsb->mon_mode_support = false; > > + > > + if (svsb->phase == SVS_PHASE_MON) > > + svsb->phase = SVS_PHASE_INIT02; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x00ffffff, INTSTS); > > +} > > + > > +static inline void svs_isr_handler(struct mtk_svs *svs) > > +{ > > + u32 intsts, svsen; > > + > > + svs_switch_bank(svs); > > + > > + intsts = svs_readl(svs, INTSTS); > > + svsen = svs_readl(svs, SVSEN); > > + > > + if (intsts == 0x1 && ((svsen & 0x7) == 0x1)) > > + svs_init01_isr_handler(svs); > > + else if ((intsts == 0x1) && ((svsen & 0x7) == 0x5)) > > + svs_init02_isr_handler(svs); > > + else if ((intsts & 0x00ff0000) != 0x0) > > + svs_mon_mode_isr_handler(svs); > > + else > > + svs_error_isr_handler(svs); > > +} > > + > > +static irqreturn_t svs_isr(int irq, void *data) > > +{ > > + struct mtk_svs *svs = (struct mtk_svs *)data; > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb = NULL; > > + unsigned long flags; > > + u32 idx; > > + > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (svsb->suspended) > > + continue; > > + else if (svsb->intst & svs_readl(svs, INTST)) > > + continue; > > + > > + svs_isr_handler(svs); > > + break; > > + } > > + release_mtk_svs_lock(flags); > > + > > + if (svsb->phase != SVS_PHASE_INIT01) > > + svs_set_volts(svsb, false); > > + > > + return IRQ_HANDLED; > > +} > > + > > +static void svs_mon_mode(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags; > > + u32 idx; > > + > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->mon_mode_support) > > + continue; > > + > > + svs_set_phase(svs, SVS_PHASE_MON); > > + } > > + release_mtk_svs_lock(flags); > > +} > > + > > +static int svs_init02(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags, time_left; > > + u32 idx; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->init02_support) > > + continue; > > + > > + reinit_completion(&svsb->init_completion); > > + flags = claim_mtk_svs_lock(); > > + svs_set_phase(svs, SVS_PHASE_INIT02); > > + release_mtk_svs_lock(flags); > > + time_left = > > + wait_for_completion_timeout(&svsb->init_completion, > > + msecs_to_jiffies(2000)); > > + if (time_left == 0) { > > + pr_err("%s: init02 completion timeout\n", svsb->name); > > + return -EBUSY; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int svs_init01(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct pm_qos_request qos_request = { {0} }; > > + unsigned long flags, time_left; > > + bool search_done; > > + int ret = -EINVAL; > > + u32 opp_freqs, opp_vboot, buck_volt, idx, i; > > + > > + /* Let CPUs leave idle-off state for initializing svs_init01. */ > > + pm_qos_add_request(&qos_request, PM_QOS_CPU_DMA_LATENCY, 0); > > + > > + /* Sometimes two svs_bank 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]; > > + search_done = false; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST); > > + if (ret) > > + pr_notice("%s: fail to set fast mode: %d\n", > > + svsb->name, ret); > > + > > + if (svsb->mtcmos_request) { > > + ret = regulator_enable(svsb->buck); > > + if (ret) { > > + pr_err("%s: fail to enable %s power: %d\n", > > + svsb->name, svsb->buck_name, ret); > > + goto init01_finish; > > + } > > + > > + ret = dev_pm_domain_attach(svsb->dev, false); > > + if (ret) { > > + pr_err("%s: attach pm domain fail: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + > > + pm_runtime_enable(svsb->dev); > > + ret = pm_runtime_get_sync(svsb->dev); > > + if (ret < 0) { > > + pr_err("%s: turn mtcmos on fail: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + } > > + > > + /* Find the fastest freq that can be run at vboot and > > + * fix to that freq until svs_init01 is done. > > + */ > > + opp_vboot = svs_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->dev, > > + opp_freqs, > > + opp_vboot); > > + if (ret) { > > + pr_err("%s: set voltage failed: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + > > + search_done = true; > > + } else { > > + dev_pm_opp_disable(svsb->dev, > > + svsb->opp_freqs[i]); > > + } > > + } > > + } > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + opp_vboot = svs_volt_to_opp_volt(svsb->vboot, > > + svsb->volt_step, > > + svsb->volt_base); > > + > > + buck_volt = regulator_get_voltage(svsb->buck); > > + if (buck_volt != opp_vboot) { > > + pr_err("%s: buck voltage: %u, expected vboot: %u\n", > > + svsb->name, buck_volt, opp_vboot); > > + ret = -EPERM; > > + goto init01_finish; > > + } > > + > > + init_completion(&svsb->init_completion); > > + flags = claim_mtk_svs_lock(); > > + svs_set_phase(svs, SVS_PHASE_INIT01); > > + release_mtk_svs_lock(flags); > > + time_left = > > + wait_for_completion_timeout(&svsb->init_completion, > > + msecs_to_jiffies(2000)); > > + if (time_left == 0) { > > + pr_err("%s: init01 completion timeout\n", svsb->name); > > + ret = -EBUSY; > > + goto init01_finish; > > + } > > + } > > + > > +init01_finish: > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + for (i = 0; i < svsb->opp_count; i++) > > + dev_pm_opp_enable(svsb->dev, svsb->opp_freqs[i]); > > + > > + if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL)) > > + pr_notice("%s: fail to set normal mode: %d\n", > > + svsb->name, ret); > > + > > + if (svsb->mtcmos_request) { > > + if (pm_runtime_put_sync(svsb->dev)) > > + pr_err("%s: turn mtcmos off fail: %d\n", > > + svsb->name, ret); > > + pm_runtime_disable(svsb->dev); > > + dev_pm_domain_detach(svsb->dev, 0); > > + if (regulator_disable(svsb->buck)) > > + pr_err("%s: fail to disable %s power: %d\n", > > + svsb->name, svsb->buck_name, ret); > > + } > > + } > > + > > + pm_qos_remove_request(&qos_request); > > + > > + return ret; > > +} > > + > > +static int svs_start(struct mtk_svs *svs) > > +{ > > + int ret; > > + > > + ret = svs_init01(svs); > > + if (ret) > > + return ret; > > + > > + ret = svs_init02(svs); > > + if (ret) > > + return ret; > > + > > + svs_mon_mode(svs); > > + > > + return ret; > > +} > > + > > +static int svs_mt8183_efuse_parsing(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct thermal_parameter tp; > > + struct svs_bank *svsb; > > + bool mon_mode_support = true; > > + int format[6], x_roomt[6], tb_roomt; > > + u32 idx, i, ft_pgm, mts, temp0, temp1, temp2; > > + > > + if (svsp->fake_efuse) { > > + pr_notice("fake efuse\n"); > > + svs->efuse[0] = 0x00310080; > > + svs->efuse[1] = 0xabfbf757; > > + svs->efuse[2] = 0x47c747c7; > > + svs->efuse[3] = 0xabfbf757; > > + svs->efuse[4] = 0xe7fca0ec; > > + svs->efuse[5] = 0x47bf4b88; > > + svs->efuse[6] = 0xabfb8fa5; > > + svs->efuse[7] = 0xabfb217b; > > + svs->efuse[8] = 0x4bf34be1; > > + svs->efuse[9] = 0xabfb670d; > > + svs->efuse[16] = 0xabfbc653; > > + svs->efuse[17] = 0x47f347e1; > > + svs->efuse[18] = 0xabfbd848; > > + > > + svs->thermal_efuse[0] = 0x02873f69; > > + svs->thermal_efuse[1] = 0xa11d9142; > > + svs->thermal_efuse[2] = 0xa2526900; > > + } > > + > > + /* svs efuse parsing */ > > + ft_pgm = (svs->efuse[0] >> 4) & 0xf; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + if (ft_pgm <= 1) > > + svsb->init01_volt_flag = SVS_INIT01_VOLT_IGNORE; > > + > > + switch (svsb->sw_id) { > > + case SVS_CPU_LITTLE: > > + svsb->bdes = svs->efuse[16] & 0xff; > > + svsb->mdes = (svs->efuse[16] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[16] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[16] >> 24) & 0xff; > > + svsb->mtdes = (svs->efuse[17] >> 16) & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 10; > > + else > > + svsb->volt_offset += 2; > > + break; > > + case SVS_CPU_BIG: > > + svsb->bdes = svs->efuse[18] & 0xff; > > + svsb->mdes = (svs->efuse[18] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[18] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[18] >> 24) & 0xff; > > + svsb->mtdes = svs->efuse[17] & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 15; > > + else > > + svsb->volt_offset += 12; > > + break; > > + case SVS_CCI: > > + svsb->bdes = svs->efuse[4] & 0xff; > > + svsb->mdes = (svs->efuse[4] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[4] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[4] >> 24) & 0xff; > > + svsb->mtdes = (svs->efuse[5] >> 16) & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 10; > > + else > > + svsb->volt_offset += 2; > > + break; > > + case SVS_GPU: > > + svsb->bdes = svs->efuse[6] & 0xff; > > + svsb->mdes = (svs->efuse[6] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[6] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[6] >> 24) & 0xff; > > + svsb->mtdes = svs->efuse[5] & 0xff; > > + > > + if (ft_pgm >= 2) { > > + svsb->freq_base = 800000000; /* 800MHz */ > > + svsb->dvt_fixed = 2; > > + } > > + break; > > + default: > > + break; > > + } > > + } > > + > > + for (i = 0; i < svsp->efuse_num; i++) { > > + if (svs->efuse[i]) > > + pr_notice("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]); > > + } > > + > > + /* thermal efuse parsing */ > > + if (!svs->thermal_efuse) > > + return 0; > > + > > + tp.adc_ge_t = (svs->thermal_efuse[1] >> 22) & 0x3ff; > > + tp.adc_oe_t = (svs->thermal_efuse[1] >> 12) & 0x3ff; > > + > > + tp.o_vtsmcu1 = (svs->thermal_efuse[0] >> 17) & 0x1ff; > > + tp.o_vtsmcu2 = (svs->thermal_efuse[0] >> 8) & 0x1ff; > > + tp.o_vtsmcu3 = svs->thermal_efuse[1] & 0x1ff; > > + tp.o_vtsmcu4 = (svs->thermal_efuse[2] >> 23) & 0x1ff; > > + tp.o_vtsmcu5 = (svs->thermal_efuse[2] >> 5) & 0x1ff; > > + tp.o_vtsabb = (svs->thermal_efuse[2] >> 14) & 0x1ff; > > + > > + tp.degc_cali = (svs->thermal_efuse[0] >> 1) & 0x3f; > > + tp.adc_cali_en_t = svs->thermal_efuse[0] & BIT(0); > > + tp.o_slope_sign = (svs->thermal_efuse[0] >> 7) & BIT(0); > > + > > + tp.ts_id = (svs->thermal_efuse[1] >> 9) & BIT(0); > > + tp.o_slope = (svs->thermal_efuse[0] >> 26) & 0x3f; > > + > > + if (tp.adc_cali_en_t == 1) { > > + if (tp.ts_id == 0) > > + 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)) { > > + pr_err("bad thermal efuse data. disable mon mode\n"); > > + mon_mode_support = false; > > + } > > + } else { > > + pr_err("no thermal efuse data. disable mon mode\n"); > > + mon_mode_support = false; > > + } > > + > > + if (!mon_mode_support) { > > + for (i = 0; i < svsp->thermal_efuse_num; i++) > > + pr_err("thermal_efuse[%u] = 0x%08x\n", > > + i, svs->thermal_efuse[i]); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->mon_mode_support = false; > > + } > > + > > + return 0; > > + } > > + > > + 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 == 0) > > + 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 SVS_CPU_LITTLE: > > + tb_roomt = x_roomt[3]; > > + break; > > + case SVS_CPU_BIG: > > + tb_roomt = x_roomt[4]; > > + break; > > + case SVS_CCI: > > + tb_roomt = x_roomt[3]; > > + break; > > + case SVS_GPU: > > + tb_roomt = x_roomt[1]; > > + break; > > + default: > > + pr_err("unknown svsb_id = %u? disable svs\n", > > + svsb->sw_id); > > + return -EINVAL; > > + } > > + > > + temp0 = (tp.degc_cali * 10 / 2); > > + temp1 = ((10000 * 100000 / 4096 / tp.gain) * > > + tp.oe + tb_roomt * 10) * 15 / 18; > > + > > + if (tp.o_slope_sign == 0) > > + 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 0; > > +} > > + > > +static int svs_is_support(struct mtk_svs *svs) > > nit: this appears to be a check if the platform supports SVS. If so, > then it should probably be 'bool' and be called svs_is_supported(). bool/svs_is_supported are good ideas. I'll apply it in the next patch. Thanks. > > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct nvmem_cell *cell; > > + size_t len; > > + int ret; > > + u32 idx, i; > > + > > + if (svsp->fake_efuse) { > > + len = svsp->efuse_num * 4; > > + svs->efuse = kzalloc(len, GFP_KERNEL); > > + if (!svs->efuse) > > + return -ENOMEM; > > + > > + len = svsp->thermal_efuse_num * 4; > > + svs->thermal_efuse = kzalloc(len, GFP_KERNEL); > > + if (!svs->thermal_efuse) > > + return -ENOMEM; > > + > > + goto svsp_efuse_parsing; > > + } > > + > > + /* get svs efuse by nvmem */ > > + cell = nvmem_cell_get(svs->dev, "svs-calibration-data"); > > + if (IS_ERR(cell)) { > > + pr_err("no \"svs-calibration-data\" from dts? disable svs\n"); > > + return PTR_ERR(cell); > > + } > > + > > + svs->efuse = (u32 *)nvmem_cell_read(cell, &len); > > + nvmem_cell_put(cell); > > + > > + ret = (svs->efuse[svsp->efuse_check] == 0) ? -EPERM : 0; > > + if (ret) { > > + pr_err("no svs efuse. disable svs.\n"); > > + for (i = 0; i < svsp->efuse_num; i++) > > + pr_err("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]); > > + return ret; > > + } > > + > > + /* get thermal efuse by nvmem */ > > + cell = nvmem_cell_get(svs->dev, "calibration-data"); > > + if (IS_ERR(cell)) { > > + pr_err("no \"calibration-data\" from dts? disable mon mode\n"); > > + svs->thermal_efuse = NULL; > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->mon_mode_support = false; > > + } > > + goto svsp_efuse_parsing; > > + } > > + > > + svs->thermal_efuse = (u32 *)nvmem_cell_read(cell, &len); > > + nvmem_cell_put(cell); > > + > > +svsp_efuse_parsing: > > + ret = svsp->efuse_parsing(svs); > > + > > + return ret; > > +} > > + > > +static int svs_resource_setup(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct platform_device *pdev; > > + struct device_node *np = NULL; > > + struct dev_pm_opp *opp; > > + unsigned long freq; > > + size_t opp_size; > > + int count, ret; > > + u32 idx, i; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + switch (svsb->sw_id) { > > + case SVS_CPU_LITTLE: > > + svsb->name = "SVS_CPU_LITTLE"; > > + break; > > + case SVS_CPU_BIG: > > + svsb->name = "SVS_CPU_BIG"; > > + break; > > + case SVS_CCI: > > + svsb->name = "SVS_CCI"; > > + break; > > + case SVS_GPU: > > + svsb->name = "SVS_GPU"; > > + break; > > + default: > > + WARN_ON(1); > > + return -EINVAL; > > + } > > + > > + /* Add svs_bank device for opp-table/mtcmos/buck control */ > > + pdev = platform_device_alloc(svsb->name, 0); > > + if (!pdev) { > > + pr_err("%s: fail to alloc pdev for svs_bank\n", > > + svsb->name); > > + return -ENOMEM; > > + } > > + > > + for_each_child_of_node(svs->dev->of_node, np) { > > + if (of_device_is_compatible(np, svsb->of_compatible)) { > > + pdev->dev.of_node = np; > > + break; > > + } > > + } > > + > > + ret = platform_device_add(pdev); > > + if (ret) { > > + pr_err("%s: fail to add svs_bank device: %d\n", > > + svsb->name, ret); > > + return ret; > > + } > > + > > + svsb->dev = &pdev->dev; > > + dev_set_drvdata(svsb->dev, svs); > > + ret = dev_pm_opp_of_add_table(svsb->dev); > > + if (ret) { > > + pr_err("%s: fail to add opp table: %d\n", > > + svsb->name, ret); > > + return ret; > > + } > > + > > + mutex_init(&svsb->lock); > > + > > + svsb->buck = devm_regulator_get_optional(svsb->dev, > > + svsb->buck_name); > > + if (IS_ERR(svsb->buck)) { > > + pr_err("%s: cannot get regulator \"%s-supply\"\n", > > + svsb->name, svsb->buck_name); > > + return PTR_ERR(svsb->buck); > > + } > > + > > + count = dev_pm_opp_get_opp_count(svsb->dev); > > + if (svsb->opp_count != count) { > > + pr_err("%s: opp_count not \"%u\" but get \"%d\"?\n", > > + svsb->name, svsb->opp_count, count); > > + return count; > > + } > > + > > + opp_size = 4 * svsb->opp_count; > > + svsb->opp_volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->opp_volts) > > + return -ENOMEM; > > + > > + svsb->init02_volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->init02_volts) > > + return -ENOMEM; > > + > > + svsb->volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->volts) > > + return -ENOMEM; > > + > > + svsb->opp_freqs = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->opp_freqs) > > + return -ENOMEM; > > + > > + svsb->freqs_pct = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->freqs_pct) > > + return -ENOMEM; > > + > > + for (i = 0, freq = (u32)-1; i < svsb->opp_count; i++, freq--) { > > + opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq); > > + if (IS_ERR(opp)) { > > + pr_err("%s: error opp entry!!, err = %ld\n", > > + svsb->name, 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) & 0xff; > > + } > > + } > > + > > + return 0; > > +} > > There are lots of resources (platform_device, all the kmalloc regions) > that are never free'd here. You might consider using devm for this. > > Related, all the small malloc's are calculated based on the opp_count > for each bank, but they are all hard-coded to 16. Seems it would be > better to have a default/max size for this in the bank structure itself > instead of making these small allocations. Thanks for the advices. The default/max size are good ideas. I'll apply it in the next patch. > > > +static int svs_suspend(struct device *dev) > > +{ > > + struct mtk_svs *svs = dev_get_drvdata(dev); > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags; > > + u32 idx; > > + > > + /* Wait if there is processing svs_isr(). Suspend all banks. */ > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + svs_switch_bank(svs); > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x00ffffff, INTSTS); > > I'm assuming this part will disable future interrupts? Yes, this for-loop will disable all the SVS banks' interrupts. > I'm not seeing where they get re-enabled on the resume path. In the svs_resume(), we re-run svs_init02() to enable each SVS bank. > > > > + svsb->suspended = true; > > + } > > + release_mtk_svs_lock(flags); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + if (svsb->phase == SVS_PHASE_MON) { > > + svsb->phase = SVS_PHASE_INIT02; > > + svs_set_volts(svsb, true); > > + } > > + } > > + > > + clk_disable_unprepare(svs->main_clk); > > + > > + return 0; > > +} > > + > > +static int svs_resume(struct device *dev) > > +{ > > + struct mtk_svs *svs = dev_get_drvdata(dev); > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + int ret; > > + u32 idx; > > + > > + ret = clk_prepare_enable(svs->main_clk); > > + if (ret) > > + pr_err("%s(): cannot enable main_clk\n", __func__); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->suspended = false; > > + } > > + > > + ret = svs_init02(svs); > > + if (ret) > > + return ret; > > + > > + svs_mon_mode(svs); > > + > > + return 0; > > +} > > Kevin _______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.3 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9DED2C3F68F for ; Fri, 3 Jan 2020 05:45:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6B5F424649 for ; Fri, 3 Jan 2020 05:45:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="L8xYRhmV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726478AbgACFpM (ORCPT ); Fri, 3 Jan 2020 00:45:12 -0500 Received: from mailgw01.mediatek.com ([210.61.82.183]:9338 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1725916AbgACFpL (ORCPT ); Fri, 3 Jan 2020 00:45:11 -0500 X-UUID: cc46d179b2924e28aa00642452e57d09-20200103 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=JNRfAfDLAyXxpHtn3SvuzDUGpMWxlxKC54Aay/GuRbs=; b=L8xYRhmVmjczS7o647tyFG651d9sTN8P/sV8/T/YSj0v2qT7yoZJPAGpw1Pu94M9qKLLXLZpaYBIkNlgPiXNi/kLVZkV1+v9/WFnj2qwt06FaRB+VWRox8NcFsuVcXrclSKVvpxP+hDQX8JHW8vIKhjGPLl9SftLG9Hsfw3icQk=; X-UUID: cc46d179b2924e28aa00642452e57d09-20200103 Received: from mtkmrs01.mediatek.inc [(172.21.131.159)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.10 Build 0809 with TLS) with ESMTP id 1744575999; Fri, 03 Jan 2020 13:44:52 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs01n2.mediatek.inc (172.21.101.79) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 3 Jan 2020 13:42:56 +0800 Received: from [172.21.77.4] (172.21.77.4) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Fri, 3 Jan 2020 13:44:49 +0800 Message-ID: <1578030290.10850.45.camel@mtksdaap41> Subject: Re: [PATCH v5 3/3] PM / AVS: SVS: Introduce SVS engine From: Roger Lu To: Kevin Hilman CC: Kevin Hilman , Rob Herring , Nicolas Boichat , Stephen Boyd , "Fan Chen" , HenryC Chen , , Angus Lin , Mark Rutland , Matthias Brugger , "Nishanth Menon" , , , , , Date: Fri, 3 Jan 2020 13:44:50 +0800 In-Reply-To: <7hpnjmiswn.fsf@baylibre.com> References: <20190906100514.30803-1-roger.lu@mediatek.com> <20190906100514.30803-4-roger.lu@mediatek.com> <7hpnjmiswn.fsf@baylibre.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: D7704B8214DDB3A76E72843BDF025556B78AC5F37EAEF28A2E40DE73002FBEE72000:8 X-MTK: N Content-Transfer-Encoding: base64 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org RGVhciBLZXZpbiBTaXIsDQoNClNvcnJ5IGZvciB0aGUgbGF0ZSByZXBseSBhbmQgdGhhbmtzIGZv ciB0aGUgYWR2aWNlIHRvIHRoaXMgcGF0Y2guDQoNCk9uIFRodSwgMjAxOS0wOS0yNiBhdCAxNToz OSAtMDcwMCwgS2V2aW4gSGlsbWFuIHdyb3RlOg0KPiBIaSBSb2dlciwNCj4gDQo+IFJvZ2VyIEx1 IDxyb2dlci5sdUBtZWRpYXRlay5jb20+IHdyaXRlczoNCj4gDQo+ID4gVGhlIFNWUyAoU21hcnQg Vm9sdGFnZSBTY2FsaW5nKSBlbmdpbmUgaXMgYSBwaWVjZSBvZiBoYXJkd2FyZSB3aGljaCBpcw0K PiA+IHVzZWQgdG8gY2FsY3VsYXRlIG9wdGltaXplZCB2b2x0YWdlIHZhbHVlcyBvZiBzZXZlcmFs IHBvd2VyIGRvbWFpbnMsIGUuZy4NCj4gPiBDUFUvR1BVL0NDSSwgYWNjb3JkaW5nIHRvIGNoaXAg cHJvY2VzcyBjb3JuZXIsIHRlbXBlcmF0dXJlcywgYW5kIG90aGVyDQo+ID4gZmFjdG9ycy4gVGhl biBEVkZTIGRyaXZlciBjb3VsZCBhcHBseSB0aG9zZSBvcHRpbWl6ZWQgdm9sdGFnZSB2YWx1ZXMg dG8NCj4gPiByZWR1Y2UgcG93ZXIgY29uc3VtcHRpb24uDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5 OiBSb2dlciBMdSA8cm9nZXIubHVAbWVkaWF0ZWsuY29tPg0KPiANCj4gSSBkb24ndCBoYXZlIGFu eSBkb2N1bWVudGF0aW9uIG9uIHRoaXMgU1ZTIGhhcmR3YXJlLCBzbyBJIHdvbid0IGJlIGFibGUN Cj4gdG8gY29tbWVudCBvbiB0aGUgc3BlY2lmaWMgZnVuY3Rpb25hbGl0eSwgc28gSSBhdHRlbXB0 ZWQgYSBmaXJzdC1wYXNzDQo+IGhpZ2gtbGV2ZWwgcmV2aWV3Li4uDQoNCkV4Y3VzZSBtZSwgd2Ug ZG9uJ3QgaGF2ZSB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgU1ZTIGhhcmR3YXJlLiBJJ2xsIHRyeSBt eQ0KYmVzdCB0byBpbnRyb2R1Y2UgU1ZTIG9ubGluZS4NCg0KPiANCj4gSW4gdGhlIGFic2VuY2Ug b2YgZG9jdW1lbnRhdGlvbiwgaXQgd291bGQgYmUgaGVscGZ1bCB0byBnaXZlIGEgaGlnaA0KPiBs ZXZlbCBkZXNjcmlwdGlvbiBvZiBob3cgdGhpcyBoYXJkd2FyZSB3b3Jrcy4gIEluIHBhcnRpY3Vs YXIsIGENCj4gaGlnaC1sZXZlbCBvdmVydmlldyBvZiB0aGUgY29udHJvbCBsb29wLCB3aGljaCBh cHBlYXJzIHRvIGJlIHByaW1hcmlseQ0KPiBpbnRlcnJ1cHQgZHJpdmVuLCB3b3VsZCBiZSBoZWxw ZnVsLiAgZS5nLiBob3cgb2Z0ZW4gYXJlIHRoZSBpbnRlcnJ1cHRzDQo+IGZpcmluZywgYW5kIHdo eS4NCg0KMS4gTVQ4MTgzIFNWUyBoYXMgNCBjb250cm9sbGVycyAoYmFua3MpLiBPbmUgYmFuayBm b3Igb3B0aW1pemluZyBvbmUNCnBvd2VyLWRvbWFpbiBPUFAgdm9sdGFnZXMuDQotIDQgcG93ZXIt ZG9tYWluIChDUFUtbGl0dGxlIC8gQ1BVLUJJRyAvIENDSSAvIEdQVSkgT1BQIHZvbHRhZ2VzIHdp bGwgYmUNCm9wdGltaXplZCBieSBTVlMgYmFua3MuLg0KMi4gRWFjaCBTVlMgYmFuayBuZWVkcyB0 byBydW4gaXRzIGluaXQwMS9pbml0MDIgc2VwYXJhdGVseSBzbyB0aGF0IFNWUw0KYmFuaydzIG9w dGltaXplZCBPUFAgdm9sdGFnZXMgY2FuIGJlIGNhbGN1bGF0ZWQgdG8gc3lzdGVtLg0KLSBpbml0 MDE6IFNWUyBiYW5rIGJhc2ljIGluaXQgKG11c3QpDQotIGluaXQwMjogU1ZTIGJhbmsgcHJvdmlk ZSBoaWdoIHRlbXBlcmF0dXJlIE9QUCB2b2x0YWdlcyAobXVzdCkNCi0gbW9uIG1vZGU6IFNWUyBi YW5rIGR5bmFtaWNhbGx5IG9wdGltaXplcyBPUFAgdm9sdGFnZXMgYmFzaW5nIG9uDQp0ZW1wZXJh dHVyZSBjaGFuZ2UuIChvcHRpb25hbCkNCjMuIFNWUyBpbnRlcnJ1cHQgYmVoYXZpb3INCi0gSW4g aW5pdDAxL2luaXQwMiwgU1ZTIG9ubHkgZmlyZSBvbmUgaW50ZXJydXB0IHRvIGluZm9ybSBTVyB0 aGF0IGluaXQNCmlzIGZpbmlzaGVkIGFuZCBvcHRpbWl6ZWQgT1BQIHZvbHRhZ2VzIGFyZSByZWFk eS4NCi0gSW4gbW9uIG1vZGUsIFNWUyBmaXJlIGludGVycnVwdCB3aGVuIHRlbXBlcmF0dXJlIGNo YW5nZXMuIE1vbiBtb2RlDQppbnRlcnJ1cHQgaXMgYWxzbyBmb3IgaW5mb3JtaW5nIG5ldyBvcHRp bWl6ZWQgT1BQIHZvbHRhZ2VzIGFyZSByZWFkeS4NCg0KPiANCj4gSXQncyBoYXJkIHRvIHVuZGVy c3RhbmQgdGhlICJpbml0MDEiIHZzIHRoZSAiaW5pdDAyIiBwYXRjaCBzaW5jZQ0KPiB0aG9zZSBu YW1lcyBhcmVuJ3QgdmVyeSBkZXNjcmlwdGl2ZS4gOikNCj4gDQo+IEFsc28sIHRoZXJlIGFyZSBs b3RzIG9mIGhhcmQtY29kZWQgY29uc3RhbnRzIChtYXNrcywgc2hpZnRzLCBldGMuKSB1c2VkDQo+ IHRocm91Z2hvdXQgdGhlIGNhbGN1bGF0aW9ucy4gICNkZWZpbmVzIGNvdWxkIGhlbHAgcmVhZGFi aWxpdHkgZm9yIG1hbnkNCj4gb2YgdGhlc2UsIGVzcGVjaWFsbHkgdGhlIG1hc2tzLg0KPiANCj4g PiAtLS0NCj4gPiAgZHJpdmVycy9wb3dlci9hdnMvS2NvbmZpZyAgICAgfCAgIDEwICsNCj4gPiAg ZHJpdmVycy9wb3dlci9hdnMvTWFrZWZpbGUgICAgfCAgICAxICsNCj4gPiAgZHJpdmVycy9wb3dl ci9hdnMvbXRrX3N2cy5jICAgfCAyMDc1ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr Kw0KPiA+ICBpbmNsdWRlL2xpbnV4L3Bvd2VyL210a19zdnMuaCB8ICAgMjMgKw0KPiA+ICA0IGZp bGVzIGNoYW5nZWQsIDIxMDkgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQg ZHJpdmVycy9wb3dlci9hdnMvbXRrX3N2cy5jDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNs dWRlL2xpbnV4L3Bvd2VyL210a19zdnMuaA0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv cG93ZXIvYXZzL0tjb25maWcgYi9kcml2ZXJzL3Bvd2VyL2F2cy9LY29uZmlnDQo+ID4gaW5kZXgg YjVhMjE3YjgyOGRjLi43YzcyNTA0ZDU1OTMgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9wb3dl ci9hdnMvS2NvbmZpZw0KPiA+ICsrKyBiL2RyaXZlcnMvcG93ZXIvYXZzL0tjb25maWcNCj4gPiBA QCAtMTksMyArMTksMTMgQEAgY29uZmlnIFJPQ0tDSElQX0lPRE9NQUlODQo+ID4gICAgICAgICAg ICBTYXkgeSBoZXJlIHRvIGVuYWJsZSBzdXBwb3J0IGlvIGRvbWFpbnMgb24gUm9ja2NoaXAgU29D cy4gSXQgaXMNCj4gPiAgICAgICAgICAgIG5lY2Vzc2FyeSBmb3IgdGhlIGlvIGRvbWFpbiBzZXR0 aW5nIG9mIHRoZSBTb0MgdG8gbWF0Y2ggdGhlDQo+ID4gICAgICAgICAgICB2b2x0YWdlIHN1cHBs aWVkIGJ5IHRoZSByZWd1bGF0b3JzLg0KPiA+ICsNCj4gPiArY29uZmlnIE1US19TVlMNCj4gPiAr CWJvb2wgIk1lZGlhVGVrIFNtYXJ0IFZvbHRhZ2UgU2NhbGluZyhTVlMpIg0KPiA+ICsJZGVwZW5k cyBvbiBQT1dFUl9BVlMgJiYgTVRLX0VGVVNFDQo+ID4gKwloZWxwDQo+ID4gKwkgIFRoZSBTVlMg ZW5naW5lIGlzIGEgcGllY2Ugb2YgaGFyZHdhcmUgd2hpY2ggaXMgdXNlZCB0byBjYWxjdWxhdGUN Cj4gPiArCSAgb3B0aW1pemVkIHZvbHRhZ2UgdmFsdWVzIG9mIHNldmVyYWwgcG93ZXIgZG9tYWlu cywgZS5nLg0KPiA+ICsJICBDUFUgY2x1c3RlcnMvR1BVL0NDSSwgYWNjb3JkaW5nIHRvIGNoaXAg cHJvY2VzcyBjb3JuZXIsIHRlbXBlcmF0dXJlcywNCj4gPiArCSAgYW5kIG90aGVyIGZhY3RvcnMu IFRoZW4gRFZGUyBkcml2ZXIgY291bGQgYXBwbHkgdGhvc2Ugb3B0aW1pemVkIHZvbHRhZ2UNCj4g PiArCSAgdmFsdWVzIHRvIHJlZHVjZSBwb3dlciBjb25zdW1wdGlvbi4NCj4gPiBkaWZmIC0tZ2l0 IGEvZHJpdmVycy9wb3dlci9hdnMvTWFrZWZpbGUgYi9kcml2ZXJzL3Bvd2VyL2F2cy9NYWtlZmls ZQ0KPiA+IGluZGV4IGExYjhjZDQ1M2YxOS4uNTcyNDZiOTc3YTkzIDEwMDY0NA0KPiA+IC0tLSBh L2RyaXZlcnMvcG93ZXIvYXZzL01ha2VmaWxlDQo+ID4gKysrIGIvZHJpdmVycy9wb3dlci9hdnMv TWFrZWZpbGUNCj4gPiBAQCAtMSwzICsxLDQgQEANCj4gPiAgIyBTUERYLUxpY2Vuc2UtSWRlbnRp ZmllcjogR1BMLTIuMC1vbmx5DQo+ID4gIG9iai0kKENPTkZJR19QT1dFUl9BVlNfT01BUCkJCSs9 IHNtYXJ0cmVmbGV4Lm8NCj4gPiAgb2JqLSQoQ09ORklHX1JPQ0tDSElQX0lPRE9NQUlOKQkJKz0g cm9ja2NoaXAtaW8tZG9tYWluLm8NCj4gPiArb2JqLSQoQ09ORklHX01US19TVlMpCQkJKz0gbXRr X3N2cy5vDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvcG93ZXIvYXZzL210a19zdnMuYyBiL2Ry aXZlcnMvcG93ZXIvYXZzL210a19zdnMuYw0KPiA+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+ID4g aW5kZXggMDAwMDAwMDAwMDAwLi43OGVjOTNjM2E0YTUNCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4g KysrIGIvZHJpdmVycy9wb3dlci9hdnMvbXRrX3N2cy5jDQo+ID4gQEAgLTAsMCArMSwyMDc1IEBA DQo+ID4gKy8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wDQo+ID4gKy8qDQo+ID4g KyAqIENvcHlyaWdodCAoQykgMjAxOCBNZWRpYVRlayBJbmMuDQo+ID4gKyAqLw0KPiA+ICsNCj4g PiArI2RlZmluZSBwcl9mbXQoZm10KQkiW210a19zdnNdICIgZm10DQo+ID4gKw0KPiA+ICsjaW5j bHVkZSA8bGludXgvY2xrLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9jb21wbGV0aW9uLmg+DQo+ ID4gKyNpbmNsdWRlIDxsaW51eC9pbml0Lmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1 cHQuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2t0aHJlYWQuaD4NCj4gPiArI2luY2x1ZGUgPGxp bnV4L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvbXV0ZXguaD4NCj4gPiArI2luY2x1 ZGUgPGxpbnV4L252bWVtLWNvbnN1bWVyLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9vZl9hZGRy ZXNzLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9vZl9pcnEuaD4NCj4gPiArI2luY2x1ZGUgPGxp bnV4L3BsYXRmb3JtX2RldmljZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcG1fZG9tYWluLmg+ DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9wbV9vcHAuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3Bt X3Fvcy5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcG1fcnVudGltZS5oPg0KPiA+ICsjaW5jbHVk ZSA8bGludXgvcG93ZXIvbXRrX3N2cy5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcHJvY19mcy5o Pg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcmVndWxhdG9yL2NvbnN1bWVyLmg+DQo+ID4gKyNpbmNs dWRlIDxsaW51eC9zZXFfZmlsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvc3BpbmxvY2suaD4N Cj4gPiArI2luY2x1ZGUgPGxpbnV4L3RoZXJtYWwuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3Vh Y2Nlc3MuaD4NCj4gPiArDQo+ID4gKyNkZWZpbmUgU1ZTX0lOSVQwMV9WT0xUX0lHTk9SRQkJMQ0K PiA+ICsjZGVmaW5lIFNWU19JTklUMDFfVk9MVF9JTkNfT05MWQkyDQo+ID4gKw0KPiA+ICsjZGVm aW5lIFNWU19QSEFTRV9JTklUMDEJCTANCj4gPiArI2RlZmluZSBTVlNfUEhBU0VfSU5JVDAyCQkx DQo+ID4gKyNkZWZpbmUgU1ZTX1BIQVNFX01PTgkJCTINCj4gPiArI2RlZmluZSBTVlNfUEhBU0Vf RVJST1IJCQkzDQo+ID4gKw0KPiA+ICsjZGVmaW5lIFNWU19DUFVfTElUVExFCQkJMQ0KPiA+ICsj ZGVmaW5lIFNWU19DUFVfQklHCQkJMg0KPiA+ICsjZGVmaW5lIFNWU19DQ0kJCQkJMw0KPiA+ICsj ZGVmaW5lIFNWU19HUFUJCQkJNA0KPiA+ICsNCj4gPiArI2RlZmluZSBwcm9jX2ZvcHNfcncobmFt ZSkgXA0KPiA+ICsJc3RhdGljIGludCBuYW1lICMjIF9wcm9jX29wZW4oc3RydWN0IGlub2RlICpp bm9kZSwJXA0KPiA+ICsJCXN0cnVjdCBmaWxlICpmaWxlKQkJCQlcDQo+ID4gKwl7CQkJCQkJCVwN Cj4gPiArCQlyZXR1cm4gc2luZ2xlX29wZW4oZmlsZSwgbmFtZSAjIyBfcHJvY19zaG93LAlcDQo+ ID4gKwkJCVBERV9EQVRBKGlub2RlKSk7CQkJXA0KPiA+ICsJfQkJCQkJCQlcDQo+ID4gKwlzdGF0 aWMgY29uc3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9ucyBuYW1lICMjIF9wcm9jX2ZvcHMgPSB7CVwN Cj4gPiArCQkub3duZXIgICAgICAgICAgPSBUSElTX01PRFVMRSwJCQkJXA0KPiA+ICsJCS5vcGVu ICAgICAgICAgICA9IG5hbWUgIyMgX3Byb2Nfb3BlbiwJCQlcDQo+ID4gKwkJLnJlYWQgICAgICAg ICAgID0gc2VxX3JlYWQsCQkJCVwNCj4gPiArCQkubGxzZWVrICAgICAgICAgPSBzZXFfbHNlZWss CQkJCVwNCj4gPiArCQkucmVsZWFzZSAgICAgICAgPSBzaW5nbGVfcmVsZWFzZSwJCQlcDQo+ID4g KwkJLndyaXRlICAgICAgICAgID0gbmFtZSAjIyBfcHJvY193cml0ZSwJCQlcDQo+ID4gKwl9DQo+ ID4gKw0KPiA+ICsjZGVmaW5lIHByb2NfZm9wc19ybyhuYW1lKSBcDQo+ID4gKwlzdGF0aWMgaW50 IG5hbWUgIyMgX3Byb2Nfb3BlbihzdHJ1Y3QgaW5vZGUgKmlub2RlLAlcDQo+ID4gKwkJc3RydWN0 IGZpbGUgKmZpbGUpCQkJCVwNCj4gPiArCXsJCQkJCQkJXA0KPiA+ICsJCXJldHVybiBzaW5nbGVf b3BlbihmaWxlLCBuYW1lICMjIF9wcm9jX3Nob3csCVwNCj4gPiArCQkJUERFX0RBVEEoaW5vZGUp KTsJCQlcDQo+ID4gKwl9CQkJCQkJCVwNCj4gPiArCXN0YXRpYyBjb25zdCBzdHJ1Y3QgZmlsZV9v cGVyYXRpb25zIG5hbWUgIyMgX3Byb2NfZm9wcyA9IHsJXA0KPiA+ICsJCS5vd25lciAgICAgICAg ICA9IFRISVNfTU9EVUxFLAkJCQlcDQo+ID4gKwkJLm9wZW4gICAgICAgICAgID0gbmFtZSAjIyBf cHJvY19vcGVuLAkJCVwNCj4gPiArCQkucmVhZCAgICAgICAgICAgPSBzZXFfcmVhZCwJCQkJXA0K PiA+ICsJCS5sbHNlZWsgICAgICAgICA9IHNlcV9sc2VlaywJCQkJXA0KPiA+ICsJCS5yZWxlYXNl ICAgICAgICA9IHNpbmdsZV9yZWxlYXNlLAkJCVwNCj4gPiArCX0NCj4gPiArDQo+ID4gKyNkZWZp bmUgcHJvY19lbnRyeShuYW1lKQl7X19zdHJpbmdpZnkobmFtZSksICZuYW1lICMjIF9wcm9jX2Zv cHN9DQo+ID4gKw0KPiA+ICtzdGF0aWMgREVGSU5FX1NQSU5MT0NLKG10a19zdnNfbG9jayk7DQo+ ID4gK3N0cnVjdCBtdGtfc3ZzOw0KPiA+ICsNCj4gPiArZW51bSByZWdfaW5kZXggew0KPiA+ICsJ VEVNUE1PTkNUTDAgPSAwLA0KPiA+ICsJVEVNUE1PTkNUTDEsDQo+ID4gKwlURU1QTU9OQ1RMMiwN Cj4gPiArCVRFTVBNT05JTlQsDQo+ID4gKwlURU1QTU9OSU5UU1RTLA0KPiA+ICsJVEVNUE1PTklE RVQwLA0KPiA+ICsJVEVNUE1PTklERVQxLA0KPiA+ICsJVEVNUE1PTklERVQyLA0KPiA+ICsJVEVN UEgyTlRIUkUsDQo+ID4gKwlURU1QSFRIUkUsDQo+ID4gKwlURU1QQ1RIUkUsDQo+ID4gKwlURU1Q T0ZGU0VUSCwNCj4gPiArCVRFTVBPRkZTRVRMLA0KPiA+ICsJVEVNUE1TUkNUTDAsDQo+ID4gKwlU RU1QTVNSQ1RMMSwNCj4gPiArCVRFTVBBSEJQT0xMLA0KPiA+ICsJVEVNUEFIQlRPLA0KPiA+ICsJ VEVNUEFEQ1BOUDAsDQo+ID4gKwlURU1QQURDUE5QMSwNCj4gPiArCVRFTVBBRENQTlAyLA0KPiA+ ICsJVEVNUEFEQ01VWCwNCj4gPiArCVRFTVBBRENFWFQsDQo+ID4gKwlURU1QQURDRVhUMSwNCj4g PiArCVRFTVBBRENFTiwNCj4gPiArCVRFTVBQTlBNVVhBRERSLA0KPiA+ICsJVEVNUEFEQ01VWEFE RFIsDQo+ID4gKwlURU1QQURDRVhUQUREUiwNCj4gPiArCVRFTVBBRENFWFQxQUREUiwNCj4gPiAr CVRFTVBBRENFTkFERFIsDQo+ID4gKwlURU1QQURDVkFMSURBRERSLA0KPiA+ICsJVEVNUEFEQ1ZP TFRBRERSLA0KPiA+ICsJVEVNUFJEQ1RSTCwNCj4gPiArCVRFTVBBRENWQUxJRE1BU0ssDQo+ID4g KwlURU1QQURDVk9MVEFHRVNISUZULA0KPiA+ICsJVEVNUEFEQ1dSSVRFQ1RSTCwNCj4gPiArCVRF TVBNU1IwLA0KPiA+ICsJVEVNUE1TUjEsDQo+ID4gKwlURU1QTVNSMiwNCj4gPiArCVRFTVBBRENI QUREUiwNCj4gPiArCVRFTVBJTU1EMCwNCj4gPiArCVRFTVBJTU1EMSwNCj4gPiArCVRFTVBJTU1E MiwNCj4gPiArCVRFTVBNT05JREVUMywNCj4gPiArCVRFTVBBRENQTlAzLA0KPiA+ICsJVEVNUE1T UjMsDQo+ID4gKwlURU1QSU1NRDMsDQo+ID4gKwlURU1QUFJPVENUTCwNCj4gPiArCVRFTVBQUk9U VEEsDQo+ID4gKwlURU1QUFJPVFRCLA0KPiA+ICsJVEVNUFBST1RUQywNCj4gPiArCVRFTVBTUEFS RTAsDQo+ID4gKwlURU1QU1BBUkUxLA0KPiA+ICsJVEVNUFNQQVJFMiwNCj4gPiArCVRFTVBTUEFS RTMsDQo+ID4gKwlURU1QTVNSMF8xLA0KPiA+ICsJVEVNUE1TUjFfMSwNCj4gPiArCVRFTVBNU1Iy XzEsDQo+ID4gKwlURU1QTVNSM18xLA0KPiA+ICsJREVTQ0hBUiwNCj4gPiArCVRFTVBDSEFSLA0K PiA+ICsJREVUQ0hBUiwNCj4gPiArCUFHRUNIQVIsDQo+ID4gKwlEQ0NPTkZJRywNCj4gPiArCUFH RUNPTkZJRywNCj4gPiArCUZSRVFQQ1QzMCwNCj4gPiArCUZSRVFQQ1Q3NCwNCj4gPiArCUxJTUlU VkFMUywNCj4gPiArCVZCT09ULA0KPiA+ICsJREVUV0lORE9XLA0KPiA+ICsJQ09ORklHLA0KPiA+ ICsJVFNDQUxDUywNCj4gPiArCVJVTkNPTkZJRywNCj4gPiArCVNWU0VOLA0KPiA+ICsJSU5JVDJW QUxTLA0KPiA+ICsJRENWQUxVRVMsDQo+ID4gKwlBR0VWQUxVRVMsDQo+ID4gKwlWT1AzMCwNCj4g PiArCVZPUDc0LA0KPiA+ICsJVEVNUCwNCj4gPiArCUlOVFNUUywNCj4gPiArCUlOVFNUU1JBVywN Cj4gPiArCUlOVEVOLA0KPiA+ICsJQ0hLSU5ULA0KPiA+ICsJQ0hLU0hJRlQsDQo+ID4gKwlTVEFU VVMsDQo+ID4gKwlWREVTSUdOMzAsDQo+ID4gKwlWREVTSUdONzQsDQo+ID4gKwlEVlQzMCwNCj4g PiArCURWVDc0LA0KPiA+ICsJQUdFQ09VTlQsDQo+ID4gKwlTTVNUQVRFMCwNCj4gPiArCVNNU1RB VEUxLA0KPiA+ICsJQ1RMMCwNCj4gPiArCURFU0RFVFNFQywNCj4gPiArCVRFTVBBR0VTRUMsDQo+ ID4gKwlDVFJMU1BBUkUwLA0KPiA+ICsJQ1RSTFNQQVJFMSwNCj4gPiArCUNUUkxTUEFSRTIsDQo+ ID4gKwlDVFJMU1BBUkUzLA0KPiA+ICsJQ09SRVNFTCwNCj4gPiArCVRIRVJNSU5UU1QsDQo+ID4g KwlJTlRTVCwNCj4gPiArCVRIU1RBR0UwU1QsDQo+ID4gKwlUSFNUQUdFMVNULA0KPiA+ICsJVEhT VEFHRTJTVCwNCj4gPiArCVRIQUhCU1QwLA0KPiA+ICsJVEhBSEJTVDEsDQo+ID4gKwlTUEFSRTAs DQo+ID4gKwlTUEFSRTEsDQo+ID4gKwlTUEFSRTIsDQo+ID4gKwlTUEFSRTMsDQo+ID4gKwlUSFNM UEVWRUIsDQo+ID4gKwlyZWdfbnVtLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0 IHUzMiBzdnNfcmVnc192MltdID0gew0KPiA+ICsJW1RFTVBNT05DVEwwXQkJPSAweDAwMCwNCj4g PiArCVtURU1QTU9OQ1RMMV0JCT0gMHgwMDQsDQo+ID4gKwlbVEVNUE1PTkNUTDJdCQk9IDB4MDA4 LA0KPiA+ICsJW1RFTVBNT05JTlRdCQk9IDB4MDBjLA0KPiA+ICsJW1RFTVBNT05JTlRTVFNdCQk9 IDB4MDEwLA0KPiA+ICsJW1RFTVBNT05JREVUMF0JCT0gMHgwMTQsDQo+ID4gKwlbVEVNUE1PTklE RVQxXQkJPSAweDAxOCwNCj4gPiArCVtURU1QTU9OSURFVDJdCQk9IDB4MDFjLA0KPiA+ICsJW1RF TVBIMk5USFJFXQkJPSAweDAyNCwNCj4gPiArCVtURU1QSFRIUkVdCQk9IDB4MDI4LA0KPiA+ICsJ W1RFTVBDVEhSRV0JCT0gMHgwMmMsDQo+ID4gKwlbVEVNUE9GRlNFVEhdCQk9IDB4MDMwLA0KPiA+ ICsJW1RFTVBPRkZTRVRMXQkJPSAweDAzNCwNCj4gPiArCVtURU1QTVNSQ1RMMF0JCT0gMHgwMzgs DQo+ID4gKwlbVEVNUE1TUkNUTDFdCQk9IDB4MDNjLA0KPiA+ICsJW1RFTVBBSEJQT0xMXQkJPSAw eDA0MCwNCj4gPiArCVtURU1QQUhCVE9dCQk9IDB4MDQ0LA0KPiA+ICsJW1RFTVBBRENQTlAwXQkJ PSAweDA0OCwNCj4gPiArCVtURU1QQURDUE5QMV0JCT0gMHgwNGMsDQo+ID4gKwlbVEVNUEFEQ1BO UDJdCQk9IDB4MDUwLA0KPiA+ICsJW1RFTVBBRENNVVhdCQk9IDB4MDU0LA0KPiA+ICsJW1RFTVBB RENFWFRdCQk9IDB4MDU4LA0KPiA+ICsJW1RFTVBBRENFWFQxXQkJPSAweDA1YywNCj4gPiArCVtU RU1QQURDRU5dCQk9IDB4MDYwLA0KPiA+ICsJW1RFTVBQTlBNVVhBRERSXQk9IDB4MDY0LA0KPiA+ ICsJW1RFTVBBRENNVVhBRERSXQk9IDB4MDY4LA0KPiA+ICsJW1RFTVBBRENFWFRBRERSXQk9IDB4 MDZjLA0KPiA+ICsJW1RFTVBBRENFWFQxQUREUl0JPSAweDA3MCwNCj4gPiArCVtURU1QQURDRU5B RERSXQkJPSAweDA3NCwNCj4gPiArCVtURU1QQURDVkFMSURBRERSXQk9IDB4MDc4LA0KPiA+ICsJ W1RFTVBBRENWT0xUQUREUl0JPSAweDA3YywNCj4gPiArCVtURU1QUkRDVFJMXQkJPSAweDA4MCwN Cj4gPiArCVtURU1QQURDVkFMSURNQVNLXQk9IDB4MDg0LA0KPiA+ICsJW1RFTVBBRENWT0xUQUdF U0hJRlRdCT0gMHgwODgsDQo+ID4gKwlbVEVNUEFEQ1dSSVRFQ1RSTF0JPSAweDA4YywNCj4gPiAr CVtURU1QTVNSMF0JCT0gMHgwOTAsDQo+ID4gKwlbVEVNUE1TUjFdCQk9IDB4MDk0LA0KPiA+ICsJ W1RFTVBNU1IyXQkJPSAweDA5OCwNCj4gPiArCVtURU1QQURDSEFERFJdCQk9IDB4MDljLA0KPiA+ ICsJW1RFTVBJTU1EMF0JCT0gMHgwYTAsDQo+ID4gKwlbVEVNUElNTUQxXQkJPSAweDBhNCwNCj4g PiArCVtURU1QSU1NRDJdCQk9IDB4MGE4LA0KPiA+ICsJW1RFTVBNT05JREVUM10JCT0gMHgwYjAs DQo+ID4gKwlbVEVNUEFEQ1BOUDNdCQk9IDB4MGI0LA0KPiA+ICsJW1RFTVBNU1IzXQkJPSAweDBi OCwNCj4gPiArCVtURU1QSU1NRDNdCQk9IDB4MGJjLA0KPiA+ICsJW1RFTVBQUk9UQ1RMXQkJPSAw eDBjMCwNCj4gPiArCVtURU1QUFJPVFRBXQkJPSAweDBjNCwNCj4gPiArCVtURU1QUFJPVFRCXQkJ PSAweDBjOCwNCj4gPiArCVtURU1QUFJPVFRDXQkJPSAweDBjYywNCj4gPiArCVtURU1QU1BBUkUw XQkJPSAweDBmMCwNCj4gPiArCVtURU1QU1BBUkUxXQkJPSAweDBmNCwNCj4gPiArCVtURU1QU1BB UkUyXQkJPSAweDBmOCwNCj4gPiArCVtURU1QU1BBUkUzXQkJPSAweDBmYywNCj4gPiArCVtURU1Q TVNSMF8xXQkJPSAweDE5MCwNCj4gPiArCVtURU1QTVNSMV8xXQkJPSAweDE5NCwNCj4gPiArCVtU RU1QTVNSMl8xXQkJPSAweDE5OCwNCj4gPiArCVtURU1QTVNSM18xXQkJPSAweDFiOCwNCj4gPiAr CVtERVNDSEFSXQkJPSAweGMwMCwNCj4gPiArCVtURU1QQ0hBUl0JCT0gMHhjMDQsDQo+ID4gKwlb REVUQ0hBUl0JCT0gMHhjMDgsDQo+ID4gKwlbQUdFQ0hBUl0JCT0gMHhjMGMsDQo+ID4gKwlbREND T05GSUddCQk9IDB4YzEwLA0KPiA+ICsJW0FHRUNPTkZJR10JCT0gMHhjMTQsDQo+ID4gKwlbRlJF UVBDVDMwXQkJPSAweGMxOCwNCj4gPiArCVtGUkVRUENUNzRdCQk9IDB4YzFjLA0KPiA+ICsJW0xJ TUlUVkFMU10JCT0gMHhjMjAsDQo+ID4gKwlbVkJPT1RdCQkJPSAweGMyNCwNCj4gPiArCVtERVRX SU5ET1ddCQk9IDB4YzI4LA0KPiA+ICsJW0NPTkZJR10JCT0gMHhjMmMsDQo+ID4gKwlbVFNDQUxD U10JCT0gMHhjMzAsDQo+ID4gKwlbUlVOQ09ORklHXQkJPSAweGMzNCwNCj4gPiArCVtTVlNFTl0J CQk9IDB4YzM4LA0KPiA+ICsJW0lOSVQyVkFMU10JCT0gMHhjM2MsDQo+ID4gKwlbRENWQUxVRVNd CQk9IDB4YzQwLA0KPiA+ICsJW0FHRVZBTFVFU10JCT0gMHhjNDQsDQo+ID4gKwlbVk9QMzBdCQkJ PSAweGM0OCwNCj4gPiArCVtWT1A3NF0JCQk9IDB4YzRjLA0KPiA+ICsJW1RFTVBdCQkJPSAweGM1 MCwNCj4gPiArCVtJTlRTVFNdCQk9IDB4YzU0LA0KPiA+ICsJW0lOVFNUU1JBV10JCT0gMHhjNTgs DQo+ID4gKwlbSU5URU5dCQkJPSAweGM1YywNCj4gPiArCVtDSEtJTlRdCQk9IDB4YzYwLA0KPiA+ ICsJW0NIS1NISUZUXQkJPSAweGM2NCwNCj4gPiArCVtTVEFUVVNdCQk9IDB4YzY4LA0KPiA+ICsJ W1ZERVNJR04zMF0JCT0gMHhjNmMsDQo+ID4gKwlbVkRFU0lHTjc0XQkJPSAweGM3MCwNCj4gPiAr CVtEVlQzMF0JCQk9IDB4Yzc0LA0KPiA+ICsJW0RWVDc0XQkJCT0gMHhjNzgsDQo+ID4gKwlbQUdF Q09VTlRdCQk9IDB4YzdjLA0KPiA+ICsJW1NNU1RBVEUwXQkJPSAweGM4MCwNCj4gPiArCVtTTVNU QVRFMV0JCT0gMHhjODQsDQo+ID4gKwlbQ1RMMF0JCQk9IDB4Yzg4LA0KPiA+ICsJW0RFU0RFVFNF Q10JCT0gMHhjZTAsDQo+ID4gKwlbVEVNUEFHRVNFQ10JCT0gMHhjZTQsDQo+ID4gKwlbQ1RSTFNQ QVJFMF0JCT0gMHhjZjAsDQo+ID4gKwlbQ1RSTFNQQVJFMV0JCT0gMHhjZjQsDQo+ID4gKwlbQ1RS TFNQQVJFMl0JCT0gMHhjZjgsDQo+ID4gKwlbQ1RSTFNQQVJFM10JCT0gMHhjZmMsDQo+ID4gKwlb Q09SRVNFTF0JCT0gMHhmMDAsDQo+ID4gKwlbVEhFUk1JTlRTVF0JCT0gMHhmMDQsDQo+ID4gKwlb SU5UU1RdCQkJPSAweGYwOCwNCj4gPiArCVtUSFNUQUdFMFNUXQkJPSAweGYwYywNCj4gPiArCVtU SFNUQUdFMVNUXQkJPSAweGYxMCwNCj4gPiArCVtUSFNUQUdFMlNUXQkJPSAweGYxNCwNCj4gPiAr CVtUSEFIQlNUMF0JCT0gMHhmMTgsDQo+ID4gKwlbVEhBSEJTVDFdCQk9IDB4ZjFjLA0KPiA+ICsJ W1NQQVJFMF0JCT0gMHhmMjAsDQo+ID4gKwlbU1BBUkUxXQkJPSAweGYyNCwNCj4gPiArCVtTUEFS RTJdCQk9IDB4ZjI4LA0KPiA+ICsJW1NQQVJFM10JCT0gMHhmMmMsDQo+ID4gKwlbVEhTTFBFVkVC XQkJPSAweGYzMCwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVjdCB0aGVybWFsX3BhcmFtZXRl ciB7DQo+ID4gKwlpbnQgYWRjX2dlX3Q7DQo+ID4gKwlpbnQgYWRjX29lX3Q7DQo+ID4gKwlpbnQg Z2U7DQo+ID4gKwlpbnQgb2U7DQo+ID4gKwlpbnQgZ2FpbjsNCj4gPiArCWludCBvX3Z0c2FiYjsN Cj4gPiArCWludCBvX3Z0c21jdTE7DQo+ID4gKwlpbnQgb192dHNtY3UyOw0KPiA+ICsJaW50IG9f dnRzbWN1MzsNCj4gPiArCWludCBvX3Z0c21jdTQ7DQo+ID4gKwlpbnQgb192dHNtY3U1Ow0KPiA+ ICsJaW50IGRlZ2NfY2FsaTsNCj4gPiArCWludCBhZGNfY2FsaV9lbl90Ow0KPiA+ICsJaW50IG9f c2xvcGU7DQo+ID4gKwlpbnQgb19zbG9wZV9zaWduOw0KPiA+ICsJaW50IHRzX2lkOw0KPiA+ICt9 Ow0KPiA+ICsNCj4gPiArc3RydWN0IHN2c19iYW5rX29wcyB7DQo+ID4gKwl2b2lkICgqc2V0X2Zy ZXFzX3BjdCkoc3RydWN0IG10a19zdnMgKnN2cyk7DQo+ID4gKwl2b2lkICgqZ2V0X3ZvcHMpKHN0 cnVjdCBtdGtfc3ZzICpzdnMpOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IHN2c19iYW5r IHsNCj4gPiArCXN0cnVjdCBzdnNfYmFua19vcHMgKm9wczsNCj4gPiArCXN0cnVjdCBjb21wbGV0 aW9uIGluaXRfY29tcGxldGlvbjsNCj4gPiArCXN0cnVjdCBkZXZpY2UgKmRldjsNCj4gPiArCXN0 cnVjdCByZWd1bGF0b3IgKmJ1Y2s7DQo+ID4gKwlzdHJ1Y3QgbXV0ZXggbG9jazsJLyogbG9jayB0 byBwcm90ZWN0IHVwZGF0ZSB2b2x0YWdlIHByb2Nlc3MgKi8NCj4gPiArCWJvb2wgc3VzcGVuZGVk Ow0KPiA+ICsJYm9vbCBtdGNtb3NfcmVxdWVzdDsNCj4gPiArCWJvb2wgaW5pdDAxX3N1cHBvcnQ7 DQo+ID4gKwlib29sIGluaXQwMl9zdXBwb3J0Ow0KPiA+ICsJYm9vbCBtb25fbW9kZV9zdXBwb3J0 Ow0KPiA+ICsJczMyIHZvbHRfb2Zmc2V0Ow0KPiA+ICsJdTMyICpvcHBfZnJlcXM7DQo+ID4gKwl1 MzIgKmZyZXFzX3BjdDsNCj4gPiArCXUzMiAqb3BwX3ZvbHRzOw0KPiA+ICsJdTMyICppbml0MDJf dm9sdHM7DQo+ID4gKwl1MzIgKnZvbHRzOw0KPiA+ICsJdTMyIHJlZ19kYXRhWzNdW3JlZ19udW1d Ow0KPiA+ICsJdTMyIGZyZXFfYmFzZTsNCj4gPiArCXUzMiB2Ym9vdDsNCj4gPiArCXUzMiB2b2x0 X3N0ZXA7DQo+ID4gKwl1MzIgdm9sdF9iYXNlOw0KPiA+ICsJdTMyIGluaXQwMV92b2x0X2ZsYWc7 DQo+ID4gKwl1MzIgcGhhc2U7DQo+ID4gKwl1MzIgdm1heDsNCj4gPiArCXUzMiB2bWluOw0KPiA+ ICsJdTMyIGJ0czsNCj4gPiArCXUzMiBtdHM7DQo+ID4gKwl1MzIgYmRlczsNCj4gPiArCXUzMiBt ZGVzOw0KPiA+ICsJdTMyIG10ZGVzOw0KPiA+ICsJdTMyIGRjYmRldDsNCj4gPiArCXUzMiBkY21k ZXQ7DQo+ID4gKwl1MzIgZHRoaTsNCj4gPiArCXUzMiBkdGxvOw0KPiA+ICsJdTMyIGRldF93aW5k b3c7DQo+ID4gKwl1MzIgZGV0X21heDsNCj4gPiArCXUzMiBhZ2VfY29uZmlnOw0KPiA+ICsJdTMy IGFnZV92b2Zmc2V0X2luOw0KPiA+ICsJdTMyIGFnZW07DQo+ID4gKwl1MzIgZGNfY29uZmlnOw0K PiA+ICsJdTMyIGRjX3ZvZmZzZXRfaW47DQo+ID4gKwl1MzIgZHZ0X2ZpeGVkOw0KPiA+ICsJdTMy IHZjbzsNCj4gPiArCXUzMiBjaGtzaGlmdDsNCj4gPiArCXUzMiBzdnNfdGVtcDsNCj4gPiArCXUz MiB1cHBlcl90ZW1wX2JvdW5kOw0KPiA+ICsJdTMyIGxvd2VyX3RlbXBfYm91bmQ7DQo+ID4gKwl1 MzIgbG93X3RlbXBfdGhyZWFzaG9sZDsNCj4gPiArCXUzMiBsb3dfdGVtcF9vZmZzZXQ7DQo+ID4g Kwl1MzIgY29yZXNlbDsNCj4gPiArCXUzMiBvcHBfY291bnQ7DQo+ID4gKwl1MzIgaW50c3Q7DQo+ ID4gKwl1MzIgc3lzdGVtY2xrX2VuOw0KPiA+ICsJdTMyIHN3X2lkOw0KPiA+ICsJdTMyIGh3X2lk Ow0KPiA+ICsJdTMyIGN0bDA7DQo+ID4gKwl1OCAqb2ZfY29tcGF0aWJsZTsNCj4gPiArCXU4ICpu YW1lOw0KPiA+ICsJdTggKnpvbmVfbmFtZTsNCj4gPiArCXU4ICpidWNrX25hbWU7DQo+ID4gK307 DQo+ID4gKw0KPiA+ICtzdHJ1Y3Qgc3ZzX3BsYXRmb3JtIHsNCj4gPiArCXN0cnVjdCBzdnNfYmFu ayAqYmFua3M7DQo+ID4gKwlpbnQgKCplZnVzZV9wYXJzaW5nKShzdHJ1Y3QgbXRrX3N2cyAqc3Zz KTsNCj4gPiArCWJvb2wgZmFrZV9lZnVzZTsNCj4gPiArCWNvbnN0IHUzMiAqcmVnczsNCj4gPiAr CXUzMiBiYW5rX251bTsNCj4gPiArCXUzMiBlZnVzZV9udW07DQo+ID4gKwl1MzIgZWZ1c2VfY2hl Y2s7DQo+ID4gKwl1MzIgdGhlcm1hbF9lZnVzZV9udW07DQo+ID4gKwl1OCAqbmFtZTsNCj4gPiAr fTsNCj4gPiArDQo+ID4gK3N0cnVjdCBtdGtfc3ZzIHsNCj4gPiArCWNvbnN0IHN0cnVjdCBzdnNf cGxhdGZvcm0gKnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpiYW5rOw0KPiA+ICsJ c3RydWN0IGRldmljZSAqZGV2Ow0KPiA+ICsJdm9pZCBfX2lvbWVtICpiYXNlOw0KPiA+ICsJc3Ry dWN0IGNsayAqbWFpbl9jbGs7DQo+ID4gKwl1MzIgKmVmdXNlOw0KPiA+ICsJdTMyICp0aGVybWFs X2VmdXNlOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArdW5zaWduZWQgbG9uZyBjbGFpbV9tdGtfc3Zz X2xvY2sodm9pZCkNCj4gPiArew0KPiA+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsNCj4gPiArDQo+ ID4gKwlzcGluX2xvY2tfaXJxc2F2ZSgmbXRrX3N2c19sb2NrLCBmbGFncyk7DQo+ID4gKw0KPiA+ ICsJcmV0dXJuIGZsYWdzOw0KPiA+ICt9DQo+ID4gK0VYUE9SVF9TWU1CT0xfR1BMKGNsYWltX210 a19zdnNfbG9jayk7DQo+ID4gKw0KPiA+ICt2b2lkIHJlbGVhc2VfbXRrX3N2c19sb2NrKHVuc2ln bmVkIGxvbmcgZmxhZ3MpDQo+ID4gK3sNCj4gPiArCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJm10 a19zdnNfbG9jaywgZmxhZ3MpOw0KPiA+ICt9DQo+ID4gK0VYUE9SVF9TWU1CT0xfR1BMKHJlbGVh c2VfbXRrX3N2c19sb2NrKTsNCj4gDQo+IEkgZG9uJ3Qgc2VlIHRoZSBuZWVkIGZvciB0aGVzZSB3 cmFwcGVyIGZ1bmN0aW9ucy4gIFlvdSBzZWVtIHRvIGJlDQo+IGRlY2xhcmluZyB0aGlzIGxvY2sg aW4gdGhlIGhlYWRlciB3aGljaCBpbXBsaWVzIHRoZXJlIGFyZSBleHRlcm5hbA0KPiB1c2Vycywg YnV0IHRoZXJlIGlzIG5vbmUgaW4gdGhpcyBzZXJpZXMsIHNvIHRoaXMgbG9jayBzaG91bGQgc3Rh eSBsb2NhbA0KPiBJTU8uDQoNClRoaXMgZXhwb3J0IEFQSSBpcyBmb3IgbXRrIHRoZXJtYWwgZHJp dmVyLg0KaHR0cHM6Ly9wYXRjaHdvcmsua2VybmVsLm9yZy9wYXRjaC8xMDkzODg0MS8NCg0KPiAN Cj4gPiArc3RhdGljIHUzMiBwZXJjZW50KHUzMiBudW1lcmF0b3IsIHUzMiBkZW5vbWluYXRvcikN Cj4gPiArew0KPiA+ICsJdTMyIHBlcmNlbnQ7DQo+ID4gKw0KPiA+ICsJLyogSWYgbm90IGRpdmlk ZSAxMDAwLCAibnVtZXJhdG9yICogMTAwIiB3b3VsZCBiZSBkYXRhIG92ZXJmbG93LiAqLw0KPiA+ ICsJbnVtZXJhdG9yIC89IDEwMDA7DQo+ID4gKwlkZW5vbWluYXRvciAvPSAxMDAwOw0KPiA+ICsJ cGVyY2VudCA9ICgobnVtZXJhdG9yICogMTAwKSArIGRlbm9taW5hdG9yIC0gMSkgLyBkZW5vbWlu YXRvcjsNCj4gPiArDQo+ID4gKwlyZXR1cm4gcGVyY2VudDsNCj4gPiArfQ0KPiANCj4gTWF5YmUg c29tZSBtYXRoIGhlbHBlcnMgZnJvbSBtYXRoNjQuaCB3b3VsZCBoZWxwIHlvdSBub3QgaGF2ZSB0 bw0KPiBvcGVuLWNvZGUgdGhpcz8NCg0KT2gsIHRoYW5rcyBmb3IgdGhlIHJlbWluZGluZy4gSSBo YXZlbid0IGZvdW5kIHRoZSBzdWl0YWJsZSAicGVyY2VudCgpDQpBUEkiIGZyb20gbWF0aDY0Lmgg YW5kIHdpbGwga2VlcCBsb29raW5nIHN1aXRhYmxlIEFQSSB0byByZXBsYWNlIHRoZXNlDQpjb2Rl cy4NCg0KPiANCj4gPiArc3RhdGljIHUzMiBzdnNfcmVhZGwoc3RydWN0IG10a19zdnMgKnN2cywg ZW51bSByZWdfaW5kZXggaSkNCj4gPiArew0KPiA+ICsJcmV0dXJuIHJlYWRsKHN2cy0+YmFzZSAr IHN2cy0+cGxhdGZvcm0tPnJlZ3NbaV0pOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9p ZCBzdnNfd3JpdGVsKHN0cnVjdCBtdGtfc3ZzICpzdnMsIHUzMiB2YWwsIGVudW0gcmVnX2luZGV4 IGkpDQo+ID4gK3sNCj4gPiArCXdyaXRlbCh2YWwsIHN2cy0+YmFzZSArIHN2cy0+cGxhdGZvcm0t PnJlZ3NbaV0pOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBzdnNfc3dpdGNoX2Jh bmsoc3RydWN0IG10a19zdnMgKnN2cykNCj4gPiArew0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpz dnNiID0gc3ZzLT5iYW5rOw0KPiA+ICsNCj4gPiArCXN2c193cml0ZWwoc3ZzLCBzdnNiLT5jb3Jl c2VsLCBDT1JFU0VMKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHUzMiBzdnNfdm9sdF90 b19vcHBfdm9sdCh1MzIgc3ZzYl92b2x0LA0KPiA+ICsJCQkJdTMyIHN2c2Jfdm9sdF9zdGVwLCB1 MzIgc3ZzYl92b2x0X2Jhc2UpDQo+ID4gK3sNCj4gPiArCXUzMiB1X3ZvbHQ7DQo+ID4gKw0KPiA+ ICsJdV92b2x0ID0gKHN2c2Jfdm9sdCAqIHN2c2Jfdm9sdF9zdGVwKSArIHN2c2Jfdm9sdF9iYXNl Ow0KPiA+ICsNCj4gPiArCXJldHVybiB1X3ZvbHQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRp YyBpbnQgc3ZzX2dldF96b25lX3RlbXBlcmF0dXJlKHN0cnVjdCBzdnNfYmFuayAqc3ZzYiwgaW50 ICp6b25lX3RlbXApDQo+ID4gK3sNCj4gPiArCXN0cnVjdCB0aGVybWFsX3pvbmVfZGV2aWNlICp0 emQ7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCXR6ZCA9IHRoZXJtYWxfem9uZV9nZXRf em9uZV9ieV9uYW1lKHN2c2ItPnpvbmVfbmFtZSk7DQo+ID4gKwlyZXQgPSB0aGVybWFsX3pvbmVf Z2V0X3RlbXAodHpkLCB6b25lX3RlbXApOw0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4g K30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgc3ZzX3NldF92b2x0cyhzdHJ1Y3Qgc3ZzX2Jhbmsg KnN2c2IsIGJvb2wgZm9yY2VfdXBkYXRlKQ0KPiA+ICt7DQo+ID4gKwl1MzIgaSwgc3ZzYl92b2x0 LCBvcHBfdm9sdCwgbG93X3RlbXBfb2Zmc2V0ID0gMDsNCj4gPiArCWludCB6b25lX3RlbXAsIHJl dDsNCj4gPiArDQo+ID4gKwltdXRleF9sb2NrKCZzdnNiLT5sb2NrKTsNCj4gPiArDQo+ID4gKwkv KiBJZiBiYW5rIGlzIHN1c3BlbmRlZCwgaXQgbWVhbnMgaW5pdDAyIHZvbHRhZ2UgaXMgYXBwbGll ZC4NCj4gPiArCSAqIERvbid0IG5lZWQgdG8gdXBkYXRlIG9wcCB2b2x0YWdlIGFueW1vcmUuDQo+ ID4gKwkgKi8NCj4gDQo+IG1pbm9yIG5pdDogZml4IG11bHRpLWxpbmUgY29tbWVudCBzdHlsZQ0K DQpTdXJlLiBJJ2xsIGZpeCBpdCBpbiB0aGUgbmV4dCBwYXRjaC5UaGFua3MuDQoNCj4gDQo+ID4g KwlpZiAoc3ZzYi0+c3VzcGVuZGVkICYmICFmb3JjZV91cGRhdGUpIHsNCj4gPiArCQlwcl9ub3Rp Y2UoIiVzOiBiYW5rIGlzIHN1c3BlbmRlZFxuIiwgc3ZzYi0+bmFtZSk7DQo+ID4gKwkJbXV0ZXhf dW5sb2NrKCZzdnNiLT5sb2NrKTsNCj4gPiArCQlyZXR1cm4gLUVQRVJNOw0KPiA+ICsJfQ0KPiA+ ICsNCj4gPiArCS8qIGdldCB0aGVybWFsIGVmZmVjdCAqLw0KPiA+ICsJaWYgKHN2c2ItPnBoYXNl ID09IFNWU19QSEFTRV9NT04pIHsNCj4gPiArCQlpZiAoc3ZzYi0+c3ZzX3RlbXAgPiBzdnNiLT51 cHBlcl90ZW1wX2JvdW5kICYmDQo+ID4gKwkJICAgIHN2c2ItPnN2c190ZW1wIDwgc3ZzYi0+bG93 ZXJfdGVtcF9ib3VuZCkgew0KPiA+ICsJCQlwcl9lcnIoIiVzOiBzdnNfdGVtcCBpcyBhYm5vcm1h bCAoMHgleCk/XG4iLA0KPiA+ICsJCQkgICAgICAgc3ZzYi0+bmFtZSwgc3ZzYi0+c3ZzX3RlbXAp Ow0KPiA+ICsJCQltdXRleF91bmxvY2soJnN2c2ItPmxvY2spOw0KPiA+ICsJCQlyZXR1cm4gLUVJ TlZBTDsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCXJldCA9IHN2c19nZXRfem9uZV90ZW1wZXJh dHVyZShzdnNiLCAmem9uZV90ZW1wKTsNCj4gPiArCQlpZiAocmV0KSB7DQo+ID4gKwkJCXByX2Vy cigiJXM6IGNhbm5vdCBnZXQgem9uZSBcIiVzXCIgdGVtcGVyYXR1cmVcbiIsDQo+ID4gKwkJCSAg ICAgICBzdnNiLT5uYW1lLCBzdnNiLT56b25lX25hbWUpOw0KPiA+ICsJCQlwcl9lcnIoIiVzOiBh ZGQgbG93X3RlbXBfb2Zmc2V0ID0gJXVcbiIsDQo+ID4gKwkJCSAgICAgICBzdnNiLT5uYW1lLCBz dnNiLT5sb3dfdGVtcF9vZmZzZXQpOw0KPiA+ICsJCQl6b25lX3RlbXAgPSBzdnNiLT5sb3dfdGVt cF90aHJlYXNob2xkOw0KPiA+ICsJCX0NCj4gPiArDQo+ID4gKwkJaWYgKHpvbmVfdGVtcCA8PSBz dnNiLT5sb3dfdGVtcF90aHJlYXNob2xkKQ0KPiA+ICsJCQlsb3dfdGVtcF9vZmZzZXQgPSBzdnNi LT5sb3dfdGVtcF9vZmZzZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJLyogdm1pbiA8PSBzdnNi X3ZvbHQgKG9wcF92b2x0KSA8PSBzaWduZWQtb2ZmIHZvbHRhZ2UgKi8NCj4gPiArCWZvciAoaSA9 IDA7IGkgPCBzdnNiLT5vcHBfY291bnQ7IGkrKykgew0KPiA+ICsJCWlmIChzdnNiLT5waGFzZSA9 PSBTVlNfUEhBU0VfTU9OKSB7DQo+ID4gKwkJCXN2c2Jfdm9sdCA9IG1heCgoc3ZzYi0+dm9sdHNb aV0gKyBzdnNiLT52b2x0X29mZnNldCArDQo+ID4gKwkJCQkJIGxvd190ZW1wX29mZnNldCksIHN2 c2ItPnZtaW4pOw0KPiA+ICsJCQlvcHBfdm9sdCA9IHN2c192b2x0X3RvX29wcF92b2x0KHN2c2Jf dm9sdCwNCj4gPiArCQkJCQkJCXN2c2ItPnZvbHRfc3RlcCwNCj4gPiArCQkJCQkJCXN2c2ItPnZv bHRfYmFzZSk7DQo+ID4gKwkJfSBlbHNlIGlmIChzdnNiLT5waGFzZSA9PSBTVlNfUEhBU0VfSU5J VDAyKSB7DQo+ID4gKwkJCXN2c2Jfdm9sdCA9IG1heCgoc3ZzYi0+aW5pdDAyX3ZvbHRzW2ldICsN Cj4gPiArCQkJCQkgc3ZzYi0+dm9sdF9vZmZzZXQpLCBzdnNiLT52bWluKTsNCj4gPiArCQkJb3Bw X3ZvbHQgPSBzdnNfdm9sdF90b19vcHBfdm9sdChzdnNiX3ZvbHQsDQo+ID4gKwkJCQkJCQlzdnNi LT52b2x0X3N0ZXAsDQo+ID4gKwkJCQkJCQlzdnNiLT52b2x0X2Jhc2UpOw0KPiA+ICsJCX0gZWxz ZSBpZiAoc3ZzYi0+cGhhc2UgPT0gU1ZTX1BIQVNFX0VSUk9SKSB7DQo+ID4gKwkJCW9wcF92b2x0 ID0gc3ZzYi0+b3BwX3ZvbHRzW2ldOw0KPiA+ICsJCX0gZWxzZSB7DQo+ID4gKwkJCXByX2Vycigi JXM6IHVua25vd24gcGhhc2U6ICV1P1xuIiwNCj4gPiArCQkJICAgICAgIHN2c2ItPm5hbWUsIHN2 c2ItPnBoYXNlKTsNCj4gPiArCQkJbXV0ZXhfdW5sb2NrKCZzdnNiLT5sb2NrKTsNCj4gPiArCQkJ cmV0dXJuIC1FSU5WQUw7DQo+ID4gKwkJfQ0KPiA+ICsNCj4gPiArCQlvcHBfdm9sdCA9IG1pbihv cHBfdm9sdCwgc3ZzYi0+b3BwX3ZvbHRzW2ldKTsNCj4gPiArCQlyZXQgPSBkZXZfcG1fb3BwX2Fk anVzdF92b2x0YWdlKHN2c2ItPmRldiwgc3ZzYi0+b3BwX2ZyZXFzW2ldLA0KPiA+ICsJCQkJCQlv cHBfdm9sdCk7DQo+ID4gKwkJaWYgKHJldCkgew0KPiA+ICsJCQlwcl9lcnIoIiVzOiBzZXQgdm9s dGFnZSBmYWlsZWQ6ICVkXG4iLCBzdnNiLT5uYW1lLCByZXQpOw0KPiA+ICsJCQltdXRleF91bmxv Y2soJnN2c2ItPmxvY2spOw0KPiA+ICsJCQlyZXR1cm4gcmV0Ow0KPiA+ICsJCX0NCj4gPiArCX0N Cj4gPiArDQo+ID4gKwltdXRleF91bmxvY2soJnN2c2ItPmxvY2spOw0KPiA+ICsNCj4gPiArCXJl dHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdTMyIGludGVycG9sYXRlKHUzMiBm MCwgdTMyIGYxLCB1MzIgdjAsIHUzMiB2MSwgdTMyIGZ4KQ0KPiA+ICt7DQo+ID4gKwl1MzIgdnk7 DQo+ID4gKw0KPiA+ICsJaWYgKHYwID09IHYxIHx8IGYwID09IGYxKQ0KPiA+ICsJCXJldHVybiB2 MDsNCj4gPiArDQo+ID4gKwkvKiAqMTAwIHRvIGhhdmUgZGVjaW1hbCBmcmFjdGlvbiBmYWN0b3Is ICs5OSBmb3Igcm91bmRpbmcgdXAuICovDQo+ID4gKwl2eSA9ICh2MCAqIDEwMCkgLSAoKCgodjAg LSB2MSkgKiAxMDApIC8gKGYwIC0gZjEpKSAqIChmMCAtIGZ4KSk7DQo+ID4gKwl2eSA9ICh2eSAr IDk5KSAvIDEwMDsNCj4gPiArDQo+ID4gKwlyZXR1cm4gdnk7DQo+ID4gK30NCj4gPiArDQo+ID4g K3N0YXRpYyB2b2lkIHN2c19nZXRfdm9wc192MihzdHJ1Y3QgbXRrX3N2cyAqc3ZzKQ0KPiA+ICt7 DQo+ID4gKwlzdHJ1Y3Qgc3ZzX2JhbmsgKnN2c2IgPSBzdnMtPmJhbms7DQo+ID4gKwl1MzIgdGVt cCwgaTsNCj4gPiArDQo+ID4gKwl0ZW1wID0gc3ZzX3JlYWRsKHN2cywgVk9QMzApOw0KPiA+ICsJ c3ZzYi0+dm9sdHNbNl0gPSAodGVtcCA+PiAyNCkgJiAweGZmOw0KPiA+ICsJc3ZzYi0+dm9sdHNb NF0gPSAodGVtcCA+PiAxNikgJiAweGZmOw0KPiA+ICsJc3ZzYi0+dm9sdHNbMl0gPSAodGVtcCA+ PiA4KSAgJiAweGZmOw0KPiA+ICsJc3ZzYi0+dm9sdHNbMF0gPSAodGVtcCAmIDB4ZmYpOw0KPiA+ ICsNCj4gPiArCXRlbXAgPSBzdnNfcmVhZGwoc3ZzLCBWT1A3NCk7DQo+ID4gKwlzdnNiLT52b2x0 c1sxNF0gPSAodGVtcCA+PiAyNCkgJiAweGZmOw0KPiA+ICsJc3ZzYi0+dm9sdHNbMTJdID0gKHRl bXAgPj4gMTYpICYgMHhmZjsNCj4gPiArCXN2c2ItPnZvbHRzWzEwXSA9ICh0ZW1wID4+IDgpICAm IDB4ZmY7DQo+ID4gKwlzdnNiLT52b2x0c1s4XSA9ICh0ZW1wICYgMHhmZik7DQo+ID4gKw0KPiA+ ICsJZm9yIChpID0gMDsgaSA8PSA3OyBpKyspIHsNCj4gPiArCQlpZiAoaSA8IDcpIHsNCj4gPiAr CQkJc3ZzYi0+dm9sdHNbKGkgKiAyKSArIDFdID0NCj4gPiArCQkJCWludGVycG9sYXRlKHN2c2It PmZyZXFzX3BjdFtpICogMl0sDQo+ID4gKwkJCQkJICAgIHN2c2ItPmZyZXFzX3BjdFsoaSArIDEp ICogMl0sDQo+ID4gKwkJCQkJICAgIHN2c2ItPnZvbHRzW2kgKiAyXSwNCj4gPiArCQkJCQkgICAg c3ZzYi0+dm9sdHNbKGkgKyAxKSAqIDJdLA0KPiA+ICsJCQkJCSAgICBzdnNiLT5mcmVxc19wY3Rb KGkgKiAyKSArIDFdKTsNCj4gPiArCQl9IGVsc2UgaWYgKGkgPT0gNykgew0KPiA+ICsJCQlzdnNi LT52b2x0c1soaSAqIDIpICsgMV0gPQ0KPiA+ICsJCQkJaW50ZXJwb2xhdGUoc3ZzYi0+ZnJlcXNf cGN0WyhpIC0gMSkgKiAyXSwNCj4gPiArCQkJCQkgICAgc3ZzYi0+ZnJlcXNfcGN0W2kgKiAyXSwN Cj4gPiArCQkJCQkgICAgc3ZzYi0+dm9sdHNbKGkgLSAxKSAqIDJdLA0KPiA+ICsJCQkJCSAgICBz dnNiLT52b2x0c1tpICogMl0sDQo+ID4gKwkJCQkJICAgIHN2c2ItPmZyZXFzX3BjdFsoaSAqIDIp ICsgMV0pOw0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZv aWQgc3ZzX3NldF9mcmVxc19wY3RfdjIoc3RydWN0IG10a19zdnMgKnN2cykNCj4gPiArew0KPiA+ ICsJc3RydWN0IHN2c19iYW5rICpzdnNiID0gc3ZzLT5iYW5rOw0KPiA+ICsNCj4gPiArCXN2c193 cml0ZWwoc3ZzLA0KPiA+ICsJCSAgICgoc3ZzYi0+ZnJlcXNfcGN0WzZdIDw8IDI0KSAmIDB4ZmYw MDAwMDApIHwNCj4gPiArCQkgICAoKHN2c2ItPmZyZXFzX3BjdFs0XSA8PCAxNikgJiAweGZmMDAw MCkgfA0KPiA+ICsJCSAgICgoc3ZzYi0+ZnJlcXNfcGN0WzJdIDw8IDgpICYgMHhmZjAwKSB8DQo+ ID4gKwkJICAgKHN2c2ItPmZyZXFzX3BjdFswXSAmIDB4ZmYpLA0KPiA+ICsJCSAgIEZSRVFQQ1Qz MCk7DQo+ID4gKwlzdnNfd3JpdGVsKHN2cywNCj4gPiArCQkgICAoKHN2c2ItPmZyZXFzX3BjdFsx NF0gPDwgMjQpICYgMHhmZjAwMDAwMCkgfA0KPiA+ICsJCSAgICgoc3ZzYi0+ZnJlcXNfcGN0WzEy XSA8PCAxNikgJiAweGZmMDAwMCkgfA0KPiA+ICsJCSAgICgoc3ZzYi0+ZnJlcXNfcGN0WzEwXSA8 PCA4KSAmIDB4ZmYwMCkgfA0KPiA+ICsJCSAgICgoc3ZzYi0+ZnJlcXNfcGN0WzhdKSAmIDB4ZmYp LA0KPiA+ICsJCSAgIEZSRVFQQ1Q3NCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lk IHN2c19zZXRfcGhhc2Uoc3RydWN0IG10a19zdnMgKnN2cywgdTMyIHRhcmdldF9waGFzZSkNCj4g PiArew0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpzdnNiID0gc3ZzLT5iYW5rOw0KPiA+ICsJdTMy IGRlc19jaGFyLCB0ZW1wX2NoYXIsIGRldF9jaGFyLCBsaW1pdF92YWxzOw0KPiA+ICsJdTMyIGlu aXQydmFscywgdHNfY2FsY3MsIHZhbCwgZmlsdGVyLCBpOw0KPiA+ICsNCj4gPiArCXN2c19zd2l0 Y2hfYmFuayhzdnMpOw0KPiA+ICsNCj4gPiArCWRlc19jaGFyID0gKChzdnNiLT5iZGVzIDw8IDgp ICYgMHhmZjAwKSB8IChzdnNiLT5tZGVzICYgMHhmZik7DQo+ID4gKwlzdnNfd3JpdGVsKHN2cywg ZGVzX2NoYXIsIERFU0NIQVIpOw0KPiA+ICsNCj4gPiArCXRlbXBfY2hhciA9ICgoc3ZzYi0+dmNv IDw8IDE2KSAmIDB4ZmYwMDAwKSB8DQo+ID4gKwkJICAgICgoc3ZzYi0+bXRkZXMgPDwgOCkgJiAw eGZmMDApIHwNCj4gPiArCQkgICAgKHN2c2ItPmR2dF9maXhlZCAmIDB4ZmYpOw0KPiA+ICsJc3Zz X3dyaXRlbChzdnMsIHRlbXBfY2hhciwgVEVNUENIQVIpOw0KPiA+ICsNCj4gPiArCWRldF9jaGFy ID0gKChzdnNiLT5kY2JkZXQgPDwgOCkgJiAweGZmMDApIHwgKHN2c2ItPmRjbWRldCAmIDB4ZmYp Ow0KPiA+ICsJc3ZzX3dyaXRlbChzdnMsIGRldF9jaGFyLCBERVRDSEFSKTsNCj4gPiArDQo+ID4g KwlzdnNfd3JpdGVsKHN2cywgc3ZzYi0+ZGNfY29uZmlnLCBEQ0NPTkZJRyk7DQo+ID4gKwlzdnNf d3JpdGVsKHN2cywgc3ZzYi0+YWdlX2NvbmZpZywgQUdFQ09ORklHKTsNCj4gPiArDQo+ID4gKwlp ZiAoc3ZzYi0+YWdlbSA9PSAweDApIHsNCj4gPiArCQlzdnNfd3JpdGVsKHN2cywgMHg4MDAwMDAw MCwgUlVOQ09ORklHKTsNCj4gPiArCX0gZWxzZSB7DQo+ID4gKwkJdmFsID0gMHgwOw0KPiA+ICsN Cj4gPiArCQlmb3IgKGkgPSAwOyBpIDwgMjQ7IGkgKz0gMikgew0KPiA+ICsJCQlmaWx0ZXIgPSAw eDMgPDwgaTsNCj4gPiArDQo+ID4gKwkJCWlmICgoc3ZzYi0+YWdlX2NvbmZpZyAmIGZpbHRlcikg PT0gMHgwKQ0KPiA+ICsJCQkJdmFsIHw9ICgweDEgPDwgaSk7DQo+ID4gKwkJCWVsc2UNCj4gPiAr CQkJCXZhbCB8PSAoc3ZzYi0+YWdlX2NvbmZpZyAmIGZpbHRlcik7DQo+ID4gKwkJfQ0KPiA+ICsJ CXN2c193cml0ZWwoc3ZzLCB2YWwsIFJVTkNPTkZJRyk7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJ c3ZzYi0+b3BzLT5zZXRfZnJlcXNfcGN0KHN2cyk7DQo+ID4gKw0KPiA+ICsJbGltaXRfdmFscyA9 ICgoc3ZzYi0+dm1heCA8PCAyNCkgJiAweGZmMDAwMDAwKSB8DQo+ID4gKwkJICAgICAoKHN2c2It PnZtaW4gPDwgMTYpICYgMHhmZjAwMDApIHwNCj4gPiArCQkgICAgICgoc3ZzYi0+ZHRoaSA8PCA4 KSAmIDB4ZmYwMCkgfA0KPiA+ICsJCSAgICAgKHN2c2ItPmR0bG8gJiAweGZmKTsNCj4gPiArCXN2 c193cml0ZWwoc3ZzLCBsaW1pdF92YWxzLCBMSU1JVFZBTFMpOw0KPiA+ICsJc3ZzX3dyaXRlbChz dnMsIChzdnNiLT52Ym9vdCAmIDB4ZmYpLCBWQk9PVCk7DQo+ID4gKwlzdnNfd3JpdGVsKHN2cywg KHN2c2ItPmRldF93aW5kb3cgJiAweGZmZmYpLCBERVRXSU5ET1cpOw0KPiA+ICsJc3ZzX3dyaXRl bChzdnMsIChzdnNiLT5kZXRfbWF4ICYgMHhmZmZmKSwgQ09ORklHKTsNCj4gPiArDQo+ID4gKwlp ZiAoc3ZzYi0+Y2hrc2hpZnQgIT0gMCkNCj4gPiArCQlzdnNfd3JpdGVsKHN2cywgKHN2c2ItPmNo a3NoaWZ0ICYgMHhmZiksIENIS1NISUZUKTsNCj4gPiArDQo+ID4gKwlpZiAoc3ZzYi0+Y3RsMCAh PSAwKQ0KPiA+ICsJCXN2c193cml0ZWwoc3ZzLCBzdnNiLT5jdGwwLCBDVEwwKTsNCj4gPiArDQo+ ID4gKwlzdnNfd3JpdGVsKHN2cywgMHgwMGZmZmZmZiwgSU5UU1RTKTsNCj4gPiArDQo+ID4gKwlz d2l0Y2ggKHRhcmdldF9waGFzZSkgew0KPiA+ICsJY2FzZSBTVlNfUEhBU0VfSU5JVDAxOg0KPiA+ ICsJCXN2c193cml0ZWwoc3ZzLCAweDAwMDA1ZjAxLCBJTlRFTik7DQo+ID4gKwkJc3ZzX3dyaXRl bChzdnMsIDB4MDAwMDAwMDEsIFNWU0VOKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWNhc2UgU1ZT X1BIQVNFX0lOSVQwMjoNCj4gPiArCQlzdnNfd3JpdGVsKHN2cywgMHgwMDAwNWYwMSwgSU5URU4p Ow0KPiA+ICsJCWluaXQydmFscyA9ICgoc3ZzYi0+YWdlX3ZvZmZzZXRfaW4gPDwgMTYpICYgMHhm ZmZmMDAwMCkgfA0KPiA+ICsJCQkgICAgKHN2c2ItPmRjX3ZvZmZzZXRfaW4gJiAweGZmZmYpOw0K PiA+ICsJCXN2c193cml0ZWwoc3ZzLCBpbml0MnZhbHMsIElOSVQyVkFMUyk7DQo+ID4gKwkJc3Zz X3dyaXRlbChzdnMsIDB4MDAwMDAwMDUsIFNWU0VOKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWNh c2UgU1ZTX1BIQVNFX01PTjoNCj4gPiArCQl0c19jYWxjcyA9ICgoc3ZzYi0+YnRzIDw8IDEyKSAm IDB4ZmZmMDAwKSB8IChzdnNiLT5tdHMgJiAweGZmZik7DQo+ID4gKwkJc3ZzX3dyaXRlbChzdnMs IHRzX2NhbGNzLCBUU0NBTENTKTsNCj4gPiArCQlzdnNfd3JpdGVsKHN2cywgMHgwMEZGMDAwMCwg SU5URU4pOw0KPiA+ICsJCXN2c193cml0ZWwoc3ZzLCAweDAwMDAwMDAyLCBTVlNFTik7DQo+ID4g KwkJYnJlYWs7DQo+ID4gKwlkZWZhdWx0Og0KPiA+ICsJCVdBUk5fT04oMSk7DQo+ID4gKwkJYnJl YWs7DQo+ID4gKwl9DQo+ID4gK30NCj4gDQo+IGxvdHMgb2YgIG1hZ2ljIGNvbnN0YW50cyBmb3Ig dGhlc2UgcmVnaXN0ZXIgd3JpdGVzLiAgI2RlZmluZXMgdy9iaXQNCj4gZGVzY3JpcHRpb25zIHdv dWxkIGJlIHZlcnkgaGVscGZ1bCBmb3IgdGhlIHJlYWRlci4NCg0KU3VyZSwgSSdsbCBhZGQgI2Rl ZmluZSB3L2JpdCBmb3IgdGhlc2UgbWFnaWMgY29uc3RhbnRzIGluIHRoZSBuZXh0DQpwYXRjaC4g VGhhbmtzLg0KDQo+IA0KPiA+ICtzdGF0aWMgaW5saW5lIHZvaWQgc3ZzX2luaXQwMV9pc3JfaGFu ZGxlcihzdHJ1Y3QgbXRrX3N2cyAqc3ZzKQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3Qgc3ZzX2Jhbmsg KnN2c2IgPSBzdnMtPmJhbms7DQo+ID4gKwllbnVtIHJlZ19pbmRleCByZ19pOw0KPiA+ICsNCj4g PiArCXByX25vdGljZSgiJXM6ICVzOiBWRE43NDoweCUwOHgsIFZETjMwOjB4JTA4eCwgRENWQUxV RVM6MHglMDh4XG4iLA0KPiA+ICsJCSAgc3ZzYi0+bmFtZSwgX19mdW5jX18sIHN2c19yZWFkbChz dnMsIFZERVNJR043NCksDQo+ID4gKwkJICBzdnNfcmVhZGwoc3ZzLCBWREVTSUdOMzApLCBzdnNf cmVhZGwoc3ZzLCBEQ1ZBTFVFUykpOw0KPiA+ICsNCj4gPiArCWZvciAocmdfaSA9IFRFTVBNT05D VEwwOyByZ19pIDwgcmVnX251bTsgcmdfaSsrKQ0KPiA+ICsJCXN2c2ItPnJlZ19kYXRhW1NWU19Q SEFTRV9JTklUMDFdW3JnX2ldID0gc3ZzX3JlYWRsKHN2cywgcmdfaSk7DQo+ID4gKw0KPiA+ICsJ c3ZzYi0+ZGNfdm9mZnNldF9pbiA9IH4oc3ZzX3JlYWRsKHN2cywgRENWQUxVRVMpICYgMHhmZmZm KSArIDE7DQo+ID4gKwlpZiAoc3ZzYi0+aW5pdDAxX3ZvbHRfZmxhZyA9PSBTVlNfSU5JVDAxX1ZP TFRfSUdOT1JFKQ0KPiA+ICsJCXN2c2ItPmRjX3ZvZmZzZXRfaW4gPSAwOw0KPiA+ICsJZWxzZSBp ZiAoKHN2c2ItPmRjX3ZvZmZzZXRfaW4gJiAweDgwMDApICYmDQo+ID4gKwkJIChzdnNiLT5pbml0 MDFfdm9sdF9mbGFnID09IFNWU19JTklUMDFfVk9MVF9JTkNfT05MWSkpDQo+ID4gKwkJc3ZzYi0+ ZGNfdm9mZnNldF9pbiA9IDA7DQo+ID4gKw0KPiA+ICsJc3ZzYi0+YWdlX3ZvZmZzZXRfaW4gPSBz dnNfcmVhZGwoc3ZzLCBBR0VWQUxVRVMpICYgMHhmZmZmOw0KPiA+ICsNCj4gPiArCXN2c193cml0 ZWwoc3ZzLCAweDAsIFNWU0VOKTsNCj4gPiArCXN2c193cml0ZWwoc3ZzLCAweDEsIElOVFNUUyk7 DQo+ID4gKw0KPiA+ICsJLyogc3ZzIGluaXQwMSBjbG9jayBnYXRpbmcgKi8NCj4gPiArCXN2c2It PmNvcmVzZWwgJj0gfnN2c2ItPnN5c3RlbWNsa19lbjsNCj4gPiArDQo+ID4gKwlzdnNiLT5waGFz ZSA9IFNWU19QSEFTRV9JTklUMDE7DQo+ID4gKwljb21wbGV0ZSgmc3ZzYi0+aW5pdF9jb21wbGV0 aW9uKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSB2b2lkIHN2c19pbml0MDJf aXNyX2hhbmRsZXIoc3RydWN0IG10a19zdnMgKnN2cykNCj4gPiArew0KPiA+ICsJc3RydWN0IHN2 c19iYW5rICpzdnNiID0gc3ZzLT5iYW5rOw0KPiA+ICsJZW51bSByZWdfaW5kZXggcmdfaTsNCj4g PiArDQo+ID4gKwlwcl9ub3RpY2UoIiVzOiAlczogVk9QNzQ6MHglMDh4LCBWT1AzMDoweCUwOHgs IERDVkFMVUVTOjB4JTA4eFxuIiwNCj4gPiArCQkgIHN2c2ItPm5hbWUsIF9fZnVuY19fLCBzdnNf cmVhZGwoc3ZzLCBWT1A3NCksDQo+ID4gKwkJICBzdnNfcmVhZGwoc3ZzLCBWT1AzMCksIHN2c19y ZWFkbChzdnMsIERDVkFMVUVTKSk7DQo+ID4gKw0KPiA+ICsJZm9yIChyZ19pID0gVEVNUE1PTkNU TDA7IHJnX2kgPCByZWdfbnVtOyByZ19pKyspDQo+ID4gKwkJc3ZzYi0+cmVnX2RhdGFbU1ZTX1BI QVNFX0lOSVQwMl1bcmdfaV0gPSBzdnNfcmVhZGwoc3ZzLCByZ19pKTsNCj4gPiArDQo+ID4gKwlz dnNiLT5vcHMtPmdldF92b3BzKHN2cyk7DQo+ID4gKwltZW1jcHkoc3ZzYi0+aW5pdDAyX3ZvbHRz LCBzdnNiLT52b2x0cywgNCAqIHN2c2ItPm9wcF9jb3VudCk7DQo+ID4gKwlzdnNiLT5waGFzZSA9 IFNWU19QSEFTRV9JTklUMDI7DQo+ID4gKw0KPiA+ICsJc3ZzX3dyaXRlbChzdnMsIDB4MCwgU1ZT RU4pOw0KPiA+ICsJc3ZzX3dyaXRlbChzdnMsIDB4MSwgSU5UU1RTKTsNCj4gPiArDQo+ID4gKwlj b21wbGV0ZSgmc3ZzYi0+aW5pdF9jb21wbGV0aW9uKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3Rh dGljIGlubGluZSB2b2lkIHN2c19tb25fbW9kZV9pc3JfaGFuZGxlcihzdHJ1Y3QgbXRrX3N2cyAq c3ZzKQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3Qgc3ZzX2JhbmsgKnN2c2IgPSBzdnMtPmJhbms7DQo+ ID4gKwllbnVtIHJlZ19pbmRleCByZ19pOw0KPiA+ICsNCj4gPiArCWZvciAocmdfaSA9IFRFTVBN T05DVEwwOyByZ19pIDwgcmVnX251bTsgcmdfaSsrKQ0KPiA+ICsJCXN2c2ItPnJlZ19kYXRhW1NW U19QSEFTRV9NT05dW3JnX2ldID0gc3ZzX3JlYWRsKHN2cywgcmdfaSk7DQo+ID4gKw0KPiA+ICsJ c3ZzYi0+c3ZzX3RlbXAgPSBzdnNfcmVhZGwoc3ZzLCBURU1QKSAmIDB4ZmY7DQo+ID4gKw0KPiA+ ICsJc3ZzYi0+b3BzLT5nZXRfdm9wcyhzdnMpOw0KPiA+ICsJc3ZzYi0+cGhhc2UgPSBTVlNfUEhB U0VfTU9OOw0KPiA+ICsNCj4gPiArCXN2c193cml0ZWwoc3ZzLCAweDAwZmYwMDAwLCBJTlRTVFMp Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW5saW5lIHZvaWQgc3ZzX2Vycm9yX2lzcl9o YW5kbGVyKHN0cnVjdCBtdGtfc3ZzICpzdnMpDQo+ID4gK3sNCj4gPiArCWNvbnN0IHN0cnVjdCBz dnNfcGxhdGZvcm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5r ICpzdnNiID0gc3ZzLT5iYW5rOw0KPiA+ICsJZW51bSByZWdfaW5kZXggcmdfaTsNCj4gPiArDQo+ ID4gKwlwcl9lcnIoIiVzKCk6ICVzKCVzKSIsIF9fZnVuY19fLCBzdnNwLT5uYW1lLCBzdnNiLT5u YW1lKTsNCj4gPiArCXByX2VycigiQ09SRVNFTCgweCV4KSA9IDB4JTA4eFxuIiwNCj4gPiArCSAg ICAgICBzdnNwLT5yZWdzW0NPUkVTRUxdLCBzdnNfcmVhZGwoc3ZzLCBDT1JFU0VMKSksDQo+ID4g Kwlwcl9lcnIoIlNWU0VOKDB4JXgpID0gMHglMDh4LCBJTlRTVFMoMHgleCkgPSAweCUwOHhcbiIs DQo+ID4gKwkgICAgICAgc3ZzcC0+cmVnc1tTVlNFTl0sIHN2c19yZWFkbChzdnMsIFNWU0VOKSwN Cj4gPiArCSAgICAgICBzdnNwLT5yZWdzW0lOVFNUU10sIHN2c19yZWFkbChzdnMsIElOVFNUUykp Ow0KPiA+ICsJcHJfZXJyKCJTTVNUQVRFMCgweCV4KSA9IDB4JTA4eCwgU01TVEFURTEoMHgleCkg PSAweCUwOHhcbiIsDQo+ID4gKwkgICAgICAgc3ZzcC0+cmVnc1tTTVNUQVRFMF0sIHN2c19yZWFk bChzdnMsIFNNU1RBVEUwKSwNCj4gPiArCSAgICAgICBzdnNwLT5yZWdzW1NNU1RBVEUxXSwgc3Zz X3JlYWRsKHN2cywgU01TVEFURTEpKTsNCj4gPiArDQo+ID4gKwlmb3IgKHJnX2kgPSBURU1QTU9O Q1RMMDsgcmdfaSA8IHJlZ19udW07IHJnX2krKykNCj4gPiArCQlzdnNiLT5yZWdfZGF0YVtTVlNf UEhBU0VfTU9OXVtyZ19pXSA9IHN2c19yZWFkbChzdnMsIHJnX2kpOw0KPiA+ICsNCj4gPiArCXN2 c2ItPmluaXQwMV9zdXBwb3J0ID0gZmFsc2U7DQo+ID4gKwlzdnNiLT5pbml0MDJfc3VwcG9ydCA9 IGZhbHNlOw0KPiA+ICsJc3ZzYi0+bW9uX21vZGVfc3VwcG9ydCA9IGZhbHNlOw0KPiA+ICsNCj4g PiArCWlmIChzdnNiLT5waGFzZSA9PSBTVlNfUEhBU0VfTU9OKQ0KPiA+ICsJCXN2c2ItPnBoYXNl ID0gU1ZTX1BIQVNFX0lOSVQwMjsNCj4gPiArDQo+ID4gKwlzdnNfd3JpdGVsKHN2cywgMHgwLCBT VlNFTik7DQo+ID4gKwlzdnNfd3JpdGVsKHN2cywgMHgwMGZmZmZmZiwgSU5UU1RTKTsNCj4gPiAr fQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSB2b2lkIHN2c19pc3JfaGFuZGxlcihzdHJ1Y3Qg bXRrX3N2cyAqc3ZzKQ0KPiA+ICt7DQo+ID4gKwl1MzIgaW50c3RzLCBzdnNlbjsNCj4gPiArDQo+ ID4gKwlzdnNfc3dpdGNoX2Jhbmsoc3ZzKTsNCj4gPiArDQo+ID4gKwlpbnRzdHMgPSBzdnNfcmVh ZGwoc3ZzLCBJTlRTVFMpOw0KPiA+ICsJc3ZzZW4gPSBzdnNfcmVhZGwoc3ZzLCBTVlNFTik7DQo+ ID4gKw0KPiA+ICsJaWYgKGludHN0cyA9PSAweDEgJiYgKChzdnNlbiAmIDB4NykgPT0gMHgxKSkN Cj4gPiArCQlzdnNfaW5pdDAxX2lzcl9oYW5kbGVyKHN2cyk7DQo+ID4gKwllbHNlIGlmICgoaW50 c3RzID09IDB4MSkgJiYgKChzdnNlbiAmIDB4NykgPT0gMHg1KSkNCj4gPiArCQlzdnNfaW5pdDAy X2lzcl9oYW5kbGVyKHN2cyk7DQo+ID4gKwllbHNlIGlmICgoaW50c3RzICYgMHgwMGZmMDAwMCkg IT0gMHgwKQ0KPiA+ICsJCXN2c19tb25fbW9kZV9pc3JfaGFuZGxlcihzdnMpOw0KPiA+ICsJZWxz ZQ0KPiA+ICsJCXN2c19lcnJvcl9pc3JfaGFuZGxlcihzdnMpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ ICtzdGF0aWMgaXJxcmV0dXJuX3Qgc3ZzX2lzcihpbnQgaXJxLCB2b2lkICpkYXRhKQ0KPiA+ICt7 DQo+ID4gKwlzdHJ1Y3QgbXRrX3N2cyAqc3ZzID0gKHN0cnVjdCBtdGtfc3ZzICopZGF0YTsNCj4g PiArCWNvbnN0IHN0cnVjdCBzdnNfcGxhdGZvcm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ ICsJc3RydWN0IHN2c19iYW5rICpzdnNiID0gTlVMTDsNCj4gPiArCXVuc2lnbmVkIGxvbmcgZmxh Z3M7DQo+ID4gKwl1MzIgaWR4Ow0KPiA+ICsNCj4gPiArCWZsYWdzID0gY2xhaW1fbXRrX3N2c19s b2NrKCk7DQo+ID4gKwlmb3IgKGlkeCA9IDA7IGlkeCA8IHN2c3AtPmJhbmtfbnVtOyBpZHgrKykg ew0KPiA+ICsJCXN2c2IgPSAmc3ZzcC0+YmFua3NbaWR4XTsNCj4gPiArCQlzdnMtPmJhbmsgPSBz dnNiOw0KPiA+ICsNCj4gPiArCQlpZiAoc3ZzYi0+c3VzcGVuZGVkKQ0KPiA+ICsJCQljb250aW51 ZTsNCj4gPiArCQllbHNlIGlmIChzdnNiLT5pbnRzdCAmIHN2c19yZWFkbChzdnMsIElOVFNUKSkN Cj4gPiArCQkJY29udGludWU7DQo+ID4gKw0KPiA+ICsJCXN2c19pc3JfaGFuZGxlcihzdnMpOw0K PiA+ICsJCWJyZWFrOw0KPiA+ICsJfQ0KPiA+ICsJcmVsZWFzZV9tdGtfc3ZzX2xvY2soZmxhZ3Mp Ow0KPiA+ICsNCj4gPiArCWlmIChzdnNiLT5waGFzZSAhPSBTVlNfUEhBU0VfSU5JVDAxKQ0KPiA+ ICsJCXN2c19zZXRfdm9sdHMoc3ZzYiwgZmFsc2UpOw0KPiA+ICsNCj4gPiArCXJldHVybiBJUlFf SEFORExFRDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgc3ZzX21vbl9tb2RlKHN0 cnVjdCBtdGtfc3ZzICpzdnMpDQo+ID4gK3sNCj4gPiArCWNvbnN0IHN0cnVjdCBzdnNfcGxhdGZv cm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpzdnNiOw0K PiA+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsNCj4gPiArCXUzMiBpZHg7DQo+ID4gKw0KPiA+ICsJ ZmxhZ3MgPSBjbGFpbV9tdGtfc3ZzX2xvY2soKTsNCj4gPiArCWZvciAoaWR4ID0gMDsgaWR4IDwg c3ZzcC0+YmFua19udW07IGlkeCsrKSB7DQo+ID4gKwkJc3ZzYiA9ICZzdnNwLT5iYW5rc1tpZHhd Ow0KPiA+ICsJCXN2cy0+YmFuayA9IHN2c2I7DQo+ID4gKw0KPiA+ICsJCWlmICghc3ZzYi0+bW9u X21vZGVfc3VwcG9ydCkNCj4gPiArCQkJY29udGludWU7DQo+ID4gKw0KPiA+ICsJCXN2c19zZXRf cGhhc2Uoc3ZzLCBTVlNfUEhBU0VfTU9OKTsNCj4gPiArCX0NCj4gPiArCXJlbGVhc2VfbXRrX3N2 c19sb2NrKGZsYWdzKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBzdnNfaW5pdDAy KHN0cnVjdCBtdGtfc3ZzICpzdnMpDQo+ID4gK3sNCj4gPiArCWNvbnN0IHN0cnVjdCBzdnNfcGxh dGZvcm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpzdnNi Ow0KPiA+ICsJdW5zaWduZWQgbG9uZyBmbGFncywgdGltZV9sZWZ0Ow0KPiA+ICsJdTMyIGlkeDsN Cj4gPiArDQo+ID4gKwlmb3IgKGlkeCA9IDA7IGlkeCA8IHN2c3AtPmJhbmtfbnVtOyBpZHgrKykg ew0KPiA+ICsJCXN2c2IgPSAmc3ZzcC0+YmFua3NbaWR4XTsNCj4gPiArCQlzdnMtPmJhbmsgPSBz dnNiOw0KPiA+ICsNCj4gPiArCQlpZiAoIXN2c2ItPmluaXQwMl9zdXBwb3J0KQ0KPiA+ICsJCQlj b250aW51ZTsNCj4gPiArDQo+ID4gKwkJcmVpbml0X2NvbXBsZXRpb24oJnN2c2ItPmluaXRfY29t cGxldGlvbik7DQo+ID4gKwkJZmxhZ3MgPSBjbGFpbV9tdGtfc3ZzX2xvY2soKTsNCj4gPiArCQlz dnNfc2V0X3BoYXNlKHN2cywgU1ZTX1BIQVNFX0lOSVQwMik7DQo+ID4gKwkJcmVsZWFzZV9tdGtf c3ZzX2xvY2soZmxhZ3MpOw0KPiA+ICsJCXRpbWVfbGVmdCA9DQo+ID4gKwkJCXdhaXRfZm9yX2Nv bXBsZXRpb25fdGltZW91dCgmc3ZzYi0+aW5pdF9jb21wbGV0aW9uLA0KPiA+ICsJCQkJCQkgICAg bXNlY3NfdG9famlmZmllcygyMDAwKSk7DQo+ID4gKwkJaWYgKHRpbWVfbGVmdCA9PSAwKSB7DQo+ ID4gKwkJCXByX2VycigiJXM6IGluaXQwMiBjb21wbGV0aW9uIHRpbWVvdXRcbiIsIHN2c2ItPm5h bWUpOw0KPiA+ICsJCQlyZXR1cm4gLUVCVVNZOw0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+ ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBzdnNfaW5pdDAx KHN0cnVjdCBtdGtfc3ZzICpzdnMpDQo+ID4gK3sNCj4gPiArCWNvbnN0IHN0cnVjdCBzdnNfcGxh dGZvcm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpzdnNi Ow0KPiA+ICsJc3RydWN0IHBtX3Fvc19yZXF1ZXN0IHFvc19yZXF1ZXN0ID0geyB7MH0gfTsNCj4g PiArCXVuc2lnbmVkIGxvbmcgZmxhZ3MsIHRpbWVfbGVmdDsNCj4gPiArCWJvb2wgc2VhcmNoX2Rv bmU7DQo+ID4gKwlpbnQgcmV0ID0gLUVJTlZBTDsNCj4gPiArCXUzMiBvcHBfZnJlcXMsIG9wcF92 Ym9vdCwgYnVja192b2x0LCBpZHgsIGk7DQo+ID4gKw0KPiA+ICsJLyogTGV0IENQVXMgbGVhdmUg aWRsZS1vZmYgc3RhdGUgZm9yIGluaXRpYWxpemluZyBzdnNfaW5pdDAxLiAqLw0KPiA+ICsJcG1f cW9zX2FkZF9yZXF1ZXN0KCZxb3NfcmVxdWVzdCwgUE1fUU9TX0NQVV9ETUFfTEFURU5DWSwgMCk7 DQo+ID4gKw0KPiA+ICsJLyogU29tZXRpbWVzIHR3byBzdnNfYmFuayB1c2UgdGhlIHNhbWUgYnVj ay4NCj4gPiArCSAqIFRoZXJlZm9yZSwgd2Ugc2V0IGVhY2ggc3ZzX2JhbmsgdG8gdmJvb3Qgdm9s dGFnZSBmaXJzdC4NCj4gPiArCSAqLw0KPiA+ICsJZm9yIChpZHggPSAwOyBpZHggPCBzdnNwLT5i YW5rX251bTsgaWR4KyspIHsNCj4gPiArCQlzdnNiID0gJnN2c3AtPmJhbmtzW2lkeF07DQo+ID4g KwkJc2VhcmNoX2RvbmUgPSBmYWxzZTsNCj4gPiArDQo+ID4gKwkJaWYgKCFzdnNiLT5pbml0MDFf c3VwcG9ydCkNCj4gPiArCQkJY29udGludWU7DQo+ID4gKw0KPiA+ICsJCXJldCA9IHJlZ3VsYXRv cl9zZXRfbW9kZShzdnNiLT5idWNrLCBSRUdVTEFUT1JfTU9ERV9GQVNUKTsNCj4gPiArCQlpZiAo cmV0KQ0KPiA+ICsJCQlwcl9ub3RpY2UoIiVzOiBmYWlsIHRvIHNldCBmYXN0IG1vZGU6ICVkXG4i LA0KPiA+ICsJCQkJICBzdnNiLT5uYW1lLCByZXQpOw0KPiA+ICsNCj4gPiArCQlpZiAoc3ZzYi0+ bXRjbW9zX3JlcXVlc3QpIHsNCj4gPiArCQkJcmV0ID0gcmVndWxhdG9yX2VuYWJsZShzdnNiLT5i dWNrKTsNCj4gPiArCQkJaWYgKHJldCkgew0KPiA+ICsJCQkJcHJfZXJyKCIlczogZmFpbCB0byBl bmFibGUgJXMgcG93ZXI6ICVkXG4iLA0KPiA+ICsJCQkJICAgICAgIHN2c2ItPm5hbWUsIHN2c2It PmJ1Y2tfbmFtZSwgcmV0KTsNCj4gPiArCQkJCWdvdG8gaW5pdDAxX2ZpbmlzaDsNCj4gPiArCQkJ fQ0KPiA+ICsNCj4gPiArCQkJcmV0ID0gZGV2X3BtX2RvbWFpbl9hdHRhY2goc3ZzYi0+ZGV2LCBm YWxzZSk7DQo+ID4gKwkJCWlmIChyZXQpIHsNCj4gPiArCQkJCXByX2VycigiJXM6IGF0dGFjaCBw bSBkb21haW4gZmFpbDogJWRcbiIsDQo+ID4gKwkJCQkgICAgICAgc3ZzYi0+bmFtZSwgcmV0KTsN Cj4gPiArCQkJCWdvdG8gaW5pdDAxX2ZpbmlzaDsNCj4gPiArCQkJfQ0KPiA+ICsNCj4gPiArCQkJ cG1fcnVudGltZV9lbmFibGUoc3ZzYi0+ZGV2KTsNCj4gPiArCQkJcmV0ID0gcG1fcnVudGltZV9n ZXRfc3luYyhzdnNiLT5kZXYpOw0KPiA+ICsJCQlpZiAocmV0IDwgMCkgew0KPiA+ICsJCQkJcHJf ZXJyKCIlczogdHVybiBtdGNtb3Mgb24gZmFpbDogJWRcbiIsDQo+ID4gKwkJCQkgICAgICAgc3Zz Yi0+bmFtZSwgcmV0KTsNCj4gPiArCQkJCWdvdG8gaW5pdDAxX2ZpbmlzaDsNCj4gPiArCQkJfQ0K PiA+ICsJCX0NCj4gPiArDQo+ID4gKwkJLyogRmluZCB0aGUgZmFzdGVzdCBmcmVxIHRoYXQgY2Fu IGJlIHJ1biBhdCB2Ym9vdCBhbmQNCj4gPiArCQkgKiBmaXggdG8gdGhhdCBmcmVxIHVudGlsIHN2 c19pbml0MDEgaXMgZG9uZS4NCj4gPiArCQkgKi8NCj4gPiArCQlvcHBfdmJvb3QgPSBzdnNfdm9s dF90b19vcHBfdm9sdChzdnNiLT52Ym9vdCwNCj4gPiArCQkJCQkJIHN2c2ItPnZvbHRfc3RlcCwN Cj4gPiArCQkJCQkJIHN2c2ItPnZvbHRfYmFzZSk7DQo+ID4gKw0KPiA+ICsJCWZvciAoaSA9IDA7 IGkgPCBzdnNiLT5vcHBfY291bnQ7IGkrKykgew0KPiA+ICsJCQlvcHBfZnJlcXMgPSBzdnNiLT5v cHBfZnJlcXNbaV07DQo+ID4gKwkJCWlmICghc2VhcmNoX2RvbmUgJiYgc3ZzYi0+b3BwX3ZvbHRz W2ldIDw9IG9wcF92Ym9vdCkgew0KPiA+ICsJCQkJcmV0ID0gZGV2X3BtX29wcF9hZGp1c3Rfdm9s dGFnZShzdnNiLT5kZXYsDQo+ID4gKwkJCQkJCQkJb3BwX2ZyZXFzLA0KPiA+ICsJCQkJCQkJCW9w cF92Ym9vdCk7DQo+ID4gKwkJCQlpZiAocmV0KSB7DQo+ID4gKwkJCQkJcHJfZXJyKCIlczogc2V0 IHZvbHRhZ2UgZmFpbGVkOiAlZFxuIiwNCj4gPiArCQkJCQkgICAgICAgc3ZzYi0+bmFtZSwgcmV0 KTsNCj4gPiArCQkJCQlnb3RvIGluaXQwMV9maW5pc2g7DQo+ID4gKwkJCQl9DQo+ID4gKw0KPiA+ ICsJCQkJc2VhcmNoX2RvbmUgPSB0cnVlOw0KPiA+ICsJCQl9IGVsc2Ugew0KPiA+ICsJCQkJZGV2 X3BtX29wcF9kaXNhYmxlKHN2c2ItPmRldiwNCj4gPiArCQkJCQkJICAgc3ZzYi0+b3BwX2ZyZXFz W2ldKTsNCj4gPiArCQkJfQ0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+ID4gKwlmb3IgKGlk eCA9IDA7IGlkeCA8IHN2c3AtPmJhbmtfbnVtOyBpZHgrKykgew0KPiA+ICsJCXN2c2IgPSAmc3Zz cC0+YmFua3NbaWR4XTsNCj4gPiArCQlzdnMtPmJhbmsgPSBzdnNiOw0KPiA+ICsNCj4gPiArCQlp ZiAoIXN2c2ItPmluaXQwMV9zdXBwb3J0KQ0KPiA+ICsJCQljb250aW51ZTsNCj4gPiArDQo+ID4g KwkJb3BwX3Zib290ID0gc3ZzX3ZvbHRfdG9fb3BwX3ZvbHQoc3ZzYi0+dmJvb3QsDQo+ID4gKwkJ CQkJCSBzdnNiLT52b2x0X3N0ZXAsDQo+ID4gKwkJCQkJCSBzdnNiLT52b2x0X2Jhc2UpOw0KPiA+ ICsNCj4gPiArCQlidWNrX3ZvbHQgPSByZWd1bGF0b3JfZ2V0X3ZvbHRhZ2Uoc3ZzYi0+YnVjayk7 DQo+ID4gKwkJaWYgKGJ1Y2tfdm9sdCAhPSBvcHBfdmJvb3QpIHsNCj4gPiArCQkJcHJfZXJyKCIl czogYnVjayB2b2x0YWdlOiAldSwgZXhwZWN0ZWQgdmJvb3Q6ICV1XG4iLA0KPiA+ICsJCQkgICAg ICAgc3ZzYi0+bmFtZSwgYnVja192b2x0LCBvcHBfdmJvb3QpOw0KPiA+ICsJCQlyZXQgPSAtRVBF Uk07DQo+ID4gKwkJCWdvdG8gaW5pdDAxX2ZpbmlzaDsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJ CWluaXRfY29tcGxldGlvbigmc3ZzYi0+aW5pdF9jb21wbGV0aW9uKTsNCj4gPiArCQlmbGFncyA9 IGNsYWltX210a19zdnNfbG9jaygpOw0KPiA+ICsJCXN2c19zZXRfcGhhc2Uoc3ZzLCBTVlNfUEhB U0VfSU5JVDAxKTsNCj4gPiArCQlyZWxlYXNlX210a19zdnNfbG9jayhmbGFncyk7DQo+ID4gKwkJ dGltZV9sZWZ0ID0NCj4gPiArCQkJd2FpdF9mb3JfY29tcGxldGlvbl90aW1lb3V0KCZzdnNiLT5p bml0X2NvbXBsZXRpb24sDQo+ID4gKwkJCQkJCSAgICBtc2Vjc190b19qaWZmaWVzKDIwMDApKTsN Cj4gPiArCQlpZiAodGltZV9sZWZ0ID09IDApIHsNCj4gPiArCQkJcHJfZXJyKCIlczogaW5pdDAx IGNvbXBsZXRpb24gdGltZW91dFxuIiwgc3ZzYi0+bmFtZSk7DQo+ID4gKwkJCXJldCA9IC1FQlVT WTsNCj4gPiArCQkJZ290byBpbml0MDFfZmluaXNoOw0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiAr DQo+ID4gK2luaXQwMV9maW5pc2g6DQo+ID4gKwlmb3IgKGlkeCA9IDA7IGlkeCA8IHN2c3AtPmJh bmtfbnVtOyBpZHgrKykgew0KPiA+ICsJCXN2c2IgPSAmc3ZzcC0+YmFua3NbaWR4XTsNCj4gPiAr DQo+ID4gKwkJaWYgKCFzdnNiLT5pbml0MDFfc3VwcG9ydCkNCj4gPiArCQkJY29udGludWU7DQo+ ID4gKw0KPiA+ICsJCWZvciAoaSA9IDA7IGkgPCBzdnNiLT5vcHBfY291bnQ7IGkrKykNCj4gPiAr CQkJZGV2X3BtX29wcF9lbmFibGUoc3ZzYi0+ZGV2LCBzdnNiLT5vcHBfZnJlcXNbaV0pOw0KPiA+ ICsNCj4gPiArCQlpZiAocmVndWxhdG9yX3NldF9tb2RlKHN2c2ItPmJ1Y2ssIFJFR1VMQVRPUl9N T0RFX05PUk1BTCkpDQo+ID4gKwkJCXByX25vdGljZSgiJXM6IGZhaWwgdG8gc2V0IG5vcm1hbCBt b2RlOiAlZFxuIiwNCj4gPiArCQkJCSAgc3ZzYi0+bmFtZSwgcmV0KTsNCj4gPiArDQo+ID4gKwkJ aWYgKHN2c2ItPm10Y21vc19yZXF1ZXN0KSB7DQo+ID4gKwkJCWlmIChwbV9ydW50aW1lX3B1dF9z eW5jKHN2c2ItPmRldikpDQo+ID4gKwkJCQlwcl9lcnIoIiVzOiB0dXJuIG10Y21vcyBvZmYgZmFp bDogJWRcbiIsDQo+ID4gKwkJCQkgICAgICAgc3ZzYi0+bmFtZSwgcmV0KTsNCj4gPiArCQkJcG1f cnVudGltZV9kaXNhYmxlKHN2c2ItPmRldik7DQo+ID4gKwkJCWRldl9wbV9kb21haW5fZGV0YWNo KHN2c2ItPmRldiwgMCk7DQo+ID4gKwkJCWlmIChyZWd1bGF0b3JfZGlzYWJsZShzdnNiLT5idWNr KSkNCj4gPiArCQkJCXByX2VycigiJXM6IGZhaWwgdG8gZGlzYWJsZSAlcyBwb3dlcjogJWRcbiIs DQo+ID4gKwkJCQkgICAgICAgc3ZzYi0+bmFtZSwgc3ZzYi0+YnVja19uYW1lLCByZXQpOw0KPiA+ ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+ID4gKwlwbV9xb3NfcmVtb3ZlX3JlcXVlc3QoJnFvc19y ZXF1ZXN0KTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz dGF0aWMgaW50IHN2c19zdGFydChzdHJ1Y3QgbXRrX3N2cyAqc3ZzKQ0KPiA+ICt7DQo+ID4gKwlp bnQgcmV0Ow0KPiA+ICsNCj4gPiArCXJldCA9IHN2c19pbml0MDEoc3ZzKTsNCj4gPiArCWlmIChy ZXQpDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSBzdnNfaW5pdDAyKHN2 cyk7DQo+ID4gKwlpZiAocmV0KQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsJc3Zz X21vbl9tb2RlKHN2cyk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsN Cj4gPiArc3RhdGljIGludCBzdnNfbXQ4MTgzX2VmdXNlX3BhcnNpbmcoc3RydWN0IG10a19zdnMg KnN2cykNCj4gPiArew0KPiA+ICsJY29uc3Qgc3RydWN0IHN2c19wbGF0Zm9ybSAqc3ZzcCA9IHN2 cy0+cGxhdGZvcm07DQo+ID4gKwlzdHJ1Y3QgdGhlcm1hbF9wYXJhbWV0ZXIgdHA7DQo+ID4gKwlz dHJ1Y3Qgc3ZzX2JhbmsgKnN2c2I7DQo+ID4gKwlib29sIG1vbl9tb2RlX3N1cHBvcnQgPSB0cnVl Ow0KPiA+ICsJaW50IGZvcm1hdFs2XSwgeF9yb29tdFs2XSwgdGJfcm9vbXQ7DQo+ID4gKwl1MzIg aWR4LCBpLCBmdF9wZ20sIG10cywgdGVtcDAsIHRlbXAxLCB0ZW1wMjsNCj4gPiArDQo+ID4gKwlp ZiAoc3ZzcC0+ZmFrZV9lZnVzZSkgew0KPiA+ICsJCXByX25vdGljZSgiZmFrZSBlZnVzZVxuIik7 DQo+ID4gKwkJc3ZzLT5lZnVzZVswXSA9IDB4MDAzMTAwODA7DQo+ID4gKwkJc3ZzLT5lZnVzZVsx XSA9IDB4YWJmYmY3NTc7DQo+ID4gKwkJc3ZzLT5lZnVzZVsyXSA9IDB4NDdjNzQ3Yzc7DQo+ID4g KwkJc3ZzLT5lZnVzZVszXSA9IDB4YWJmYmY3NTc7DQo+ID4gKwkJc3ZzLT5lZnVzZVs0XSA9IDB4 ZTdmY2EwZWM7DQo+ID4gKwkJc3ZzLT5lZnVzZVs1XSA9IDB4NDdiZjRiODg7DQo+ID4gKwkJc3Zz LT5lZnVzZVs2XSA9IDB4YWJmYjhmYTU7DQo+ID4gKwkJc3ZzLT5lZnVzZVs3XSA9IDB4YWJmYjIx N2I7DQo+ID4gKwkJc3ZzLT5lZnVzZVs4XSA9IDB4NGJmMzRiZTE7DQo+ID4gKwkJc3ZzLT5lZnVz ZVs5XSA9IDB4YWJmYjY3MGQ7DQo+ID4gKwkJc3ZzLT5lZnVzZVsxNl0gPSAweGFiZmJjNjUzOw0K PiA+ICsJCXN2cy0+ZWZ1c2VbMTddID0gMHg0N2YzNDdlMTsNCj4gPiArCQlzdnMtPmVmdXNlWzE4 XSA9IDB4YWJmYmQ4NDg7DQo+ID4gKw0KPiA+ICsJCXN2cy0+dGhlcm1hbF9lZnVzZVswXSA9IDB4 MDI4NzNmNjk7DQo+ID4gKwkJc3ZzLT50aGVybWFsX2VmdXNlWzFdID0gMHhhMTFkOTE0MjsNCj4g PiArCQlzdnMtPnRoZXJtYWxfZWZ1c2VbMl0gPSAweGEyNTI2OTAwOw0KPiA+ICsJfQ0KPiA+ICsN Cj4gPiArCS8qIHN2cyBlZnVzZSBwYXJzaW5nICovDQo+ID4gKwlmdF9wZ20gPSAoc3ZzLT5lZnVz ZVswXSA+PiA0KSAmIDB4ZjsNCj4gPiArDQo+ID4gKwlmb3IgKGlkeCA9IDA7IGlkeCA8IHN2c3At PmJhbmtfbnVtOyBpZHgrKykgew0KPiA+ICsJCXN2c2IgPSAmc3ZzcC0+YmFua3NbaWR4XTsNCj4g PiArCQlpZiAoZnRfcGdtIDw9IDEpDQo+ID4gKwkJCXN2c2ItPmluaXQwMV92b2x0X2ZsYWcgPSBT VlNfSU5JVDAxX1ZPTFRfSUdOT1JFOw0KPiA+ICsNCj4gPiArCQlzd2l0Y2ggKHN2c2ItPnN3X2lk KSB7DQo+ID4gKwkJY2FzZSBTVlNfQ1BVX0xJVFRMRToNCj4gPiArCQkJc3ZzYi0+YmRlcyA9IHN2 cy0+ZWZ1c2VbMTZdICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+bWRlcyA9IChzdnMtPmVmdXNlWzE2 XSA+PiA4KSAmIDB4ZmY7DQo+ID4gKwkJCXN2c2ItPmRjYmRldCA9IChzdnMtPmVmdXNlWzE2XSA+ PiAxNikgJiAweGZmOw0KPiA+ICsJCQlzdnNiLT5kY21kZXQgPSAoc3ZzLT5lZnVzZVsxNl0gPj4g MjQpICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+bXRkZXMgID0gKHN2cy0+ZWZ1c2VbMTddID4+IDE2 KSAmIDB4ZmY7DQo+ID4gKw0KPiA+ICsJCQlpZiAoZnRfcGdtIDw9IDMpDQo+ID4gKwkJCQlzdnNi LT52b2x0X29mZnNldCArPSAxMDsNCj4gPiArCQkJZWxzZQ0KPiA+ICsJCQkJc3ZzYi0+dm9sdF9v ZmZzZXQgKz0gMjsNCj4gPiArCQkJYnJlYWs7DQo+ID4gKwkJY2FzZSBTVlNfQ1BVX0JJRzoNCj4g PiArCQkJc3ZzYi0+YmRlcyA9IHN2cy0+ZWZ1c2VbMThdICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+ bWRlcyA9IChzdnMtPmVmdXNlWzE4XSA+PiA4KSAmIDB4ZmY7DQo+ID4gKwkJCXN2c2ItPmRjYmRl dCA9IChzdnMtPmVmdXNlWzE4XSA+PiAxNikgJiAweGZmOw0KPiA+ICsJCQlzdnNiLT5kY21kZXQg PSAoc3ZzLT5lZnVzZVsxOF0gPj4gMjQpICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+bXRkZXMgID0g c3ZzLT5lZnVzZVsxN10gJiAweGZmOw0KPiA+ICsNCj4gPiArCQkJaWYgKGZ0X3BnbSA8PSAzKQ0K PiA+ICsJCQkJc3ZzYi0+dm9sdF9vZmZzZXQgKz0gMTU7DQo+ID4gKwkJCWVsc2UNCj4gPiArCQkJ CXN2c2ItPnZvbHRfb2Zmc2V0ICs9IDEyOw0KPiA+ICsJCQlicmVhazsNCj4gPiArCQljYXNlIFNW U19DQ0k6DQo+ID4gKwkJCXN2c2ItPmJkZXMgPSBzdnMtPmVmdXNlWzRdICYgMHhmZjsNCj4gPiAr CQkJc3ZzYi0+bWRlcyA9IChzdnMtPmVmdXNlWzRdID4+IDgpICYgMHhmZjsNCj4gPiArCQkJc3Zz Yi0+ZGNiZGV0ID0gKHN2cy0+ZWZ1c2VbNF0gPj4gMTYpICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+ ZGNtZGV0ID0gKHN2cy0+ZWZ1c2VbNF0gPj4gMjQpICYgMHhmZjsNCj4gPiArCQkJc3ZzYi0+bXRk ZXMgID0gKHN2cy0+ZWZ1c2VbNV0gPj4gMTYpICYgMHhmZjsNCj4gPiArDQo+ID4gKwkJCWlmIChm dF9wZ20gPD0gMykNCj4gPiArCQkJCXN2c2ItPnZvbHRfb2Zmc2V0ICs9IDEwOw0KPiA+ICsJCQll bHNlDQo+ID4gKwkJCQlzdnNiLT52b2x0X29mZnNldCArPSAyOw0KPiA+ICsJCQlicmVhazsNCj4g PiArCQljYXNlIFNWU19HUFU6DQo+ID4gKwkJCXN2c2ItPmJkZXMgPSBzdnMtPmVmdXNlWzZdICYg MHhmZjsNCj4gPiArCQkJc3ZzYi0+bWRlcyA9IChzdnMtPmVmdXNlWzZdID4+IDgpICYgMHhmZjsN Cj4gPiArCQkJc3ZzYi0+ZGNiZGV0ID0gKHN2cy0+ZWZ1c2VbNl0gPj4gMTYpICYgMHhmZjsNCj4g PiArCQkJc3ZzYi0+ZGNtZGV0ID0gKHN2cy0+ZWZ1c2VbNl0gPj4gMjQpICYgMHhmZjsNCj4gPiAr CQkJc3ZzYi0+bXRkZXMgID0gc3ZzLT5lZnVzZVs1XSAmIDB4ZmY7DQo+ID4gKw0KPiA+ICsJCQlp ZiAoZnRfcGdtID49IDIpIHsNCj4gPiArCQkJCXN2c2ItPmZyZXFfYmFzZSA9IDgwMDAwMDAwMDsg LyogODAwTUh6ICovDQo+ID4gKwkJCQlzdnNiLT5kdnRfZml4ZWQgPSAyOw0KPiA+ICsJCQl9DQo+ ID4gKwkJCWJyZWFrOw0KPiA+ICsJCWRlZmF1bHQ6DQo+ID4gKwkJCWJyZWFrOw0KPiA+ICsJCX0N Cj4gPiArCX0NCj4gPiArDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgc3ZzcC0+ZWZ1c2VfbnVtOyBp KyspIHsNCj4gPiArCQlpZiAoc3ZzLT5lZnVzZVtpXSkNCj4gPiArCQkJcHJfbm90aWNlKCJNX0hX X1JFUyVkOiAweCUwOHhcbiIsIGksIHN2cy0+ZWZ1c2VbaV0pOw0KPiA+ICsJfQ0KPiA+ICsNCj4g PiArCS8qIHRoZXJtYWwgZWZ1c2UgcGFyc2luZyAqLw0KPiA+ICsJaWYgKCFzdnMtPnRoZXJtYWxf ZWZ1c2UpDQo+ID4gKwkJcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICsJdHAuYWRjX2dlX3QgPSAoc3Zz LT50aGVybWFsX2VmdXNlWzFdID4+IDIyKSAmIDB4M2ZmOw0KPiA+ICsJdHAuYWRjX29lX3QgPSAo c3ZzLT50aGVybWFsX2VmdXNlWzFdID4+IDEyKSAmIDB4M2ZmOw0KPiA+ICsNCj4gPiArCXRwLm9f dnRzbWN1MSA9IChzdnMtPnRoZXJtYWxfZWZ1c2VbMF0gPj4gMTcpICYgMHgxZmY7DQo+ID4gKwl0 cC5vX3Z0c21jdTIgPSAoc3ZzLT50aGVybWFsX2VmdXNlWzBdID4+IDgpICYgMHgxZmY7DQo+ID4g Kwl0cC5vX3Z0c21jdTMgPSBzdnMtPnRoZXJtYWxfZWZ1c2VbMV0gJiAweDFmZjsNCj4gPiArCXRw Lm9fdnRzbWN1NCA9IChzdnMtPnRoZXJtYWxfZWZ1c2VbMl0gPj4gMjMpICYgMHgxZmY7DQo+ID4g Kwl0cC5vX3Z0c21jdTUgPSAoc3ZzLT50aGVybWFsX2VmdXNlWzJdID4+IDUpICYgMHgxZmY7DQo+ ID4gKwl0cC5vX3Z0c2FiYiA9IChzdnMtPnRoZXJtYWxfZWZ1c2VbMl0gPj4gMTQpICYgMHgxZmY7 DQo+ID4gKw0KPiA+ICsJdHAuZGVnY19jYWxpID0gKHN2cy0+dGhlcm1hbF9lZnVzZVswXSA+PiAx KSAmIDB4M2Y7DQo+ID4gKwl0cC5hZGNfY2FsaV9lbl90ID0gc3ZzLT50aGVybWFsX2VmdXNlWzBd ICYgQklUKDApOw0KPiA+ICsJdHAub19zbG9wZV9zaWduID0gKHN2cy0+dGhlcm1hbF9lZnVzZVsw XSA+PiA3KSAmIEJJVCgwKTsNCj4gPiArDQo+ID4gKwl0cC50c19pZCA9IChzdnMtPnRoZXJtYWxf ZWZ1c2VbMV0gPj4gOSkgJiBCSVQoMCk7DQo+ID4gKwl0cC5vX3Nsb3BlID0gKHN2cy0+dGhlcm1h bF9lZnVzZVswXSA+PiAyNikgJiAweDNmOw0KPiA+ICsNCj4gPiArCWlmICh0cC5hZGNfY2FsaV9l bl90ID09IDEpIHsNCj4gPiArCQlpZiAodHAudHNfaWQgPT0gMCkNCj4gPiArCQkJdHAub19zbG9w ZSA9IDA7DQo+ID4gKw0KPiA+ICsJCWlmICgodHAuYWRjX2dlX3QgPCAyNjUgfHwgdHAuYWRjX2dl X3QgPiA3NTgpIHx8DQo+ID4gKwkJICAgICh0cC5hZGNfb2VfdCA8IDI2NSB8fCB0cC5hZGNfb2Vf dCA+IDc1OCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzbWN1MSA8IC04IHx8IHRwLm9fdnRzbWN1 MSA+IDQ4NCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzbWN1MiA8IC04IHx8IHRwLm9fdnRzbWN1 MiA+IDQ4NCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzbWN1MyA8IC04IHx8IHRwLm9fdnRzbWN1 MyA+IDQ4NCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzbWN1NCA8IC04IHx8IHRwLm9fdnRzbWN1 NCA+IDQ4NCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzbWN1NSA8IC04IHx8IHRwLm9fdnRzbWN1 NSA+IDQ4NCkgfHwNCj4gPiArCQkgICAgKHRwLm9fdnRzYWJiIDwgLTggfHwgdHAub192dHNhYmIg PiA0ODQpIHx8DQo+ID4gKwkJICAgICh0cC5kZWdjX2NhbGkgPCAxIHx8IHRwLmRlZ2NfY2FsaSA+ IDYzKSkgew0KPiA+ICsJCQlwcl9lcnIoImJhZCB0aGVybWFsIGVmdXNlIGRhdGEuIGRpc2FibGUg bW9uIG1vZGVcbiIpOw0KPiA+ICsJCQltb25fbW9kZV9zdXBwb3J0ID0gZmFsc2U7DQo+ID4gKwkJ fQ0KPiA+ICsJfSBlbHNlIHsNCj4gPiArCQlwcl9lcnIoIm5vIHRoZXJtYWwgZWZ1c2UgZGF0YS4g ZGlzYWJsZSBtb24gbW9kZVxuIik7DQo+ID4gKwkJbW9uX21vZGVfc3VwcG9ydCA9IGZhbHNlOw0K PiA+ICsJfQ0KPiA+ICsNCj4gPiArCWlmICghbW9uX21vZGVfc3VwcG9ydCkgew0KPiA+ICsJCWZv ciAoaSA9IDA7IGkgPCBzdnNwLT50aGVybWFsX2VmdXNlX251bTsgaSsrKQ0KPiA+ICsJCQlwcl9l cnIoInRoZXJtYWxfZWZ1c2VbJXVdID0gMHglMDh4XG4iLA0KPiA+ICsJCQkgICAgICAgaSwgc3Zz LT50aGVybWFsX2VmdXNlW2ldKTsNCj4gPiArDQo+ID4gKwkJZm9yIChpZHggPSAwOyBpZHggPCBz dnNwLT5iYW5rX251bTsgaWR4KyspIHsNCj4gPiArCQkJc3ZzYiA9ICZzdnNwLT5iYW5rc1tpZHhd Ow0KPiA+ICsJCQlzdnNiLT5tb25fbW9kZV9zdXBwb3J0ID0gZmFsc2U7DQo+ID4gKwkJfQ0KPiA+ ICsNCj4gPiArCQlyZXR1cm4gMDsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwl0cC5nZSA9ICgodHAu YWRjX2dlX3QgLSA1MTIpICogMTAwMDApIC8gNDA5NjsNCj4gPiArCXRwLm9lID0gKHRwLmFkY19v ZV90IC0gNTEyKTsNCj4gPiArCXRwLmdhaW4gPSAoMTAwMDAgKyB0cC5nZSk7DQo+ID4gKw0KPiA+ ICsJZm9ybWF0WzBdID0gKHRwLm9fdnRzbWN1MSArIDMzNTAgLSB0cC5vZSk7DQo+ID4gKwlmb3Jt YXRbMV0gPSAodHAub192dHNtY3UyICsgMzM1MCAtIHRwLm9lKTsNCj4gPiArCWZvcm1hdFsyXSA9 ICh0cC5vX3Z0c21jdTMgKyAzMzUwIC0gdHAub2UpOw0KPiA+ICsJZm9ybWF0WzNdID0gKHRwLm9f dnRzbWN1NCArIDMzNTAgLSB0cC5vZSk7DQo+ID4gKwlmb3JtYXRbNF0gPSAodHAub192dHNtY3U1 ICsgMzM1MCAtIHRwLm9lKTsNCj4gPiArCWZvcm1hdFs1XSA9ICh0cC5vX3Z0c2FiYiArIDMzNTAg LSB0cC5vZSk7DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsgaSA8IDY7IGkrKykNCj4gPiArCQl4 X3Jvb210W2ldID0gKCgoZm9ybWF0W2ldICogMTAwMDApIC8gNDA5NikgKiAxMDAwMCkgLyB0cC5n YWluOw0KPiA+ICsNCj4gPiArCXRlbXAwID0gKDEwMDAwICogMTAwMDAwIC8gdHAuZ2FpbikgKiAx NSAvIDE4Ow0KPiA+ICsNCj4gPiArCWlmICh0cC5vX3Nsb3BlX3NpZ24gPT0gMCkNCj4gPiArCQlt dHMgPSAodGVtcDAgKiAxMCkgLyAoMTUzNCArIHRwLm9fc2xvcGUgKiAxMCk7DQo+ID4gKwllbHNl DQo+ID4gKwkJbXRzID0gKHRlbXAwICogMTApIC8gKDE1MzQgLSB0cC5vX3Nsb3BlICogMTApOw0K PiA+ICsNCj4gPiArCWZvciAoaWR4ID0gMDsgaWR4IDwgc3ZzcC0+YmFua19udW07IGlkeCsrKSB7 DQo+ID4gKwkJc3ZzYiA9ICZzdnNwLT5iYW5rc1tpZHhdOw0KPiA+ICsJCXN2c2ItPm10cyA9IG10 czsNCj4gPiArDQo+ID4gKwkJc3dpdGNoIChzdnNiLT5zd19pZCkgew0KPiA+ICsJCWNhc2UgU1ZT X0NQVV9MSVRUTEU6DQo+ID4gKwkJCXRiX3Jvb210ID0geF9yb29tdFszXTsNCj4gPiArCQkJYnJl YWs7DQo+ID4gKwkJY2FzZSBTVlNfQ1BVX0JJRzoNCj4gPiArCQkJdGJfcm9vbXQgPSB4X3Jvb210 WzRdOw0KPiA+ICsJCQlicmVhazsNCj4gPiArCQljYXNlIFNWU19DQ0k6DQo+ID4gKwkJCXRiX3Jv b210ID0geF9yb29tdFszXTsNCj4gPiArCQkJYnJlYWs7DQo+ID4gKwkJY2FzZSBTVlNfR1BVOg0K PiA+ICsJCQl0Yl9yb29tdCA9IHhfcm9vbXRbMV07DQo+ID4gKwkJCWJyZWFrOw0KPiA+ICsJCWRl ZmF1bHQ6DQo+ID4gKwkJCXByX2VycigidW5rbm93biBzdnNiX2lkID0gJXU/IGRpc2FibGUgc3Zz XG4iLA0KPiA+ICsJCQkgICAgICAgc3ZzYi0+c3dfaWQpOw0KPiA+ICsJCQlyZXR1cm4gLUVJTlZB TDsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCXRlbXAwID0gKHRwLmRlZ2NfY2FsaSAqIDEwIC8g Mik7DQo+ID4gKwkJdGVtcDEgPSAoKDEwMDAwICogMTAwMDAwIC8gNDA5NiAvIHRwLmdhaW4pICoN Cj4gPiArCQkJIHRwLm9lICsgdGJfcm9vbXQgKiAxMCkgKiAxNSAvIDE4Ow0KPiA+ICsNCj4gPiAr CQlpZiAodHAub19zbG9wZV9zaWduID09IDApDQo+ID4gKwkJCXRlbXAyID0gdGVtcDEgKiAxMDAg LyAoMTUzNCArIHRwLm9fc2xvcGUgKiAxMCk7DQo+ID4gKwkJZWxzZQ0KPiA+ICsJCQl0ZW1wMiA9 IHRlbXAxICogMTAwIC8gKDE1MzQgLSB0cC5vX3Nsb3BlICogMTApOw0KPiA+ICsNCj4gPiArCQlz dnNiLT5idHMgPSAodGVtcDAgKyB0ZW1wMiAtIDI1MCkgKiA0IC8gMTA7DQo+ID4gKwl9DQo+ID4g Kw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgc3ZzX2lz X3N1cHBvcnQoc3RydWN0IG10a19zdnMgKnN2cykNCj4gDQo+IG5pdDogdGhpcyBhcHBlYXJzIHRv IGJlIGEgY2hlY2sgaWYgdGhlIHBsYXRmb3JtIHN1cHBvcnRzIFNWUy4gIElmIHNvLA0KPiB0aGVu IGl0IHNob3VsZCBwcm9iYWJseSBiZSAnYm9vbCcgYW5kIGJlIGNhbGxlZCBzdnNfaXNfc3VwcG9y dGVkKCkuDQoNCmJvb2wvc3ZzX2lzX3N1cHBvcnRlZCBhcmUgZ29vZCBpZGVhcy4gSSdsbCBhcHBs eSBpdCBpbiB0aGUgbmV4dCBwYXRjaC4NClRoYW5rcy4NCg0KPiANCj4gPiArew0KPiA+ICsJY29u c3Qgc3RydWN0IHN2c19wbGF0Zm9ybSAqc3ZzcCA9IHN2cy0+cGxhdGZvcm07DQo+ID4gKwlzdHJ1 Y3Qgc3ZzX2JhbmsgKnN2c2I7DQo+ID4gKwlzdHJ1Y3QgbnZtZW1fY2VsbCAqY2VsbDsNCj4gPiAr CXNpemVfdCBsZW47DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsJdTMyIGlkeCwgaTsNCj4gPiArDQo+ ID4gKwlpZiAoc3ZzcC0+ZmFrZV9lZnVzZSkgew0KPiA+ICsJCWxlbiA9IHN2c3AtPmVmdXNlX251 bSAqIDQ7DQo+ID4gKwkJc3ZzLT5lZnVzZSA9IGt6YWxsb2MobGVuLCBHRlBfS0VSTkVMKTsNCj4g PiArCQlpZiAoIXN2cy0+ZWZ1c2UpDQo+ID4gKwkJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsNCj4g PiArCQlsZW4gPSBzdnNwLT50aGVybWFsX2VmdXNlX251bSAqIDQ7DQo+ID4gKwkJc3ZzLT50aGVy bWFsX2VmdXNlID0ga3phbGxvYyhsZW4sIEdGUF9LRVJORUwpOw0KPiA+ICsJCWlmICghc3ZzLT50 aGVybWFsX2VmdXNlKQ0KPiA+ICsJCQlyZXR1cm4gLUVOT01FTTsNCj4gPiArDQo+ID4gKwkJZ290 byBzdnNwX2VmdXNlX3BhcnNpbmc7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJLyogZ2V0IHN2cyBl ZnVzZSBieSBudm1lbSAqLw0KPiA+ICsJY2VsbCA9IG52bWVtX2NlbGxfZ2V0KHN2cy0+ZGV2LCAi c3ZzLWNhbGlicmF0aW9uLWRhdGEiKTsNCj4gPiArCWlmIChJU19FUlIoY2VsbCkpIHsNCj4gPiAr CQlwcl9lcnIoIm5vIFwic3ZzLWNhbGlicmF0aW9uLWRhdGFcIiBmcm9tIGR0cz8gZGlzYWJsZSBz dnNcbiIpOw0KPiA+ICsJCXJldHVybiBQVFJfRVJSKGNlbGwpOw0KPiA+ICsJfQ0KPiA+ICsNCj4g PiArCXN2cy0+ZWZ1c2UgPSAodTMyICopbnZtZW1fY2VsbF9yZWFkKGNlbGwsICZsZW4pOw0KPiA+ ICsJbnZtZW1fY2VsbF9wdXQoY2VsbCk7DQo+ID4gKw0KPiA+ICsJcmV0ID0gKHN2cy0+ZWZ1c2Vb c3ZzcC0+ZWZ1c2VfY2hlY2tdID09IDApID8gLUVQRVJNIDogMDsNCj4gPiArCWlmIChyZXQpIHsN Cj4gPiArCQlwcl9lcnIoIm5vIHN2cyBlZnVzZS4gZGlzYWJsZSBzdnMuXG4iKTsNCj4gPiArCQlm b3IgKGkgPSAwOyBpIDwgc3ZzcC0+ZWZ1c2VfbnVtOyBpKyspDQo+ID4gKwkJCXByX2VycigiTV9I V19SRVMlZDogMHglMDh4XG4iLCBpLCBzdnMtPmVmdXNlW2ldKTsNCj4gPiArCQlyZXR1cm4gcmV0 Ow0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCS8qIGdldCB0aGVybWFsIGVmdXNlIGJ5IG52bWVtICov DQo+ID4gKwljZWxsID0gbnZtZW1fY2VsbF9nZXQoc3ZzLT5kZXYsICJjYWxpYnJhdGlvbi1kYXRh Iik7DQo+ID4gKwlpZiAoSVNfRVJSKGNlbGwpKSB7DQo+ID4gKwkJcHJfZXJyKCJubyBcImNhbGli cmF0aW9uLWRhdGFcIiBmcm9tIGR0cz8gZGlzYWJsZSBtb24gbW9kZVxuIik7DQo+ID4gKwkJc3Zz LT50aGVybWFsX2VmdXNlID0gTlVMTDsNCj4gPiArCQlmb3IgKGlkeCA9IDA7IGlkeCA8IHN2c3At PmJhbmtfbnVtOyBpZHgrKykgew0KPiA+ICsJCQlzdnNiID0gJnN2c3AtPmJhbmtzW2lkeF07DQo+ ID4gKwkJCXN2c2ItPm1vbl9tb2RlX3N1cHBvcnQgPSBmYWxzZTsNCj4gPiArCQl9DQo+ID4gKwkJ Z290byBzdnNwX2VmdXNlX3BhcnNpbmc7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJc3ZzLT50aGVy bWFsX2VmdXNlID0gKHUzMiAqKW52bWVtX2NlbGxfcmVhZChjZWxsLCAmbGVuKTsNCj4gPiArCW52 bWVtX2NlbGxfcHV0KGNlbGwpOw0KPiA+ICsNCj4gPiArc3ZzcF9lZnVzZV9wYXJzaW5nOg0KPiA+ ICsJcmV0ID0gc3ZzcC0+ZWZ1c2VfcGFyc2luZyhzdnMpOw0KPiA+ICsNCj4gPiArCXJldHVybiBy ZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgc3ZzX3Jlc291cmNlX3NldHVwKHN0 cnVjdCBtdGtfc3ZzICpzdnMpDQo+ID4gK3sNCj4gPiArCWNvbnN0IHN0cnVjdCBzdnNfcGxhdGZv cm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3RydWN0IHN2c19iYW5rICpzdnNiOw0K PiA+ICsJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldjsNCj4gPiArCXN0cnVjdCBkZXZpY2Vf bm9kZSAqbnAgPSBOVUxMOw0KPiA+ICsJc3RydWN0IGRldl9wbV9vcHAgKm9wcDsNCj4gPiArCXVu c2lnbmVkIGxvbmcgZnJlcTsNCj4gPiArCXNpemVfdCBvcHBfc2l6ZTsNCj4gPiArCWludCBjb3Vu dCwgcmV0Ow0KPiA+ICsJdTMyIGlkeCwgaTsNCj4gPiArDQo+ID4gKwlmb3IgKGlkeCA9IDA7IGlk eCA8IHN2c3AtPmJhbmtfbnVtOyBpZHgrKykgew0KPiA+ICsJCXN2c2IgPSAmc3ZzcC0+YmFua3Nb aWR4XTsNCj4gPiArDQo+ID4gKwkJaWYgKCFzdnNiLT5pbml0MDFfc3VwcG9ydCkNCj4gPiArCQkJ Y29udGludWU7DQo+ID4gKw0KPiA+ICsJCXN3aXRjaCAoc3ZzYi0+c3dfaWQpIHsNCj4gPiArCQlj YXNlIFNWU19DUFVfTElUVExFOg0KPiA+ICsJCQlzdnNiLT5uYW1lID0gIlNWU19DUFVfTElUVExF IjsNCj4gPiArCQkJYnJlYWs7DQo+ID4gKwkJY2FzZSBTVlNfQ1BVX0JJRzoNCj4gPiArCQkJc3Zz Yi0+bmFtZSA9ICJTVlNfQ1BVX0JJRyI7DQo+ID4gKwkJCWJyZWFrOw0KPiA+ICsJCWNhc2UgU1ZT X0NDSToNCj4gPiArCQkJc3ZzYi0+bmFtZSA9ICJTVlNfQ0NJIjsNCj4gPiArCQkJYnJlYWs7DQo+ ID4gKwkJY2FzZSBTVlNfR1BVOg0KPiA+ICsJCQlzdnNiLT5uYW1lID0gIlNWU19HUFUiOw0KPiA+ ICsJCQlicmVhazsNCj4gPiArCQlkZWZhdWx0Og0KPiA+ICsJCQlXQVJOX09OKDEpOw0KPiA+ICsJ CQlyZXR1cm4gLUVJTlZBTDsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCS8qIEFkZCBzdnNfYmFu ayBkZXZpY2UgZm9yIG9wcC10YWJsZS9tdGNtb3MvYnVjayBjb250cm9sICovDQo+ID4gKwkJcGRl diA9IHBsYXRmb3JtX2RldmljZV9hbGxvYyhzdnNiLT5uYW1lLCAwKTsNCj4gPiArCQlpZiAoIXBk ZXYpIHsNCj4gPiArCQkJcHJfZXJyKCIlczogZmFpbCB0byBhbGxvYyBwZGV2IGZvciBzdnNfYmFu a1xuIiwNCj4gPiArCQkJICAgICAgIHN2c2ItPm5hbWUpOw0KPiA+ICsJCQlyZXR1cm4gLUVOT01F TTsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCWZvcl9lYWNoX2NoaWxkX29mX25vZGUoc3ZzLT5k ZXYtPm9mX25vZGUsIG5wKSB7DQo+ID4gKwkJCWlmIChvZl9kZXZpY2VfaXNfY29tcGF0aWJsZShu cCwgc3ZzYi0+b2ZfY29tcGF0aWJsZSkpIHsNCj4gPiArCQkJCXBkZXYtPmRldi5vZl9ub2RlID0g bnA7DQo+ID4gKwkJCQlicmVhazsNCj4gPiArCQkJfQ0KPiA+ICsJCX0NCj4gPiArDQo+ID4gKwkJ cmV0ID0gcGxhdGZvcm1fZGV2aWNlX2FkZChwZGV2KTsNCj4gPiArCQlpZiAocmV0KSB7DQo+ID4g KwkJCXByX2VycigiJXM6IGZhaWwgdG8gYWRkIHN2c19iYW5rIGRldmljZTogJWRcbiIsDQo+ID4g KwkJCSAgICAgICBzdnNiLT5uYW1lLCByZXQpOw0KPiA+ICsJCQlyZXR1cm4gcmV0Ow0KPiA+ICsJ CX0NCj4gPiArDQo+ID4gKwkJc3ZzYi0+ZGV2ID0gJnBkZXYtPmRldjsNCj4gPiArCQlkZXZfc2V0 X2RydmRhdGEoc3ZzYi0+ZGV2LCBzdnMpOw0KPiA+ICsJCXJldCA9IGRldl9wbV9vcHBfb2ZfYWRk X3RhYmxlKHN2c2ItPmRldik7DQo+ID4gKwkJaWYgKHJldCkgew0KPiA+ICsJCQlwcl9lcnIoIiVz OiBmYWlsIHRvIGFkZCBvcHAgdGFibGU6ICVkXG4iLA0KPiA+ICsJCQkgICAgICAgc3ZzYi0+bmFt ZSwgcmV0KTsNCj4gPiArCQkJcmV0dXJuIHJldDsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCW11 dGV4X2luaXQoJnN2c2ItPmxvY2spOw0KPiA+ICsNCj4gPiArCQlzdnNiLT5idWNrID0gZGV2bV9y ZWd1bGF0b3JfZ2V0X29wdGlvbmFsKHN2c2ItPmRldiwNCj4gPiArCQkJCQkJCSBzdnNiLT5idWNr X25hbWUpOw0KPiA+ICsJCWlmIChJU19FUlIoc3ZzYi0+YnVjaykpIHsNCj4gPiArCQkJcHJfZXJy KCIlczogY2Fubm90IGdldCByZWd1bGF0b3IgXCIlcy1zdXBwbHlcIlxuIiwNCj4gPiArCQkJICAg ICAgIHN2c2ItPm5hbWUsIHN2c2ItPmJ1Y2tfbmFtZSk7DQo+ID4gKwkJCXJldHVybiBQVFJfRVJS KHN2c2ItPmJ1Y2spOw0KPiA+ICsJCX0NCj4gPiArDQo+ID4gKwkJY291bnQgPSBkZXZfcG1fb3Bw X2dldF9vcHBfY291bnQoc3ZzYi0+ZGV2KTsNCj4gPiArCQlpZiAoc3ZzYi0+b3BwX2NvdW50ICE9 IGNvdW50KSB7DQo+ID4gKwkJCXByX2VycigiJXM6IG9wcF9jb3VudCBub3QgXCIldVwiIGJ1dCBn ZXQgXCIlZFwiP1xuIiwNCj4gPiArCQkJICAgICAgIHN2c2ItPm5hbWUsIHN2c2ItPm9wcF9jb3Vu dCwgY291bnQpOw0KPiA+ICsJCQlyZXR1cm4gY291bnQ7DQo+ID4gKwkJfQ0KPiA+ICsNCj4gPiAr CQlvcHBfc2l6ZSA9IDQgKiBzdnNiLT5vcHBfY291bnQ7DQo+ID4gKwkJc3ZzYi0+b3BwX3ZvbHRz ID0ga21hbGxvYyhvcHBfc2l6ZSwgR0ZQX0tFUk5FTCk7DQo+ID4gKwkJaWYgKCFzdnNiLT5vcHBf dm9sdHMpDQo+ID4gKwkJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsNCj4gPiArCQlzdnNiLT5pbml0 MDJfdm9sdHMgPSBrbWFsbG9jKG9wcF9zaXplLCBHRlBfS0VSTkVMKTsNCj4gPiArCQlpZiAoIXN2 c2ItPmluaXQwMl92b2x0cykNCj4gPiArCQkJcmV0dXJuIC1FTk9NRU07DQo+ID4gKw0KPiA+ICsJ CXN2c2ItPnZvbHRzID0ga21hbGxvYyhvcHBfc2l6ZSwgR0ZQX0tFUk5FTCk7DQo+ID4gKwkJaWYg KCFzdnNiLT52b2x0cykNCj4gPiArCQkJcmV0dXJuIC1FTk9NRU07DQo+ID4gKw0KPiA+ICsJCXN2 c2ItPm9wcF9mcmVxcyA9IGttYWxsb2Mob3BwX3NpemUsIEdGUF9LRVJORUwpOw0KPiA+ICsJCWlm ICghc3ZzYi0+b3BwX2ZyZXFzKQ0KPiA+ICsJCQlyZXR1cm4gLUVOT01FTTsNCj4gPiArDQo+ID4g KwkJc3ZzYi0+ZnJlcXNfcGN0ID0ga21hbGxvYyhvcHBfc2l6ZSwgR0ZQX0tFUk5FTCk7DQo+ID4g KwkJaWYgKCFzdnNiLT5mcmVxc19wY3QpDQo+ID4gKwkJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsN Cj4gPiArCQlmb3IgKGkgPSAwLCBmcmVxID0gKHUzMiktMTsgaSA8IHN2c2ItPm9wcF9jb3VudDsg aSsrLCBmcmVxLS0pIHsNCj4gPiArCQkJb3BwID0gZGV2X3BtX29wcF9maW5kX2ZyZXFfZmxvb3Io c3ZzYi0+ZGV2LCAmZnJlcSk7DQo+ID4gKwkJCWlmIChJU19FUlIob3BwKSkgew0KPiA+ICsJCQkJ cHJfZXJyKCIlczogZXJyb3Igb3BwIGVudHJ5ISEsIGVyciA9ICVsZFxuIiwNCj4gPiArCQkJCSAg ICAgICBzdnNiLT5uYW1lLCBQVFJfRVJSKG9wcCkpOw0KPiA+ICsJCQkJcmV0dXJuIFBUUl9FUlIo b3BwKTsNCj4gPiArCQkJfQ0KPiA+ICsNCj4gPiArCQkJc3ZzYi0+b3BwX2ZyZXFzW2ldID0gZnJl cTsNCj4gPiArCQkJc3ZzYi0+b3BwX3ZvbHRzW2ldID0gZGV2X3BtX29wcF9nZXRfdm9sdGFnZShv cHApOw0KPiA+ICsJCQlzdnNiLT5mcmVxc19wY3RbaV0gPSBwZXJjZW50KHN2c2ItPm9wcF9mcmVx c1tpXSwNCj4gPiArCQkJCQkJICAgICBzdnNiLT5mcmVxX2Jhc2UpICYgMHhmZjsNCj4gPiArCQl9 DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4gDQo+IFRoZXJlIGFy ZSBsb3RzIG9mIHJlc291cmNlcyAocGxhdGZvcm1fZGV2aWNlLCBhbGwgdGhlIGttYWxsb2MgcmVn aW9ucykNCj4gdGhhdCBhcmUgbmV2ZXIgZnJlZSdkIGhlcmUuICBZb3UgbWlnaHQgY29uc2lkZXIg dXNpbmcgZGV2bSBmb3IgdGhpcy4NCj4gDQo+IFJlbGF0ZWQsIGFsbCB0aGUgc21hbGwgbWFsbG9j J3MgYXJlIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIG9wcF9jb3VudA0KPiBmb3IgZWFjaCBiYW5r LCBidXQgdGhleSBhcmUgYWxsIGhhcmQtY29kZWQgdG8gMTYuICAgU2VlbXMgaXQgd291bGQgYmUN Cj4gYmV0dGVyIHRvIGhhdmUgYSBkZWZhdWx0L21heCBzaXplIGZvciB0aGlzIGluIHRoZSBiYW5r IHN0cnVjdHVyZSBpdHNlbGYNCj4gaW5zdGVhZCBvZiBtYWtpbmcgdGhlc2Ugc21hbGwgYWxsb2Nh dGlvbnMuDQoNClRoYW5rcyBmb3IgdGhlIGFkdmljZXMuIFRoZSBkZWZhdWx0L21heCBzaXplIGFy ZSBnb29kIGlkZWFzLiBJJ2xsIGFwcGx5DQppdCBpbiB0aGUgbmV4dCBwYXRjaC4NCg0KPiANCj4g PiArc3RhdGljIGludCBzdnNfc3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpkZXYpDQo+ID4gK3sNCj4g PiArCXN0cnVjdCBtdGtfc3ZzICpzdnMgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCj4gPiArCWNv bnN0IHN0cnVjdCBzdnNfcGxhdGZvcm0gKnN2c3AgPSBzdnMtPnBsYXRmb3JtOw0KPiA+ICsJc3Ry dWN0IHN2c19iYW5rICpzdnNiOw0KPiA+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsNCj4gPiArCXUz MiBpZHg7DQo+ID4gKw0KPiA+ICsJLyogV2FpdCBpZiB0aGVyZSBpcyBwcm9jZXNzaW5nIHN2c19p c3IoKS4gU3VzcGVuZCBhbGwgYmFua3MuICovDQo+ID4gKwlmbGFncyA9IGNsYWltX210a19zdnNf bG9jaygpOw0KPiA+ICsJZm9yIChpZHggPSAwOyBpZHggPCBzdnNwLT5iYW5rX251bTsgaWR4Kysp IHsNCj4gPiArCQlzdnNiID0gJnN2c3AtPmJhbmtzW2lkeF07DQo+ID4gKwkJc3ZzLT5iYW5rID0g c3ZzYjsNCj4gPiArCQlzdnNfc3dpdGNoX2Jhbmsoc3ZzKTsNCj4gPiArCQlzdnNfd3JpdGVsKHN2 cywgMHgwLCBTVlNFTik7DQo+ID4gKwkJc3ZzX3dyaXRlbChzdnMsIDB4MDBmZmZmZmYsIElOVFNU Uyk7DQo+IA0KPiBJJ20gYXNzdW1pbmcgdGhpcyBwYXJ0IHdpbGwgZGlzYWJsZSBmdXR1cmUgaW50 ZXJydXB0cz8NClllcywgdGhpcyBmb3ItbG9vcCB3aWxsIGRpc2FibGUgYWxsIHRoZSBTVlMgYmFu a3MnIGludGVycnVwdHMuDQoNCj4gSSdtIG5vdCBzZWVpbmcgd2hlcmUgdGhleSBnZXQgcmUtZW5h YmxlZCBvbiB0aGUgcmVzdW1lIHBhdGguDQpJbiB0aGUgc3ZzX3Jlc3VtZSgpLCB3ZSByZS1ydW4g c3ZzX2luaXQwMigpIHRvIGVuYWJsZSBlYWNoIFNWUyBiYW5rLg0KDQo+IA0KPiANCj4gPiArCQlz dnNiLT5zdXNwZW5kZWQgPSB0cnVlOw0KPiA+ICsJfQ0KPiA+ICsJcmVsZWFzZV9tdGtfc3ZzX2xv Y2soZmxhZ3MpOw0KPiA+ICsNCj4gPiArCWZvciAoaWR4ID0gMDsgaWR4IDwgc3ZzcC0+YmFua19u dW07IGlkeCsrKSB7DQo+ID4gKwkJc3ZzYiA9ICZzdnNwLT5iYW5rc1tpZHhdOw0KPiA+ICsJCWlm IChzdnNiLT5waGFzZSA9PSBTVlNfUEhBU0VfTU9OKSB7DQo+ID4gKwkJCXN2c2ItPnBoYXNlID0g U1ZTX1BIQVNFX0lOSVQwMjsNCj4gPiArCQkJc3ZzX3NldF92b2x0cyhzdnNiLCB0cnVlKTsNCj4g PiArCQl9DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJY2xrX2Rpc2FibGVfdW5wcmVwYXJlKHN2cy0+ bWFpbl9jbGspOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz dGF0aWMgaW50IHN2c19yZXN1bWUoc3RydWN0IGRldmljZSAqZGV2KQ0KPiA+ICt7DQo+ID4gKwlz dHJ1Y3QgbXRrX3N2cyAqc3ZzID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ID4gKwljb25zdCBz dHJ1Y3Qgc3ZzX3BsYXRmb3JtICpzdnNwID0gc3ZzLT5wbGF0Zm9ybTsNCj4gPiArCXN0cnVjdCBz dnNfYmFuayAqc3ZzYjsNCj4gPiArCWludCByZXQ7DQo+ID4gKwl1MzIgaWR4Ow0KPiA+ICsNCj4g PiArCXJldCA9IGNsa19wcmVwYXJlX2VuYWJsZShzdnMtPm1haW5fY2xrKTsNCj4gPiArCWlmIChy ZXQpDQo+ID4gKwkJcHJfZXJyKCIlcygpOiBjYW5ub3QgZW5hYmxlIG1haW5fY2xrXG4iLCBfX2Z1 bmNfXyk7DQo+ID4gKw0KPiA+ICsJZm9yIChpZHggPSAwOyBpZHggPCBzdnNwLT5iYW5rX251bTsg aWR4KyspIHsNCj4gPiArCQlzdnNiID0gJnN2c3AtPmJhbmtzW2lkeF07DQo+ID4gKwkJc3ZzYi0+ c3VzcGVuZGVkID0gZmFsc2U7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0ID0gc3ZzX2luaXQw MihzdnMpOw0KPiA+ICsJaWYgKHJldCkNCj4gPiArCQlyZXR1cm4gcmV0Ow0KPiA+ICsNCj4gPiAr CXN2c19tb25fbW9kZShzdnMpOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+IA0K PiBLZXZpbg0KDQo= From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.2 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,USER_AGENT_SANE_2 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51204C32771 for ; Fri, 3 Jan 2020 05:55:21 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1F2ED21734 for ; Fri, 3 Jan 2020 05:55:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="qlJXUOIw"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="L8xYRhmV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1F2ED21734 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Date:To:From:Subject:Message-ID:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=g8A80eWHLaOD8r+CTWUOaMLjtv1dN8MFkmxmOVZGjas=; b=qlJXUOIwsdRZCb rknDURMn6Wp5bCTBfcy872SfZ9AASX51yFpn3ImyrNOyUSKTRJXGnVmuOz5NuRBOjbVKtyXpaQKpn Ty5k85/L3By11c4ROkhjiJwi7BUlBmukTPGOOlsscCPvi0azMUYLKoeFxkKDS5RoakS2ONnCA6zVW rfy3yN0mxE0nCOSeyd1MPOV66h/uppt7nA4oRJBBpfBQfE1foGDgkdEMc6g5ii6qV2viMVFqul11w 9UriYCYLA6h1VnLaRMnS2LagRspjyLSGBPMmAsA1vF47pU6jRv924AwQ0jd+O2+wLTUpy/f0bJAKb doibVrNXYYqD1JOA5R/g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1inFvc-00075m-PA; Fri, 03 Jan 2020 05:55:20 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1inFvV-00074H-AZ; Fri, 03 Jan 2020 05:55:18 +0000 X-UUID: 46dcfd2d8b244249b7953ff7f8117c95-20200102 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:MIME-Version:Content-Type:References:In-Reply-To:Date:CC:To:From:Subject:Message-ID; bh=JNRfAfDLAyXxpHtn3SvuzDUGpMWxlxKC54Aay/GuRbs=; b=L8xYRhmVmjczS7o647tyFG651d9sTN8P/sV8/T/YSj0v2qT7yoZJPAGpw1Pu94M9qKLLXLZpaYBIkNlgPiXNi/kLVZkV1+v9/WFnj2qwt06FaRB+VWRox8NcFsuVcXrclSKVvpxP+hDQX8JHW8vIKhjGPLl9SftLG9Hsfw3icQk=; X-UUID: 46dcfd2d8b244249b7953ff7f8117c95-20200102 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 844353794; Thu, 02 Jan 2020 21:55:08 -0800 Received: from MTKMBS01N2.mediatek.inc (172.21.101.79) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 2 Jan 2020 21:45:08 -0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs01n2.mediatek.inc (172.21.101.79) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 3 Jan 2020 13:42:56 +0800 Received: from [172.21.77.4] (172.21.77.4) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Fri, 3 Jan 2020 13:44:49 +0800 Message-ID: <1578030290.10850.45.camel@mtksdaap41> Subject: Re: [PATCH v5 3/3] PM / AVS: SVS: Introduce SVS engine From: Roger Lu To: Kevin Hilman Date: Fri, 3 Jan 2020 13:44:50 +0800 In-Reply-To: <7hpnjmiswn.fsf@baylibre.com> References: <20190906100514.30803-1-roger.lu@mediatek.com> <20190906100514.30803-4-roger.lu@mediatek.com> <7hpnjmiswn.fsf@baylibre.com> X-Mailer: Evolution 3.10.4-0ubuntu2 MIME-Version: 1.0 X-TM-SNTS-SMTP: D7704B8214DDB3A76E72843BDF025556B78AC5F37EAEF28A2E40DE73002FBEE72000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200102_215514_355820_9BAB1E1B X-CRM114-Status: GOOD ( 25.41 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Nicolas Boichat , Angus Lin , Kevin Hilman , Stephen Boyd , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, HenryC Chen , yt.lee@mediatek.com, Fan Chen , devicetree@vger.kernel.org, Rob Herring , linux-mediatek@lists.infradead.org, Matthias Brugger , Nishanth Menon , linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org Dear Kevin Sir, Sorry for the late reply and thanks for the advice to this patch. On Thu, 2019-09-26 at 15:39 -0700, Kevin Hilman wrote: > Hi Roger, > > Roger Lu writes: > > > The SVS (Smart Voltage Scaling) engine is a piece of hardware which is > > used to calculate optimized voltage values of several power domains, e.g. > > CPU/GPU/CCI, according to chip process corner, temperatures, and other > > factors. Then DVFS driver could apply those optimized voltage values to > > reduce power consumption. > > > > Signed-off-by: Roger Lu > > I don't have any documentation on this SVS hardware, so I won't be able > to comment on the specific functionality, so I attempted a first-pass > high-level review... Excuse me, we don't have the documentation for SVS hardware. I'll try my best to introduce SVS online. > > In the absence of documentation, it would be helpful to give a high > level description of how this hardware works. In particular, a > high-level overview of the control loop, which appears to be primarily > interrupt driven, would be helpful. e.g. how often are the interrupts > firing, and why. 1. MT8183 SVS has 4 controllers (banks). One bank for optimizing one power-domain OPP voltages. - 4 power-domain (CPU-little / CPU-BIG / CCI / GPU) OPP voltages will be optimized by SVS banks.. 2. Each SVS bank needs to run its init01/init02 separately so that SVS bank's optimized OPP voltages can be calculated to system. - init01: SVS bank basic init (must) - init02: SVS bank provide high temperature OPP voltages (must) - mon mode: SVS bank dynamically optimizes OPP voltages basing on temperature change. (optional) 3. SVS interrupt behavior - In init01/init02, SVS only fire one interrupt to inform SW that init is finished and optimized OPP voltages are ready. - In mon mode, SVS fire interrupt when temperature changes. Mon mode interrupt is also for informing new optimized OPP voltages are ready. > > It's hard to understand the "init01" vs the "init02" patch since > those names aren't very descriptive. :) > > Also, there are lots of hard-coded constants (masks, shifts, etc.) used > throughout the calculations. #defines could help readability for many > of these, especially the masks. > > > --- > > drivers/power/avs/Kconfig | 10 + > > drivers/power/avs/Makefile | 1 + > > drivers/power/avs/mtk_svs.c | 2075 +++++++++++++++++++++++++++++++++ > > include/linux/power/mtk_svs.h | 23 + > > 4 files changed, 2109 insertions(+) > > create mode 100644 drivers/power/avs/mtk_svs.c > > create mode 100644 include/linux/power/mtk_svs.h > > > > diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig > > index b5a217b828dc..7c72504d5593 100644 > > --- a/drivers/power/avs/Kconfig > > +++ b/drivers/power/avs/Kconfig > > @@ -19,3 +19,13 @@ config ROCKCHIP_IODOMAIN > > Say y here to enable support io domains on Rockchip SoCs. It is > > necessary for the io domain setting of the SoC to match the > > voltage supplied by the regulators. > > + > > +config MTK_SVS > > + bool "MediaTek Smart Voltage Scaling(SVS)" > > + depends on POWER_AVS && MTK_EFUSE > > + help > > + The SVS engine is a piece of hardware which is used to calculate > > + optimized voltage values of several power domains, e.g. > > + CPU clusters/GPU/CCI, according to chip process corner, temperatures, > > + and other factors. Then DVFS driver could apply those optimized voltage > > + values to reduce power consumption. > > diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile > > index a1b8cd453f19..57246b977a93 100644 > > --- a/drivers/power/avs/Makefile > > +++ b/drivers/power/avs/Makefile > > @@ -1,3 +1,4 @@ > > # SPDX-License-Identifier: GPL-2.0-only > > obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o > > obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o > > +obj-$(CONFIG_MTK_SVS) += mtk_svs.o > > diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c > > new file mode 100644 > > index 000000000000..78ec93c3a4a5 > > --- /dev/null > > +++ b/drivers/power/avs/mtk_svs.c > > @@ -0,0 +1,2075 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2018 MediaTek Inc. > > + */ > > + > > +#define pr_fmt(fmt) "[mtk_svs] " fmt > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define SVS_INIT01_VOLT_IGNORE 1 > > +#define SVS_INIT01_VOLT_INC_ONLY 2 > > + > > +#define SVS_PHASE_INIT01 0 > > +#define SVS_PHASE_INIT02 1 > > +#define SVS_PHASE_MON 2 > > +#define SVS_PHASE_ERROR 3 > > + > > +#define SVS_CPU_LITTLE 1 > > +#define SVS_CPU_BIG 2 > > +#define SVS_CCI 3 > > +#define SVS_GPU 4 > > + > > +#define proc_fops_rw(name) \ > > + static int name ## _proc_open(struct inode *inode, \ > > + struct file *file) \ > > + { \ > > + return single_open(file, name ## _proc_show, \ > > + PDE_DATA(inode)); \ > > + } \ > > + static const struct file_operations name ## _proc_fops = { \ > > + .owner = THIS_MODULE, \ > > + .open = name ## _proc_open, \ > > + .read = seq_read, \ > > + .llseek = seq_lseek, \ > > + .release = single_release, \ > > + .write = name ## _proc_write, \ > > + } > > + > > +#define proc_fops_ro(name) \ > > + static int name ## _proc_open(struct inode *inode, \ > > + struct file *file) \ > > + { \ > > + return single_open(file, name ## _proc_show, \ > > + PDE_DATA(inode)); \ > > + } \ > > + static const struct file_operations name ## _proc_fops = { \ > > + .owner = THIS_MODULE, \ > > + .open = name ## _proc_open, \ > > + .read = seq_read, \ > > + .llseek = seq_lseek, \ > > + .release = single_release, \ > > + } > > + > > +#define proc_entry(name) {__stringify(name), &name ## _proc_fops} > > + > > +static DEFINE_SPINLOCK(mtk_svs_lock); > > +struct mtk_svs; > > + > > +enum reg_index { > > + TEMPMONCTL0 = 0, > > + TEMPMONCTL1, > > + TEMPMONCTL2, > > + TEMPMONINT, > > + TEMPMONINTSTS, > > + TEMPMONIDET0, > > + TEMPMONIDET1, > > + TEMPMONIDET2, > > + TEMPH2NTHRE, > > + TEMPHTHRE, > > + TEMPCTHRE, > > + TEMPOFFSETH, > > + TEMPOFFSETL, > > + TEMPMSRCTL0, > > + TEMPMSRCTL1, > > + TEMPAHBPOLL, > > + TEMPAHBTO, > > + TEMPADCPNP0, > > + TEMPADCPNP1, > > + TEMPADCPNP2, > > + TEMPADCMUX, > > + TEMPADCEXT, > > + TEMPADCEXT1, > > + TEMPADCEN, > > + TEMPPNPMUXADDR, > > + TEMPADCMUXADDR, > > + TEMPADCEXTADDR, > > + TEMPADCEXT1ADDR, > > + TEMPADCENADDR, > > + TEMPADCVALIDADDR, > > + TEMPADCVOLTADDR, > > + TEMPRDCTRL, > > + TEMPADCVALIDMASK, > > + TEMPADCVOLTAGESHIFT, > > + TEMPADCWRITECTRL, > > + TEMPMSR0, > > + TEMPMSR1, > > + TEMPMSR2, > > + TEMPADCHADDR, > > + TEMPIMMD0, > > + TEMPIMMD1, > > + TEMPIMMD2, > > + TEMPMONIDET3, > > + TEMPADCPNP3, > > + TEMPMSR3, > > + TEMPIMMD3, > > + TEMPPROTCTL, > > + TEMPPROTTA, > > + TEMPPROTTB, > > + TEMPPROTTC, > > + TEMPSPARE0, > > + TEMPSPARE1, > > + TEMPSPARE2, > > + TEMPSPARE3, > > + TEMPMSR0_1, > > + TEMPMSR1_1, > > + TEMPMSR2_1, > > + TEMPMSR3_1, > > + DESCHAR, > > + 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, > > + reg_num, > > +}; > > + > > +static const u32 svs_regs_v2[] = { > > + [TEMPMONCTL0] = 0x000, > > + [TEMPMONCTL1] = 0x004, > > + [TEMPMONCTL2] = 0x008, > > + [TEMPMONINT] = 0x00c, > > + [TEMPMONINTSTS] = 0x010, > > + [TEMPMONIDET0] = 0x014, > > + [TEMPMONIDET1] = 0x018, > > + [TEMPMONIDET2] = 0x01c, > > + [TEMPH2NTHRE] = 0x024, > > + [TEMPHTHRE] = 0x028, > > + [TEMPCTHRE] = 0x02c, > > + [TEMPOFFSETH] = 0x030, > > + [TEMPOFFSETL] = 0x034, > > + [TEMPMSRCTL0] = 0x038, > > + [TEMPMSRCTL1] = 0x03c, > > + [TEMPAHBPOLL] = 0x040, > > + [TEMPAHBTO] = 0x044, > > + [TEMPADCPNP0] = 0x048, > > + [TEMPADCPNP1] = 0x04c, > > + [TEMPADCPNP2] = 0x050, > > + [TEMPADCMUX] = 0x054, > > + [TEMPADCEXT] = 0x058, > > + [TEMPADCEXT1] = 0x05c, > > + [TEMPADCEN] = 0x060, > > + [TEMPPNPMUXADDR] = 0x064, > > + [TEMPADCMUXADDR] = 0x068, > > + [TEMPADCEXTADDR] = 0x06c, > > + [TEMPADCEXT1ADDR] = 0x070, > > + [TEMPADCENADDR] = 0x074, > > + [TEMPADCVALIDADDR] = 0x078, > > + [TEMPADCVOLTADDR] = 0x07c, > > + [TEMPRDCTRL] = 0x080, > > + [TEMPADCVALIDMASK] = 0x084, > > + [TEMPADCVOLTAGESHIFT] = 0x088, > > + [TEMPADCWRITECTRL] = 0x08c, > > + [TEMPMSR0] = 0x090, > > + [TEMPMSR1] = 0x094, > > + [TEMPMSR2] = 0x098, > > + [TEMPADCHADDR] = 0x09c, > > + [TEMPIMMD0] = 0x0a0, > > + [TEMPIMMD1] = 0x0a4, > > + [TEMPIMMD2] = 0x0a8, > > + [TEMPMONIDET3] = 0x0b0, > > + [TEMPADCPNP3] = 0x0b4, > > + [TEMPMSR3] = 0x0b8, > > + [TEMPIMMD3] = 0x0bc, > > + [TEMPPROTCTL] = 0x0c0, > > + [TEMPPROTTA] = 0x0c4, > > + [TEMPPROTTB] = 0x0c8, > > + [TEMPPROTTC] = 0x0cc, > > + [TEMPSPARE0] = 0x0f0, > > + [TEMPSPARE1] = 0x0f4, > > + [TEMPSPARE2] = 0x0f8, > > + [TEMPSPARE3] = 0x0fc, > > + [TEMPMSR0_1] = 0x190, > > + [TEMPMSR1_1] = 0x194, > > + [TEMPMSR2_1] = 0x198, > > + [TEMPMSR3_1] = 0x1b8, > > + [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 { > > + 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; > > +}; > > + > > +struct svs_bank_ops { > > + void (*set_freqs_pct)(struct mtk_svs *svs); > > + void (*get_vops)(struct mtk_svs *svs); > > +}; > > + > > +struct svs_bank { > > + struct svs_bank_ops *ops; > > + struct completion init_completion; > > + struct device *dev; > > + struct regulator *buck; > > + struct mutex lock; /* lock to protect update voltage process */ > > + bool suspended; > > + bool mtcmos_request; > > + bool init01_support; > > + bool init02_support; > > + bool mon_mode_support; > > + s32 volt_offset; > > + u32 *opp_freqs; > > + u32 *freqs_pct; > > + u32 *opp_volts; > > + u32 *init02_volts; > > + u32 *volts; > > + u32 reg_data[3][reg_num]; > > + u32 freq_base; > > + u32 vboot; > > + u32 volt_step; > > + u32 volt_base; > > + u32 init01_volt_flag; > > + u32 phase; > > + u32 vmax; > > + u32 vmin; > > + 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 chkshift; > > + u32 svs_temp; > > + u32 upper_temp_bound; > > + u32 lower_temp_bound; > > + u32 low_temp_threashold; > > + u32 low_temp_offset; > > + u32 coresel; > > + u32 opp_count; > > + u32 intst; > > + u32 systemclk_en; > > + u32 sw_id; > > + u32 hw_id; > > + u32 ctl0; > > + u8 *of_compatible; > > + u8 *name; > > + u8 *zone_name; > > + u8 *buck_name; > > +}; > > + > > +struct svs_platform { > > + struct svs_bank *banks; > > + int (*efuse_parsing)(struct mtk_svs *svs); > > + bool fake_efuse; > > + const u32 *regs; > > + u32 bank_num; > > + u32 efuse_num; > > + u32 efuse_check; > > + u32 thermal_efuse_num; > > + u8 *name; > > +}; > > + > > +struct mtk_svs { > > + const struct svs_platform *platform; > > + struct svs_bank *bank; > > + struct device *dev; > > + void __iomem *base; > > + struct clk *main_clk; > > + u32 *efuse; > > + u32 *thermal_efuse; > > +}; > > + > > +unsigned long claim_mtk_svs_lock(void) > > +{ > > + unsigned long flags; > > + > > + spin_lock_irqsave(&mtk_svs_lock, flags); > > + > > + return flags; > > +} > > +EXPORT_SYMBOL_GPL(claim_mtk_svs_lock); > > + > > +void release_mtk_svs_lock(unsigned long flags) > > +{ > > + spin_unlock_irqrestore(&mtk_svs_lock, flags); > > +} > > +EXPORT_SYMBOL_GPL(release_mtk_svs_lock); > > I don't see the need for these wrapper functions. You seem to be > declaring this lock in the header which implies there are external > users, but there is none in this series, so this lock should stay local > IMO. This export API is for mtk thermal driver. https://patchwork.kernel.org/patch/10938841/ > > > +static u32 percent(u32 numerator, u32 denominator) > > +{ > > + u32 percent; > > + > > + /* If not divide 1000, "numerator * 100" would be data overflow. */ > > + numerator /= 1000; > > + denominator /= 1000; > > + percent = ((numerator * 100) + denominator - 1) / denominator; > > + > > + return percent; > > +} > > Maybe some math helpers from math64.h would help you not have to > open-code this? Oh, thanks for the reminding. I haven't found the suitable "percent() API" from math64.h and will keep looking suitable API to replace these codes. > > > +static u32 svs_readl(struct mtk_svs *svs, enum reg_index i) > > +{ > > + return readl(svs->base + svs->platform->regs[i]); > > +} > > + > > +static void svs_writel(struct mtk_svs *svs, u32 val, enum reg_index i) > > +{ > > + writel(val, svs->base + svs->platform->regs[i]); > > +} > > + > > +static void svs_switch_bank(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + > > + svs_writel(svs, svsb->coresel, CORESEL); > > +} > > + > > +static u32 svs_volt_to_opp_volt(u32 svsb_volt, > > + u32 svsb_volt_step, u32 svsb_volt_base) > > +{ > > + u32 u_volt; > > + > > + u_volt = (svsb_volt * svsb_volt_step) + svsb_volt_base; > > + > > + return u_volt; > > +} > > + > > +static int svs_get_zone_temperature(struct svs_bank *svsb, int *zone_temp) > > +{ > > + struct thermal_zone_device *tzd; > > + int ret; > > + > > + tzd = thermal_zone_get_zone_by_name(svsb->zone_name); > > + ret = thermal_zone_get_temp(tzd, zone_temp); > > + > > + return ret; > > +} > > + > > +static int svs_set_volts(struct svs_bank *svsb, bool force_update) > > +{ > > + u32 i, svsb_volt, opp_volt, low_temp_offset = 0; > > + int zone_temp, ret; > > + > > + mutex_lock(&svsb->lock); > > + > > + /* If bank is suspended, it means init02 voltage is applied. > > + * Don't need to update opp voltage anymore. > > + */ > > minor nit: fix multi-line comment style Sure. I'll fix it in the next patch.Thanks. > > > + if (svsb->suspended && !force_update) { > > + pr_notice("%s: bank is suspended\n", svsb->name); > > + mutex_unlock(&svsb->lock); > > + return -EPERM; > > + } > > + > > + /* get thermal effect */ > > + if (svsb->phase == SVS_PHASE_MON) { > > + if (svsb->svs_temp > svsb->upper_temp_bound && > > + svsb->svs_temp < svsb->lower_temp_bound) { > > + pr_err("%s: svs_temp is abnormal (0x%x)?\n", > > + svsb->name, svsb->svs_temp); > > + mutex_unlock(&svsb->lock); > > + return -EINVAL; > > + } > > + > > + ret = svs_get_zone_temperature(svsb, &zone_temp); > > + if (ret) { > > + pr_err("%s: cannot get zone \"%s\" temperature\n", > > + svsb->name, svsb->zone_name); > > + pr_err("%s: add low_temp_offset = %u\n", > > + svsb->name, svsb->low_temp_offset); > > + zone_temp = svsb->low_temp_threashold; > > + } > > + > > + if (zone_temp <= svsb->low_temp_threashold) > > + low_temp_offset = svsb->low_temp_offset; > > + } > > + > > + /* vmin <= svsb_volt (opp_volt) <= signed-off voltage */ > > + for (i = 0; i < svsb->opp_count; i++) { > > + if (svsb->phase == SVS_PHASE_MON) { > > + svsb_volt = max((svsb->volts[i] + svsb->volt_offset + > > + low_temp_offset), svsb->vmin); > > + opp_volt = svs_volt_to_opp_volt(svsb_volt, > > + svsb->volt_step, > > + svsb->volt_base); > > + } else if (svsb->phase == SVS_PHASE_INIT02) { > > + svsb_volt = max((svsb->init02_volts[i] + > > + svsb->volt_offset), svsb->vmin); > > + opp_volt = svs_volt_to_opp_volt(svsb_volt, > > + svsb->volt_step, > > + svsb->volt_base); > > + } else if (svsb->phase == SVS_PHASE_ERROR) { > > + opp_volt = svsb->opp_volts[i]; > > + } else { > > + pr_err("%s: unknown phase: %u?\n", > > + svsb->name, svsb->phase); > > + mutex_unlock(&svsb->lock); > > + return -EINVAL; > > + } > > + > > + opp_volt = min(opp_volt, svsb->opp_volts[i]); > > + ret = dev_pm_opp_adjust_voltage(svsb->dev, svsb->opp_freqs[i], > > + opp_volt); > > + if (ret) { > > + pr_err("%s: set voltage failed: %d\n", svsb->name, ret); > > + mutex_unlock(&svsb->lock); > > + return ret; > > + } > > + } > > + > > + mutex_unlock(&svsb->lock); > > + > > + return 0; > > +} > > + > > +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx) > > +{ > > + u32 vy; > > + > > + if (v0 == v1 || f0 == f1) > > + return v0; > > + > > + /* *100 to have decimal fraction factor, +99 for rounding up. */ > > + vy = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx)); > > + vy = (vy + 99) / 100; > > + > > + return vy; > > +} > > + > > +static void svs_get_vops_v2(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + u32 temp, i; > > + > > + temp = svs_readl(svs, VOP30); > > + svsb->volts[6] = (temp >> 24) & 0xff; > > + svsb->volts[4] = (temp >> 16) & 0xff; > > + svsb->volts[2] = (temp >> 8) & 0xff; > > + svsb->volts[0] = (temp & 0xff); > > + > > + temp = svs_readl(svs, VOP74); > > + svsb->volts[14] = (temp >> 24) & 0xff; > > + svsb->volts[12] = (temp >> 16) & 0xff; > > + svsb->volts[10] = (temp >> 8) & 0xff; > > + svsb->volts[8] = (temp & 0xff); > > + > > + for (i = 0; i <= 7; i++) { > > + if (i < 7) { > > + svsb->volts[(i * 2) + 1] = > > + interpolate(svsb->freqs_pct[i * 2], > > + svsb->freqs_pct[(i + 1) * 2], > > + svsb->volts[i * 2], > > + svsb->volts[(i + 1) * 2], > > + svsb->freqs_pct[(i * 2) + 1]); > > + } else if (i == 7) { > > + svsb->volts[(i * 2) + 1] = > > + interpolate(svsb->freqs_pct[(i - 1) * 2], > > + svsb->freqs_pct[i * 2], > > + svsb->volts[(i - 1) * 2], > > + svsb->volts[i * 2], > > + svsb->freqs_pct[(i * 2) + 1]); > > + } > > + } > > +} > > + > > +static void svs_set_freqs_pct_v2(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + > > + svs_writel(svs, > > + ((svsb->freqs_pct[6] << 24) & 0xff000000) | > > + ((svsb->freqs_pct[4] << 16) & 0xff0000) | > > + ((svsb->freqs_pct[2] << 8) & 0xff00) | > > + (svsb->freqs_pct[0] & 0xff), > > + FREQPCT30); > > + svs_writel(svs, > > + ((svsb->freqs_pct[14] << 24) & 0xff000000) | > > + ((svsb->freqs_pct[12] << 16) & 0xff0000) | > > + ((svsb->freqs_pct[10] << 8) & 0xff00) | > > + ((svsb->freqs_pct[8]) & 0xff), > > + FREQPCT74); > > +} > > + > > +static void svs_set_phase(struct mtk_svs *svs, u32 target_phase) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + u32 des_char, temp_char, det_char, limit_vals; > > + u32 init2vals, ts_calcs, val, filter, i; > > + > > + svs_switch_bank(svs); > > + > > + des_char = ((svsb->bdes << 8) & 0xff00) | (svsb->mdes & 0xff); > > + svs_writel(svs, des_char, DESCHAR); > > + > > + temp_char = ((svsb->vco << 16) & 0xff0000) | > > + ((svsb->mtdes << 8) & 0xff00) | > > + (svsb->dvt_fixed & 0xff); > > + svs_writel(svs, temp_char, TEMPCHAR); > > + > > + det_char = ((svsb->dcbdet << 8) & 0xff00) | (svsb->dcmdet & 0xff); > > + svs_writel(svs, det_char, DETCHAR); > > + > > + svs_writel(svs, svsb->dc_config, DCCONFIG); > > + svs_writel(svs, svsb->age_config, AGECONFIG); > > + > > + if (svsb->agem == 0x0) { > > + svs_writel(svs, 0x80000000, RUNCONFIG); > > + } else { > > + val = 0x0; > > + > > + for (i = 0; i < 24; i += 2) { > > + filter = 0x3 << i; > > + > > + if ((svsb->age_config & filter) == 0x0) > > + val |= (0x1 << i); > > + else > > + val |= (svsb->age_config & filter); > > + } > > + svs_writel(svs, val, RUNCONFIG); > > + } > > + > > + svsb->ops->set_freqs_pct(svs); > > + > > + limit_vals = ((svsb->vmax << 24) & 0xff000000) | > > + ((svsb->vmin << 16) & 0xff0000) | > > + ((svsb->dthi << 8) & 0xff00) | > > + (svsb->dtlo & 0xff); > > + svs_writel(svs, limit_vals, LIMITVALS); > > + svs_writel(svs, (svsb->vboot & 0xff), VBOOT); > > + svs_writel(svs, (svsb->det_window & 0xffff), DETWINDOW); > > + svs_writel(svs, (svsb->det_max & 0xffff), CONFIG); > > + > > + if (svsb->chkshift != 0) > > + svs_writel(svs, (svsb->chkshift & 0xff), CHKSHIFT); > > + > > + if (svsb->ctl0 != 0) > > + svs_writel(svs, svsb->ctl0, CTL0); > > + > > + svs_writel(svs, 0x00ffffff, INTSTS); > > + > > + switch (target_phase) { > > + case SVS_PHASE_INIT01: > > + svs_writel(svs, 0x00005f01, INTEN); > > + svs_writel(svs, 0x00000001, SVSEN); > > + break; > > + case SVS_PHASE_INIT02: > > + svs_writel(svs, 0x00005f01, INTEN); > > + init2vals = ((svsb->age_voffset_in << 16) & 0xffff0000) | > > + (svsb->dc_voffset_in & 0xffff); > > + svs_writel(svs, init2vals, INIT2VALS); > > + svs_writel(svs, 0x00000005, SVSEN); > > + break; > > + case SVS_PHASE_MON: > > + ts_calcs = ((svsb->bts << 12) & 0xfff000) | (svsb->mts & 0xfff); > > + svs_writel(svs, ts_calcs, TSCALCS); > > + svs_writel(svs, 0x00FF0000, INTEN); > > + svs_writel(svs, 0x00000002, SVSEN); > > + break; > > + default: > > + WARN_ON(1); > > + break; > > + } > > +} > > lots of magic constants for these register writes. #defines w/bit > descriptions would be very helpful for the reader. Sure, I'll add #define w/bit for these magic constants in the next patch. Thanks. > > > +static inline void svs_init01_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_notice("%s: %s: VDN74:0x%08x, VDN30:0x%08x, DCVALUES:0x%08x\n", > > + svsb->name, __func__, svs_readl(svs, VDESIGN74), > > + svs_readl(svs, VDESIGN30), svs_readl(svs, DCVALUES)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_INIT01][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->dc_voffset_in = ~(svs_readl(svs, DCVALUES) & 0xffff) + 1; > > + if (svsb->init01_volt_flag == SVS_INIT01_VOLT_IGNORE) > > + svsb->dc_voffset_in = 0; > > + else if ((svsb->dc_voffset_in & 0x8000) && > > + (svsb->init01_volt_flag == SVS_INIT01_VOLT_INC_ONLY)) > > + svsb->dc_voffset_in = 0; > > + > > + svsb->age_voffset_in = svs_readl(svs, AGEVALUES) & 0xffff; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x1, INTSTS); > > + > > + /* svs init01 clock gating */ > > + svsb->coresel &= ~svsb->systemclk_en; > > + > > + svsb->phase = SVS_PHASE_INIT01; > > + complete(&svsb->init_completion); > > +} > > + > > +static inline void svs_init02_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_notice("%s: %s: VOP74:0x%08x, VOP30:0x%08x, DCVALUES:0x%08x\n", > > + svsb->name, __func__, svs_readl(svs, VOP74), > > + svs_readl(svs, VOP30), svs_readl(svs, DCVALUES)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_INIT02][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->ops->get_vops(svs); > > + memcpy(svsb->init02_volts, svsb->volts, 4 * svsb->opp_count); > > + svsb->phase = SVS_PHASE_INIT02; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x1, INTSTS); > > + > > + complete(&svsb->init_completion); > > +} > > + > > +static inline void svs_mon_mode_isr_handler(struct mtk_svs *svs) > > +{ > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->svs_temp = svs_readl(svs, TEMP) & 0xff; > > + > > + svsb->ops->get_vops(svs); > > + svsb->phase = SVS_PHASE_MON; > > + > > + svs_writel(svs, 0x00ff0000, INTSTS); > > +} > > + > > +static inline void svs_error_isr_handler(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb = svs->bank; > > + enum reg_index rg_i; > > + > > + pr_err("%s(): %s(%s)", __func__, svsp->name, svsb->name); > > + pr_err("CORESEL(0x%x) = 0x%08x\n", > > + svsp->regs[CORESEL], svs_readl(svs, CORESEL)), > > + pr_err("SVSEN(0x%x) = 0x%08x, INTSTS(0x%x) = 0x%08x\n", > > + svsp->regs[SVSEN], svs_readl(svs, SVSEN), > > + svsp->regs[INTSTS], svs_readl(svs, INTSTS)); > > + pr_err("SMSTATE0(0x%x) = 0x%08x, SMSTATE1(0x%x) = 0x%08x\n", > > + svsp->regs[SMSTATE0], svs_readl(svs, SMSTATE0), > > + svsp->regs[SMSTATE1], svs_readl(svs, SMSTATE1)); > > + > > + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++) > > + svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i); > > + > > + svsb->init01_support = false; > > + svsb->init02_support = false; > > + svsb->mon_mode_support = false; > > + > > + if (svsb->phase == SVS_PHASE_MON) > > + svsb->phase = SVS_PHASE_INIT02; > > + > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x00ffffff, INTSTS); > > +} > > + > > +static inline void svs_isr_handler(struct mtk_svs *svs) > > +{ > > + u32 intsts, svsen; > > + > > + svs_switch_bank(svs); > > + > > + intsts = svs_readl(svs, INTSTS); > > + svsen = svs_readl(svs, SVSEN); > > + > > + if (intsts == 0x1 && ((svsen & 0x7) == 0x1)) > > + svs_init01_isr_handler(svs); > > + else if ((intsts == 0x1) && ((svsen & 0x7) == 0x5)) > > + svs_init02_isr_handler(svs); > > + else if ((intsts & 0x00ff0000) != 0x0) > > + svs_mon_mode_isr_handler(svs); > > + else > > + svs_error_isr_handler(svs); > > +} > > + > > +static irqreturn_t svs_isr(int irq, void *data) > > +{ > > + struct mtk_svs *svs = (struct mtk_svs *)data; > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb = NULL; > > + unsigned long flags; > > + u32 idx; > > + > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (svsb->suspended) > > + continue; > > + else if (svsb->intst & svs_readl(svs, INTST)) > > + continue; > > + > > + svs_isr_handler(svs); > > + break; > > + } > > + release_mtk_svs_lock(flags); > > + > > + if (svsb->phase != SVS_PHASE_INIT01) > > + svs_set_volts(svsb, false); > > + > > + return IRQ_HANDLED; > > +} > > + > > +static void svs_mon_mode(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags; > > + u32 idx; > > + > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->mon_mode_support) > > + continue; > > + > > + svs_set_phase(svs, SVS_PHASE_MON); > > + } > > + release_mtk_svs_lock(flags); > > +} > > + > > +static int svs_init02(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags, time_left; > > + u32 idx; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->init02_support) > > + continue; > > + > > + reinit_completion(&svsb->init_completion); > > + flags = claim_mtk_svs_lock(); > > + svs_set_phase(svs, SVS_PHASE_INIT02); > > + release_mtk_svs_lock(flags); > > + time_left = > > + wait_for_completion_timeout(&svsb->init_completion, > > + msecs_to_jiffies(2000)); > > + if (time_left == 0) { > > + pr_err("%s: init02 completion timeout\n", svsb->name); > > + return -EBUSY; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int svs_init01(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct pm_qos_request qos_request = { {0} }; > > + unsigned long flags, time_left; > > + bool search_done; > > + int ret = -EINVAL; > > + u32 opp_freqs, opp_vboot, buck_volt, idx, i; > > + > > + /* Let CPUs leave idle-off state for initializing svs_init01. */ > > + pm_qos_add_request(&qos_request, PM_QOS_CPU_DMA_LATENCY, 0); > > + > > + /* Sometimes two svs_bank 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]; > > + search_done = false; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST); > > + if (ret) > > + pr_notice("%s: fail to set fast mode: %d\n", > > + svsb->name, ret); > > + > > + if (svsb->mtcmos_request) { > > + ret = regulator_enable(svsb->buck); > > + if (ret) { > > + pr_err("%s: fail to enable %s power: %d\n", > > + svsb->name, svsb->buck_name, ret); > > + goto init01_finish; > > + } > > + > > + ret = dev_pm_domain_attach(svsb->dev, false); > > + if (ret) { > > + pr_err("%s: attach pm domain fail: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + > > + pm_runtime_enable(svsb->dev); > > + ret = pm_runtime_get_sync(svsb->dev); > > + if (ret < 0) { > > + pr_err("%s: turn mtcmos on fail: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + } > > + > > + /* Find the fastest freq that can be run at vboot and > > + * fix to that freq until svs_init01 is done. > > + */ > > + opp_vboot = svs_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->dev, > > + opp_freqs, > > + opp_vboot); > > + if (ret) { > > + pr_err("%s: set voltage failed: %d\n", > > + svsb->name, ret); > > + goto init01_finish; > > + } > > + > > + search_done = true; > > + } else { > > + dev_pm_opp_disable(svsb->dev, > > + svsb->opp_freqs[i]); > > + } > > + } > > + } > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + opp_vboot = svs_volt_to_opp_volt(svsb->vboot, > > + svsb->volt_step, > > + svsb->volt_base); > > + > > + buck_volt = regulator_get_voltage(svsb->buck); > > + if (buck_volt != opp_vboot) { > > + pr_err("%s: buck voltage: %u, expected vboot: %u\n", > > + svsb->name, buck_volt, opp_vboot); > > + ret = -EPERM; > > + goto init01_finish; > > + } > > + > > + init_completion(&svsb->init_completion); > > + flags = claim_mtk_svs_lock(); > > + svs_set_phase(svs, SVS_PHASE_INIT01); > > + release_mtk_svs_lock(flags); > > + time_left = > > + wait_for_completion_timeout(&svsb->init_completion, > > + msecs_to_jiffies(2000)); > > + if (time_left == 0) { > > + pr_err("%s: init01 completion timeout\n", svsb->name); > > + ret = -EBUSY; > > + goto init01_finish; > > + } > > + } > > + > > +init01_finish: > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + for (i = 0; i < svsb->opp_count; i++) > > + dev_pm_opp_enable(svsb->dev, svsb->opp_freqs[i]); > > + > > + if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL)) > > + pr_notice("%s: fail to set normal mode: %d\n", > > + svsb->name, ret); > > + > > + if (svsb->mtcmos_request) { > > + if (pm_runtime_put_sync(svsb->dev)) > > + pr_err("%s: turn mtcmos off fail: %d\n", > > + svsb->name, ret); > > + pm_runtime_disable(svsb->dev); > > + dev_pm_domain_detach(svsb->dev, 0); > > + if (regulator_disable(svsb->buck)) > > + pr_err("%s: fail to disable %s power: %d\n", > > + svsb->name, svsb->buck_name, ret); > > + } > > + } > > + > > + pm_qos_remove_request(&qos_request); > > + > > + return ret; > > +} > > + > > +static int svs_start(struct mtk_svs *svs) > > +{ > > + int ret; > > + > > + ret = svs_init01(svs); > > + if (ret) > > + return ret; > > + > > + ret = svs_init02(svs); > > + if (ret) > > + return ret; > > + > > + svs_mon_mode(svs); > > + > > + return ret; > > +} > > + > > +static int svs_mt8183_efuse_parsing(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct thermal_parameter tp; > > + struct svs_bank *svsb; > > + bool mon_mode_support = true; > > + int format[6], x_roomt[6], tb_roomt; > > + u32 idx, i, ft_pgm, mts, temp0, temp1, temp2; > > + > > + if (svsp->fake_efuse) { > > + pr_notice("fake efuse\n"); > > + svs->efuse[0] = 0x00310080; > > + svs->efuse[1] = 0xabfbf757; > > + svs->efuse[2] = 0x47c747c7; > > + svs->efuse[3] = 0xabfbf757; > > + svs->efuse[4] = 0xe7fca0ec; > > + svs->efuse[5] = 0x47bf4b88; > > + svs->efuse[6] = 0xabfb8fa5; > > + svs->efuse[7] = 0xabfb217b; > > + svs->efuse[8] = 0x4bf34be1; > > + svs->efuse[9] = 0xabfb670d; > > + svs->efuse[16] = 0xabfbc653; > > + svs->efuse[17] = 0x47f347e1; > > + svs->efuse[18] = 0xabfbd848; > > + > > + svs->thermal_efuse[0] = 0x02873f69; > > + svs->thermal_efuse[1] = 0xa11d9142; > > + svs->thermal_efuse[2] = 0xa2526900; > > + } > > + > > + /* svs efuse parsing */ > > + ft_pgm = (svs->efuse[0] >> 4) & 0xf; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + if (ft_pgm <= 1) > > + svsb->init01_volt_flag = SVS_INIT01_VOLT_IGNORE; > > + > > + switch (svsb->sw_id) { > > + case SVS_CPU_LITTLE: > > + svsb->bdes = svs->efuse[16] & 0xff; > > + svsb->mdes = (svs->efuse[16] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[16] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[16] >> 24) & 0xff; > > + svsb->mtdes = (svs->efuse[17] >> 16) & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 10; > > + else > > + svsb->volt_offset += 2; > > + break; > > + case SVS_CPU_BIG: > > + svsb->bdes = svs->efuse[18] & 0xff; > > + svsb->mdes = (svs->efuse[18] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[18] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[18] >> 24) & 0xff; > > + svsb->mtdes = svs->efuse[17] & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 15; > > + else > > + svsb->volt_offset += 12; > > + break; > > + case SVS_CCI: > > + svsb->bdes = svs->efuse[4] & 0xff; > > + svsb->mdes = (svs->efuse[4] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[4] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[4] >> 24) & 0xff; > > + svsb->mtdes = (svs->efuse[5] >> 16) & 0xff; > > + > > + if (ft_pgm <= 3) > > + svsb->volt_offset += 10; > > + else > > + svsb->volt_offset += 2; > > + break; > > + case SVS_GPU: > > + svsb->bdes = svs->efuse[6] & 0xff; > > + svsb->mdes = (svs->efuse[6] >> 8) & 0xff; > > + svsb->dcbdet = (svs->efuse[6] >> 16) & 0xff; > > + svsb->dcmdet = (svs->efuse[6] >> 24) & 0xff; > > + svsb->mtdes = svs->efuse[5] & 0xff; > > + > > + if (ft_pgm >= 2) { > > + svsb->freq_base = 800000000; /* 800MHz */ > > + svsb->dvt_fixed = 2; > > + } > > + break; > > + default: > > + break; > > + } > > + } > > + > > + for (i = 0; i < svsp->efuse_num; i++) { > > + if (svs->efuse[i]) > > + pr_notice("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]); > > + } > > + > > + /* thermal efuse parsing */ > > + if (!svs->thermal_efuse) > > + return 0; > > + > > + tp.adc_ge_t = (svs->thermal_efuse[1] >> 22) & 0x3ff; > > + tp.adc_oe_t = (svs->thermal_efuse[1] >> 12) & 0x3ff; > > + > > + tp.o_vtsmcu1 = (svs->thermal_efuse[0] >> 17) & 0x1ff; > > + tp.o_vtsmcu2 = (svs->thermal_efuse[0] >> 8) & 0x1ff; > > + tp.o_vtsmcu3 = svs->thermal_efuse[1] & 0x1ff; > > + tp.o_vtsmcu4 = (svs->thermal_efuse[2] >> 23) & 0x1ff; > > + tp.o_vtsmcu5 = (svs->thermal_efuse[2] >> 5) & 0x1ff; > > + tp.o_vtsabb = (svs->thermal_efuse[2] >> 14) & 0x1ff; > > + > > + tp.degc_cali = (svs->thermal_efuse[0] >> 1) & 0x3f; > > + tp.adc_cali_en_t = svs->thermal_efuse[0] & BIT(0); > > + tp.o_slope_sign = (svs->thermal_efuse[0] >> 7) & BIT(0); > > + > > + tp.ts_id = (svs->thermal_efuse[1] >> 9) & BIT(0); > > + tp.o_slope = (svs->thermal_efuse[0] >> 26) & 0x3f; > > + > > + if (tp.adc_cali_en_t == 1) { > > + if (tp.ts_id == 0) > > + 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)) { > > + pr_err("bad thermal efuse data. disable mon mode\n"); > > + mon_mode_support = false; > > + } > > + } else { > > + pr_err("no thermal efuse data. disable mon mode\n"); > > + mon_mode_support = false; > > + } > > + > > + if (!mon_mode_support) { > > + for (i = 0; i < svsp->thermal_efuse_num; i++) > > + pr_err("thermal_efuse[%u] = 0x%08x\n", > > + i, svs->thermal_efuse[i]); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->mon_mode_support = false; > > + } > > + > > + return 0; > > + } > > + > > + 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 == 0) > > + 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 SVS_CPU_LITTLE: > > + tb_roomt = x_roomt[3]; > > + break; > > + case SVS_CPU_BIG: > > + tb_roomt = x_roomt[4]; > > + break; > > + case SVS_CCI: > > + tb_roomt = x_roomt[3]; > > + break; > > + case SVS_GPU: > > + tb_roomt = x_roomt[1]; > > + break; > > + default: > > + pr_err("unknown svsb_id = %u? disable svs\n", > > + svsb->sw_id); > > + return -EINVAL; > > + } > > + > > + temp0 = (tp.degc_cali * 10 / 2); > > + temp1 = ((10000 * 100000 / 4096 / tp.gain) * > > + tp.oe + tb_roomt * 10) * 15 / 18; > > + > > + if (tp.o_slope_sign == 0) > > + 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 0; > > +} > > + > > +static int svs_is_support(struct mtk_svs *svs) > > nit: this appears to be a check if the platform supports SVS. If so, > then it should probably be 'bool' and be called svs_is_supported(). bool/svs_is_supported are good ideas. I'll apply it in the next patch. Thanks. > > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct nvmem_cell *cell; > > + size_t len; > > + int ret; > > + u32 idx, i; > > + > > + if (svsp->fake_efuse) { > > + len = svsp->efuse_num * 4; > > + svs->efuse = kzalloc(len, GFP_KERNEL); > > + if (!svs->efuse) > > + return -ENOMEM; > > + > > + len = svsp->thermal_efuse_num * 4; > > + svs->thermal_efuse = kzalloc(len, GFP_KERNEL); > > + if (!svs->thermal_efuse) > > + return -ENOMEM; > > + > > + goto svsp_efuse_parsing; > > + } > > + > > + /* get svs efuse by nvmem */ > > + cell = nvmem_cell_get(svs->dev, "svs-calibration-data"); > > + if (IS_ERR(cell)) { > > + pr_err("no \"svs-calibration-data\" from dts? disable svs\n"); > > + return PTR_ERR(cell); > > + } > > + > > + svs->efuse = (u32 *)nvmem_cell_read(cell, &len); > > + nvmem_cell_put(cell); > > + > > + ret = (svs->efuse[svsp->efuse_check] == 0) ? -EPERM : 0; > > + if (ret) { > > + pr_err("no svs efuse. disable svs.\n"); > > + for (i = 0; i < svsp->efuse_num; i++) > > + pr_err("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]); > > + return ret; > > + } > > + > > + /* get thermal efuse by nvmem */ > > + cell = nvmem_cell_get(svs->dev, "calibration-data"); > > + if (IS_ERR(cell)) { > > + pr_err("no \"calibration-data\" from dts? disable mon mode\n"); > > + svs->thermal_efuse = NULL; > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->mon_mode_support = false; > > + } > > + goto svsp_efuse_parsing; > > + } > > + > > + svs->thermal_efuse = (u32 *)nvmem_cell_read(cell, &len); > > + nvmem_cell_put(cell); > > + > > +svsp_efuse_parsing: > > + ret = svsp->efuse_parsing(svs); > > + > > + return ret; > > +} > > + > > +static int svs_resource_setup(struct mtk_svs *svs) > > +{ > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + struct platform_device *pdev; > > + struct device_node *np = NULL; > > + struct dev_pm_opp *opp; > > + unsigned long freq; > > + size_t opp_size; > > + int count, ret; > > + u32 idx, i; > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + > > + if (!svsb->init01_support) > > + continue; > > + > > + switch (svsb->sw_id) { > > + case SVS_CPU_LITTLE: > > + svsb->name = "SVS_CPU_LITTLE"; > > + break; > > + case SVS_CPU_BIG: > > + svsb->name = "SVS_CPU_BIG"; > > + break; > > + case SVS_CCI: > > + svsb->name = "SVS_CCI"; > > + break; > > + case SVS_GPU: > > + svsb->name = "SVS_GPU"; > > + break; > > + default: > > + WARN_ON(1); > > + return -EINVAL; > > + } > > + > > + /* Add svs_bank device for opp-table/mtcmos/buck control */ > > + pdev = platform_device_alloc(svsb->name, 0); > > + if (!pdev) { > > + pr_err("%s: fail to alloc pdev for svs_bank\n", > > + svsb->name); > > + return -ENOMEM; > > + } > > + > > + for_each_child_of_node(svs->dev->of_node, np) { > > + if (of_device_is_compatible(np, svsb->of_compatible)) { > > + pdev->dev.of_node = np; > > + break; > > + } > > + } > > + > > + ret = platform_device_add(pdev); > > + if (ret) { > > + pr_err("%s: fail to add svs_bank device: %d\n", > > + svsb->name, ret); > > + return ret; > > + } > > + > > + svsb->dev = &pdev->dev; > > + dev_set_drvdata(svsb->dev, svs); > > + ret = dev_pm_opp_of_add_table(svsb->dev); > > + if (ret) { > > + pr_err("%s: fail to add opp table: %d\n", > > + svsb->name, ret); > > + return ret; > > + } > > + > > + mutex_init(&svsb->lock); > > + > > + svsb->buck = devm_regulator_get_optional(svsb->dev, > > + svsb->buck_name); > > + if (IS_ERR(svsb->buck)) { > > + pr_err("%s: cannot get regulator \"%s-supply\"\n", > > + svsb->name, svsb->buck_name); > > + return PTR_ERR(svsb->buck); > > + } > > + > > + count = dev_pm_opp_get_opp_count(svsb->dev); > > + if (svsb->opp_count != count) { > > + pr_err("%s: opp_count not \"%u\" but get \"%d\"?\n", > > + svsb->name, svsb->opp_count, count); > > + return count; > > + } > > + > > + opp_size = 4 * svsb->opp_count; > > + svsb->opp_volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->opp_volts) > > + return -ENOMEM; > > + > > + svsb->init02_volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->init02_volts) > > + return -ENOMEM; > > + > > + svsb->volts = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->volts) > > + return -ENOMEM; > > + > > + svsb->opp_freqs = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->opp_freqs) > > + return -ENOMEM; > > + > > + svsb->freqs_pct = kmalloc(opp_size, GFP_KERNEL); > > + if (!svsb->freqs_pct) > > + return -ENOMEM; > > + > > + for (i = 0, freq = (u32)-1; i < svsb->opp_count; i++, freq--) { > > + opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq); > > + if (IS_ERR(opp)) { > > + pr_err("%s: error opp entry!!, err = %ld\n", > > + svsb->name, 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) & 0xff; > > + } > > + } > > + > > + return 0; > > +} > > There are lots of resources (platform_device, all the kmalloc regions) > that are never free'd here. You might consider using devm for this. > > Related, all the small malloc's are calculated based on the opp_count > for each bank, but they are all hard-coded to 16. Seems it would be > better to have a default/max size for this in the bank structure itself > instead of making these small allocations. Thanks for the advices. The default/max size are good ideas. I'll apply it in the next patch. > > > +static int svs_suspend(struct device *dev) > > +{ > > + struct mtk_svs *svs = dev_get_drvdata(dev); > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + unsigned long flags; > > + u32 idx; > > + > > + /* Wait if there is processing svs_isr(). Suspend all banks. */ > > + flags = claim_mtk_svs_lock(); > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svs->bank = svsb; > > + svs_switch_bank(svs); > > + svs_writel(svs, 0x0, SVSEN); > > + svs_writel(svs, 0x00ffffff, INTSTS); > > I'm assuming this part will disable future interrupts? Yes, this for-loop will disable all the SVS banks' interrupts. > I'm not seeing where they get re-enabled on the resume path. In the svs_resume(), we re-run svs_init02() to enable each SVS bank. > > > > + svsb->suspended = true; > > + } > > + release_mtk_svs_lock(flags); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + if (svsb->phase == SVS_PHASE_MON) { > > + svsb->phase = SVS_PHASE_INIT02; > > + svs_set_volts(svsb, true); > > + } > > + } > > + > > + clk_disable_unprepare(svs->main_clk); > > + > > + return 0; > > +} > > + > > +static int svs_resume(struct device *dev) > > +{ > > + struct mtk_svs *svs = dev_get_drvdata(dev); > > + const struct svs_platform *svsp = svs->platform; > > + struct svs_bank *svsb; > > + int ret; > > + u32 idx; > > + > > + ret = clk_prepare_enable(svs->main_clk); > > + if (ret) > > + pr_err("%s(): cannot enable main_clk\n", __func__); > > + > > + for (idx = 0; idx < svsp->bank_num; idx++) { > > + svsb = &svsp->banks[idx]; > > + svsb->suspended = false; > > + } > > + > > + ret = svs_init02(svs); > > + if (ret) > > + return ret; > > + > > + svs_mon_mode(svs); > > + > > + return 0; > > +} > > Kevin _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel