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 Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4480AC43334 for ; Fri, 22 Jul 2022 20:03:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233737AbiGVUDl (ORCPT ); Fri, 22 Jul 2022 16:03:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59420 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229522AbiGVUDj (ORCPT ); Fri, 22 Jul 2022 16:03:39 -0400 Received: from aposti.net (aposti.net [89.234.176.197]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5A536796BB; Fri, 22 Jul 2022 13:03:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1658520211; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4GUlLQB0aPpv22nxPOF0z62UWHL5GT/zBSnJNV62yLM=; b=L5oYvEmgKCcill8Gw3llzkRidYXGlkDxgZrDHgOKCuBbTnQbyCwVpEoAiHrAz0zqm5BOzV kvNsGpdv1ZEkleMTqIY+hOXTZC6LIHVI8wh4tKGVQuTHv3ZKgzcPIDDWrdkY3vx7pLV1AE zsKODExZfc8vfL5pm0D6xUPO9u+6Ji4= Date: Fri, 22 Jul 2022 21:03:19 +0100 From: Paul Cercueil Subject: Re: [PATCH 3/3] SPI: Ingenic: Add SFC support for Ingenic SoCs. To: =?UTF-8?b?5ZGo55Cw5p2w?= Cc: tudor.ambarus@microchip.com, p.yadav@ti.com, michael@walle.cc, miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com, broonie@kernel.org, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, linux-mtd@lists.infradead.org, linux-spi@vger.kernel.org, linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, aidanmacdonald.0x0@gmail.com, tmn505@gmail.com, dongsheng.qiu@ingenic.com, aric.pzqi@ingenic.com, rick.tyliu@ingenic.com, jinghui.liu@ingenic.com, sernia.zhou@foxmail.com, reimu@sudomaker.com Message-Id: In-Reply-To: <1658508510-15400-4-git-send-email-zhouyanjie@wanyeetech.com> References: <1658508510-15400-1-git-send-email-zhouyanjie@wanyeetech.com> <1658508510-15400-4-git-send-email-zhouyanjie@wanyeetech.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Zhou, Le sam., juil. 23 2022 at 00:48:30 +0800, =E5=91=A8=E7=90=B0=E6=9D=B0 (Zhou= Yanjie)=20 a =C3=A9crit : > Add SFC support for the X1000 SoC, the X1600 SoC, and the X2000 SoC > from Ingenic. >=20 > Signed-off-by: =E5=91=A8=E7=90=B0=E6=9D=B0 (Zhou Yanjie) > --- > drivers/spi/Kconfig | 9 + > drivers/spi/Makefile | 1 + > drivers/spi/spi-ingenic-sfc.c | 662=20 > ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 672 insertions(+) > create mode 100644 drivers/spi/spi-ingenic-sfc.c >=20 > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 3b1044e..1077bd3 100644 > --- a/drivers/spi/Kconfig > +++ b/drivers/spi/Kconfig > @@ -437,6 +437,15 @@ config SPI_INGENIC > To compile this driver as a module, choose M here: the module > will be called spi-ingenic. >=20 > +config SPI_INGENIC_SFC > + tristate "Ingenic SoCs SPI Flash Controller" > + depends on MACH_INGENIC || COMPILE_TEST > + help > + This enables support for the Ingenic SoCs SPI flash controller. > + > + To compile this driver as a module, choose M here: the module > + will be called ingenic-sfc. > + > config SPI_INTEL > tristate >=20 > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index 0f44eb6..f3e42c0 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -62,6 +62,7 @@ obj-$(CONFIG_SPI_HISI_SFC_V3XX) +=3D=20 > spi-hisi-sfc-v3xx.o > obj-$(CONFIG_SPI_IMG_SPFI) +=3D spi-img-spfi.o > obj-$(CONFIG_SPI_IMX) +=3D spi-imx.o > obj-$(CONFIG_SPI_INGENIC) +=3D spi-ingenic.o > +obj-$(CONFIG_SPI_INGENIC_SFC) +=3D spi-ingenic-sfc.o > obj-$(CONFIG_SPI_INTEL) +=3D spi-intel.o > obj-$(CONFIG_SPI_INTEL_PCI) +=3D spi-intel-pci.o > obj-$(CONFIG_SPI_INTEL_PLATFORM) +=3D spi-intel-platform.o > diff --git a/drivers/spi/spi-ingenic-sfc.c=20 > b/drivers/spi/spi-ingenic-sfc.c > new file mode 100644 > index 00000000..a565546 > --- /dev/null > +++ b/drivers/spi/spi-ingenic-sfc.c > @@ -0,0 +1,662 @@ > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) Dual-license driver? That's not what MODULE_LICENSE() says. > +/* > + * Ingenic SoCs SPI Flash Controller Driver > + * Copyright (c) 2022 =E5=91=A8=E7=90=B0=E6=9D=B0 (Zhou Yanjie)=20 > > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* SFC register offsets */ > +#define SFC_REG_GLB 0x0000 > +#define SFC_REG_DEV_CONF 0x0004 > +#define SFC_REG_DEV_STA_EXP 0x0008 > +#define SFC_REG_DEV_STA_RT 0x000c > +#define SFC_REG_DEV_STA_MSK 0x0010 > +#define SFC_REG_TRAN_CONF(n) (0x0014 + n * 4) > +#define SFC_REG_TRAN_CFG0(n) (0x0014 + n * 4) You should protect the macro parameter. If you do for instance=20 SFC_REG_TRAN_CONF(x + 1) it would resolve to (0x0014 + x + 1 * 4) which=20 is not what you'd want. Also - looks like SFC_REG_TRAN_CONF() and SFC_REG_TRAN_CFG0() are the=20 same thing, that's on purpose? > +#define SFC_REG_TRAN_LEN 0x002c > +#define SFC_REG_DEV_ADDR(n) (0x0030 + n * 4) > +#define SFC_REG_DEV_ADDR_PLUS(n) (0x0048 + n * 4) > +#define SFC_REG_MEM_ADDR 0x0060 > +#define SFC_REG_TRIG 0x0064 > +#define SFC_REG_SR 0x0068 > +#define SFC_REG_SCR 0x006c > +#define SFC_REG_INTC 0x0070 > +#define SFC_REG_FSM 0x0074 > +#define SFC_REG_CGE 0x0078 > +#define SFC_REG_TRAN_CFG1(n) (0x009c + n * 4) > +#define SFC_REG_DR 0x1000 > + > +/* bits within the GLB register */ > +#define GLB_TRAN_DIR_MASK GENMASK(13, 13) > +#define GLB_TRAN_DIR_WRITE 0x1 > +#define GLB_TRAN_DIR_READ 0x0 When it's a single bit - just use BIT(). > +#define GLB_THRESHOLD_MASK GENMASK(12, 7) > +#define GLB_OP_MODE_MASK GENMASK(6, 6) Same here, and I see it a few times below as well. > +#define GLB_OP_MODE_DMA 0x1 > +#define GLB_OP_MODE_SLAVE 0x0 > +#define GLB_PHASE_NUM_MASK GENMASK(5, 3) > +#define GLB_WP_EN BIT(2) > +#define GLB_BURST_MD_MASK GENMASK(1, 0) > +#define GLB_BURST_MD_INCR32 0x3 > +#define GLB_BURST_MD_INCR16 0x2 > +#define GLB_BURST_MD_INCR8 0x1 > +#define GLB_BURST_MD_INCR4 0x0 > + > +/* bits within the DEV_CONF register */ > +#define DEV_CONF_SMP_DELAY_MASK GENMASK(20, 16) > +#define DEV_CONF_SMP_DELAY_180DEG 0x4 > +#define DEV_CONF_SMP_DELAY_HALF_CYCLE 0x1 > +#define DEV_CONF_CMD_TYPE_MASK GENMASK(15, 15) > +#define DEV_CONF_CMD_TYPE_16BIT 0x1 > +#define DEV_CONF_CMD_TYPE_8BIT 0x0 > +#define DEV_CONF_STA_TYPE_MASK GENMASK(14, 13) > +#define DEV_CONF_THOLD_MASK GENMASK(12, 11) > +#define DEV_CONF_TSETUP_MASK GENMASK(10, 9) > +#define DEV_CONF_TSH_MASK GENMASK(8, 5) > +#define DEV_CONF_CPHA BIT(4) > +#define DEV_CONF_CPOL BIT(3) > +#define DEV_CONF_CE_DL BIT(2) > +#define DEV_CONF_HOLD_DL BIT(1) > +#define DEV_CONF_WP_DL BIT(0) > + > +/* bits within the TRAN_CONF(n) register */ > +#define TRAN_CONF_TRAN_MODE_MASK GENMASK(31, 29) > +#define TRAN_CONF_ADDR_WIDTH_MASK GENMASK(28, 26) > +#define TRAN_CONF_POLL_EN BIT(25) > +#define TRAN_CONF_CMD_EN BIT(24) > +#define TRAN_CONF_PHASE_FORMAT_MASK GENMASK(23, 23) > +#define TRAN_CONF_DMY_BITS_MASK GENMASK(22, 17) > +#define TRAN_CONF_DATA_EN BIT(16) > +#define TRAN_CONF_CMD_MASK GENMASK(15, 0) > + > +/* bits within the TRIG register */ > +#define TRIG_FLUSH BIT(2) > +#define TRIG_STOP BIT(1) > +#define TRIG_START BIT(0) > + > +/* bits within the SR register */ > +#define SR_FIFO_NUM_MASK GENMASK(22, 16) > +#define SR_END BIT(4) > +#define SR_TRAN_REQ BIT(3) > +#define SR_RECE_REQ BIT(2) > +#define SR_OVER BIT(1) > +#define SR_UNDER BIT(0) > + > +/* bits within the SCR register */ > +#define SCR_CLR_END BIT(4) > +#define SCR_CLR_TREQ BIT(3) > +#define SCR_CLR_RREQ BIT(2) > +#define SCR_CLR_OVER BIT(1) > +#define SCR_CLR_UNDER BIT(0) > + > +/* bits within the INTC register */ > +#define INTC_MASK_END BIT(4) > +#define INTC_MASK_TREQ BIT(3) > +#define INTC_MASK_RREQ BIT(2) > +#define INTC_MASK_OVER BIT(1) > +#define INTC_MASK_UNDER BIT(0) > + > +/* bits within the TRAN_CFG1(n) register */ > +#define TRAN_CFG1_TRAN_MODE_MASK GENMASK(7, 4) > + > +#define TRAN_MODE_STANDARD 0 > +#define TRAN_MODE_DUAL_DATA 1 > +#define TRAN_MODE_DUAL_IO 2 > +#define TRAN_MODE_DUAL_FULL 3 > +#define TRAN_MODE_QUAD_DATA 5 > +#define TRAN_MODE_QUAD_IO 6 > +#define TRAN_MODE_QUAD_FULL 7 > +#define TRAN_MODE_OCTAL_DATA 9 > +#define TRAN_MODE_OCTAL_IO 10 > +#define TRAN_MODE_OCTAL_FULL 11 > + > +#define INGENIC_SFC_FIFO_SIZE (64 * 4) > + > +#define INGENIC_SFC_TRANSFER_TIMEOUT 1000 Maybe add the unit name in the macro as well -=20 INGENIC_SFC_TRANSFER_TIMEOUT_MS. > + > +enum ingenic_sfc_version { > + ID_X1000, > + ID_X1600, > + ID_X2000, > +}; > + > +struct ingenic_soc_info { > + enum ingenic_sfc_version version; > + > + unsigned int max_bus_width; > + > + const u32 tran_mode_mask; > +}; > + > +struct ingenic_sfc { > + const struct ingenic_soc_info *soc_info; > + > + void __iomem *base; > + struct device *dev; > + struct clk *clk; > + int irq; > + > + struct completion completion; > +}; > + > +static irqreturn_t ingenic_sfc_irq_handler(int irq, void *data) > +{ > + struct ingenic_sfc *sfc =3D data; > + > + writel(0x1f, sfc->base + SFC_REG_INTC); > + > + complete(&sfc->completion); > + > + return IRQ_HANDLED; > +} > + > +static int ingenic_sfc_adjust_op_size(struct spi_mem *mem, struct=20 > spi_mem_op *op) > +{ > + uintptr_t addr =3D (uintptr_t)op->data.buf.in; > + > + if (op->data.nbytes > INGENIC_SFC_FIFO_SIZE && !IS_ALIGNED(addr, 4)) > + op->data.nbytes =3D INGENIC_SFC_FIFO_SIZE; > + > + return 0; > +} > + > +static bool ingenic_sfc_supports_op(struct spi_mem *mem, const=20 > struct spi_mem_op *op) > +{ > + struct spi_device *spi =3D mem->spi; > + struct ingenic_sfc *sfc =3D spi_controller_get_devdata(spi->master); > + uintptr_t addr =3D (uintptr_t)op->data.buf.in; > + > + /* The controller only supports Standard SPI mode, Duall mode, Quad=20 > mode and Octal mode. */ Dual* > + if (op->cmd.buswidth > sfc->soc_info->max_bus_width || > + op->addr.buswidth > sfc->soc_info->max_bus_width || > + op->dummy.buswidth > sfc->soc_info->max_bus_width || > + op->data.buswidth > sfc->soc_info->max_bus_width) > + return false; > + > + /* Max 32 dummy clock cycles supported */ > + if (op->dummy.nbytes && op->dummy.nbytes * 8 / op->dummy.buswidth >=20 > 32) > + return false; > + > + /* Max rx data length, check controller limits and alignment */ > + if (op->data.dir =3D=3D SPI_MEM_DATA_IN && > + op->data.nbytes > INGENIC_SFC_FIFO_SIZE && !IS_ALIGNED(addr, 4)) This does the same check than in ingenic_sfc_adjust_op_size(), maybe=20 move it to a new inline function? > + return false; > + > + /* Max 6 bytes address width supported */ > + if (op->addr.nbytes > 6) > + return false; > + > + return spi_mem_default_supports_op(mem, op); > +} > + > +static void ingenic_sfc_set_transfer_mode(struct ingenic_sfc *sfc,=20 > const struct spi_mem_op *op) > +{ > + int val; > + > + val =3D readl(sfc->base + (sfc->soc_info->version >=3D ID_X1600 ? > + SFC_REG_TRAN_CFG1(0) : SFC_REG_TRAN_CONF(0))); As Krzysztof said - ugh. Also, instead of having a "version" enum in your soc_info, why not just=20 have a "reg_conf" field that gives you directly the right register? > + val &=3D ~sfc->soc_info->tran_mode_mask; > + if (op->cmd.buswidth =3D=3D 8) > + val |=3D (TRAN_MODE_OCTAL_FULL <<=20 > (ffs(sfc->soc_info->tran_mode_mask) - 1)) & > + sfc->soc_info->tran_mode_mask; Looks like you're really trying to reinvent the wheel. val |=3D FIELD_PREP(sfc->soc_info->tran_mode_mask, TRAN_MODE_OCTAL_FULL); using . Also, just define a 'mode' variable and set it in your if/else blocks,=20 that would look much better. Then you can set val |=3D FIELD_PREP(...,=20 mode) at the end. > + else if (op->cmd.buswidth =3D=3D 4) > + val |=3D (TRAN_MODE_QUAD_FULL << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->cmd.buswidth =3D=3D 2) > + val |=3D (TRAN_MODE_DUAL_FULL << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->addr.buswidth =3D=3D 8) > + val |=3D (TRAN_MODE_OCTAL_IO << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->addr.buswidth =3D=3D 4) > + val |=3D (TRAN_MODE_QUAD_IO << (ffs(sfc->soc_info->tran_mode_mask) -=20 > 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->addr.buswidth =3D=3D 2) > + val |=3D (TRAN_MODE_DUAL_IO << (ffs(sfc->soc_info->tran_mode_mask) -=20 > 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->data.buswidth =3D=3D 8) > + val |=3D (TRAN_MODE_OCTAL_DATA <<=20 > (ffs(sfc->soc_info->tran_mode_mask) - 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->data.buswidth =3D=3D 4) > + val |=3D (TRAN_MODE_QUAD_DATA << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + else if (op->data.buswidth =3D=3D 2) > + val |=3D (TRAN_MODE_DUAL_DATA << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + else > + val |=3D (TRAN_MODE_STANDARD << (ffs(sfc->soc_info->tran_mode_mask)=20 > - 1)) & > + sfc->soc_info->tran_mode_mask; > + writel(val, sfc->base + (sfc->soc_info->version >=3D ID_X1600 ? > + SFC_REG_TRAN_CFG1(0) : SFC_REG_TRAN_CONF(0))); > +} > + > +/* > + * We only need PIO mode to handle the SPI_MEM_NO_DATA transfers, > + * and the unaligned accesses in SPI_MEM_DATA_IN transfers. > + */ > +static void ingenic_sfc_read_rxfifo(struct ingenic_sfc *sfc, u8 *to,=20 > unsigned int len) > +{ > + void __iomem *from; > + > + from =3D sfc->base + SFC_REG_DR; > + > + for (; len >=3D 4; len -=3D 4, to +=3D 4) { > + u32 val =3D __raw_readl(from); > + memcpy(to, &val, 4); No need to use memcpy for 4 bytes. You can do: put_unaligned(val, (u32=20 *)to); > + } > + > + if (len) { > + u32 val =3D __raw_readl(from); > + memcpy(to, &val, len); Hmm, I'm not sure that is endian-safe. I would prefer if you copied=20 byte by byte. > + } > +} > + > +static int ingenic_sfc_exec_op_pio(struct ingenic_sfc *sfc, const=20 > struct spi_mem_op *op) > +{ > + int ret, val; > + > + val =3D readl(sfc->base + SFC_REG_GLB); > + u32p_replace_bits(&val, GLB_TRAN_DIR_READ, GLB_TRAN_DIR_MASK); > + u32p_replace_bits(&val, GLB_OP_MODE_SLAVE, GLB_OP_MODE_MASK); > + writel(val, sfc->base + SFC_REG_GLB); By the way, have you considered using regmap? It would give you things like regmap_update_bits() for this kind of=20 things, and regmap_field() to handle your conf register being at a=20 different address across SoCs. > + > + val =3D TRAN_CONF_CMD_EN | op->cmd.opcode; > + > + if (op->addr.nbytes > 0) { > + val |=3D FIELD_PREP(TRAN_CONF_ADDR_WIDTH_MASK, op->addr.nbytes); > + > + writel(op->addr.val & 0xffffffff, sfc->base + SFC_REG_DEV_ADDR(0)); > + writel(op->addr.val >> 32, sfc->base + SFC_REG_DEV_ADDR_PLUS(0)); > + } > + > + if (op->dummy.nbytes > 0) > + val |=3D FIELD_PREP(TRAN_CONF_DMY_BITS_MASK, > + op->dummy.nbytes * 8 / op->dummy.buswidth); > + > + if (op->data.nbytes > 0) > + val |=3D TRAN_CONF_DATA_EN; > + > + writel(val, sfc->base + SFC_REG_TRAN_CONF(0)); > + writel(op->data.nbytes, sfc->base + SFC_REG_TRAN_LEN); > + > + ingenic_sfc_set_transfer_mode(sfc, op); > + > + writel(0x1f, sfc->base + SFC_REG_SCR); Random 0x1f value here, maybe use a macro? > + writel(~(INTC_MASK_END | INTC_MASK_RREQ), sfc->base + SFC_REG_INTC); > + > + writel(0, sfc->base + SFC_REG_MEM_ADDR); > + > + writel(TRIG_FLUSH, sfc->base + SFC_REG_TRIG); > + writel(TRIG_START, sfc->base + SFC_REG_TRIG); > + > + ret =3D wait_for_completion_timeout(&sfc->completion, > + msecs_to_jiffies(INGENIC_SFC_TRANSFER_TIMEOUT)); > + if (!ret) { > + writel(0x1f, sfc->base + SFC_REG_INTC); > + writel(0x1f, sfc->base + SFC_REG_SCR); > + dev_err(sfc->dev, "line:%d Timeout for ACK from SFC device\n",=20 > __LINE__); > + return -ETIMEDOUT; > + } > + > + ingenic_sfc_read_rxfifo(sfc, op->data.buf.in, op->data.nbytes); > + readl_poll_timeout(sfc->base + SFC_REG_SR, val, val & SR_END, 10,=20 > 0); Infinite timeout? Is that very wise? > + > + writel(INTC_MASK_END | INTC_MASK_RREQ, sfc->base + SFC_REG_SCR); > + writel(TRIG_STOP, sfc->base + SFC_REG_TRIG); > + > + return 0; > +} > + > +static int ingenic_sfc_exec_op_dma(struct ingenic_sfc *sfc, const=20 > struct spi_mem_op *op) > +{ > + dma_addr_t addr; > + int ret, val; > + > + val =3D readl(sfc->base + SFC_REG_GLB); > + u32p_replace_bits(&val, op->data.dir =3D=3D SPI_MEM_DATA_IN ? > + GLB_TRAN_DIR_READ : GLB_TRAN_DIR_WRITE, GLB_TRAN_DIR_MASK); > + u32p_replace_bits(&val, GLB_OP_MODE_DMA, GLB_OP_MODE_MASK); > + writel(val, sfc->base + SFC_REG_GLB); > + > + val =3D TRAN_CONF_CMD_EN | op->cmd.opcode; > + > + if (op->addr.nbytes > 0) { > + val |=3D FIELD_PREP(TRAN_CONF_ADDR_WIDTH_MASK, op->addr.nbytes); > + writel(op->addr.val & 0xffffffff, sfc->base + SFC_REG_DEV_ADDR(0)); > + writel(op->addr.val >> 32, sfc->base + SFC_REG_DEV_ADDR_PLUS(0)); > + } > + > + if (op->dummy.nbytes > 0) > + val |=3D FIELD_PREP(TRAN_CONF_DMY_BITS_MASK, > + op->dummy.nbytes * 8 / op->dummy.buswidth); > + > + if (op->data.nbytes > 0) > + val |=3D TRAN_CONF_DATA_EN; There's a lot of code duplication here with ingenic_sfc_exec_op_pio().=20 A lot can be factorized. > + > + writel(val, sfc->base + SFC_REG_TRAN_CONF(0)); > + writel(op->data.nbytes, sfc->base + SFC_REG_TRAN_LEN); > + > + ingenic_sfc_set_transfer_mode(sfc, op); > + > + writel(0x1f, sfc->base + SFC_REG_SCR); > + writel(~INTC_MASK_END, sfc->base + SFC_REG_INTC); > + > + switch (op->data.dir) { > + case SPI_MEM_DATA_IN: > + addr =3D dma_map_single(sfc->dev, op->data.buf.in, op->data.nbytes,=20 > DMA_FROM_DEVICE); > + if (dma_mapping_error(sfc->dev, addr)) { > + dev_err(sfc->dev, "RX DMA=E3=80=80memory not mapped\n"); > + return -ENOMEM; > + } > + > + writel(addr, sfc->base + SFC_REG_MEM_ADDR); > + break; > + > + case SPI_MEM_DATA_OUT: > + addr =3D dma_map_single(sfc->dev, (void *)op->data.buf.out, > + op->data.nbytes, DMA_TO_DEVICE); > + if (dma_mapping_error(sfc->dev, addr)) { > + dev_err(sfc->dev, "TX DMA=E3=80=80memory not mapped\n"); > + return -ENOMEM; > + } > + > + writel(addr, sfc->base + SFC_REG_MEM_ADDR); > + break; > + > + default: > + return -EINVAL; > + } > + > + writel(TRIG_START, sfc->base + SFC_REG_TRIG); > + > + ret =3D wait_for_completion_timeout(&sfc->completion, > + msecs_to_jiffies(INGENIC_SFC_TRANSFER_TIMEOUT)); > + if (!ret) { > + writel(0x1f, sfc->base + SFC_REG_INTC); > + writel(0x1f, sfc->base + SFC_REG_SCR); > + dev_err(sfc->dev, "line:%d Timeout for ACK from SFC device\n",=20 > __LINE__); > + return -ETIMEDOUT; > + } > + > + dma_unmap_single(sfc->dev, addr, op->data.nbytes, > + op->data.dir =3D=3D SPI_MEM_DATA_IN ? DMA_FROM_DEVICE :=20 > DMA_TO_DEVICE); Use a small inline function for that too. My personal rule is that ?:=20 is fine if the line fits in 80 characters, but if you have to break,=20 then you really need to move it somewhere else. > + > + writel(INTC_MASK_END, sfc->base + SFC_REG_SCR); > + writel(TRIG_STOP, sfc->base + SFC_REG_TRIG); > + > + return 0; > +} > + > +static int ingenic_sfc_exec_op(struct spi_mem *mem, const struct=20 > spi_mem_op *op) > +{ > + struct spi_device *spi =3D mem->spi; > + struct ingenic_sfc *sfc =3D spi_controller_get_devdata(spi->master); > + uintptr_t addr =3D (uintptr_t)op->data.buf.in; > + > + init_completion(&sfc->completion); > + > + switch (op->data.dir) { > + case SPI_MEM_DATA_IN: > + if (sfc->soc_info->version >=3D ID_X1600 || IS_ALIGNED(addr, 4)) > + break; > + > + fallthrough; > + > + case SPI_MEM_NO_DATA: > + return ingenic_sfc_exec_op_pio(sfc, op); > + > + default: > + break; > + } > + > + return ingenic_sfc_exec_op_dma(sfc, op); > +} > + > +static int ingenic_sfc_poll_status(struct spi_mem *mem, const struct=20 > spi_mem_op *op, > + u16 mask, u16 match, unsigned long initial_delay_us, > + unsigned long polling_delay_us, unsigned long timeout_ms) > +{ > + struct spi_device *spi =3D mem->spi; > + struct ingenic_sfc *sfc =3D spi_controller_get_devdata(spi->master); > + int ret, val; > + > + init_completion(&sfc->completion); > + > + val =3D readl(sfc->base + SFC_REG_GLB); > + u32p_replace_bits(&val, GLB_TRAN_DIR_READ, GLB_TRAN_DIR_MASK); > + u32p_replace_bits(&val, GLB_OP_MODE_SLAVE, GLB_OP_MODE_MASK); > + writel(val, sfc->base + SFC_REG_GLB); > + > + writel(match, sfc->base + SFC_REG_DEV_STA_EXP); > + writel(mask, sfc->base + SFC_REG_DEV_STA_MSK); > + > + val =3D TRAN_CONF_POLL_EN | TRAN_CONF_CMD_EN | op->cmd.opcode; > + > + if (op->addr.nbytes > 0) { > + val |=3D FIELD_PREP(TRAN_CONF_ADDR_WIDTH_MASK, op->addr.nbytes); > + > + writel(op->addr.val & 0xffffffff, sfc->base + SFC_REG_DEV_ADDR(0)); > + writel(op->addr.val >> 32, sfc->base + SFC_REG_DEV_ADDR_PLUS(0)); > + } > + > + if (op->dummy.nbytes > 0) > + val |=3D FIELD_PREP(TRAN_CONF_DMY_BITS_MASK, > + op->dummy.nbytes * 8 / op->dummy.buswidth); > + > + if (op->data.nbytes > 0) > + val |=3D TRAN_CONF_DATA_EN; > + > + writel(val, sfc->base + SFC_REG_TRAN_CONF(0)); > + writel(op->data.nbytes, sfc->base + SFC_REG_TRAN_LEN); > + > + ingenic_sfc_set_transfer_mode(sfc, op); > + > + writel(0x1f, sfc->base + SFC_REG_SCR); > + writel(~INTC_MASK_END, sfc->base + SFC_REG_INTC); > + > + writel(0, sfc->base + SFC_REG_MEM_ADDR); > + > + writel(TRIG_START, sfc->base + SFC_REG_TRIG); > + > + ret =3D wait_for_completion_timeout(&sfc->completion, > + msecs_to_jiffies(INGENIC_SFC_TRANSFER_TIMEOUT)); > + if (!ret) { > + writel(0x1f, sfc->base + SFC_REG_INTC); > + writel(0x1f, sfc->base + SFC_REG_SCR); > + dev_err(sfc->dev, "line:%d Timeout for ACK from SFC device\n",=20 > __LINE__); > + return -ETIMEDOUT; > + } > + > + writel(SCR_CLR_END, sfc->base + SFC_REG_SCR); > + writel(TRIG_STOP, sfc->base + SFC_REG_TRIG); > + > + return 0; > +} > + > +static const struct spi_controller_mem_ops ingenic_sfc_mem_ops =3D { > + .adjust_op_size =3D ingenic_sfc_adjust_op_size, > + .supports_op =3D ingenic_sfc_supports_op, > + .exec_op =3D ingenic_sfc_exec_op, > + .poll_status =3D ingenic_sfc_poll_status, > +}; > + > +static int ingenic_sfc_setup(struct spi_device *spi) > +{ > + struct ingenic_sfc *sfc =3D spi_controller_get_devdata(spi->master); > + unsigned long rate; > + int ret, val; > + > + if (!spi->max_speed_hz) > + return -EINVAL; Maybe set a sane default? > + > + ret =3D clk_set_rate(sfc->clk, spi->max_speed_hz * 2); > + if (ret) > + return -EINVAL; > + > + writel(TRIG_STOP, sfc->base + SFC_REG_TRIG); > + writel(0, sfc->base + SFC_REG_DEV_CONF); > + writel(0, sfc->base + SFC_REG_CGE); > + > + val =3D readl(sfc->base + SFC_REG_GLB); > + u32p_replace_bits(&val, 64 - 1, GLB_THRESHOLD_MASK); > + writel(val, sfc->base + SFC_REG_GLB); > + > + val =3D readl(sfc->base + SFC_REG_DEV_CONF); > + > + /* cpha bit:0 , cpol bit:0 */ > + val &=3D ~(DEV_CONF_CPHA | DEV_CONF_CPOL); > + val |=3D spi->mode & SPI_CPHA ? DEV_CONF_CPHA : 0; > + val |=3D spi->mode & SPI_CPOL ? DEV_CONF_CPOL : 0; > + > + /* ce_dl bit:1, hold bit:1, wp bit:1 */ > + val |=3D (DEV_CONF_CE_DL | DEV_CONF_HOLD_DL | DEV_CONF_WP_DL); > + > + writel(val, sfc->base + SFC_REG_DEV_CONF); > + > + val =3D readl(sfc->base + SFC_REG_GLB); > + u32p_replace_bits(&val, GLB_OP_MODE_SLAVE, GLB_OP_MODE_MASK); > + writel(val, sfc->base + SFC_REG_GLB); > + > + rate =3D clk_get_rate(sfc->clk); I'd suggest using clk_round_rate() before clk_set_rate() because then=20 you know what frequency it's going to be, and you don't have to call=20 clk_get_rate() afterwards. Cheers, -Paul > + val =3D readl(sfc->base + SFC_REG_DEV_CONF); > + if (sfc->soc_info->version >=3D ID_X1600 && rate >=3D 200000000) > + u32p_replace_bits(&val, DEV_CONF_SMP_DELAY_180DEG,=20 > DEV_CONF_SMP_DELAY_MASK); > + else if (sfc->soc_info->version =3D=3D ID_X1000 && rate >=3D 100000000) > + u32p_replace_bits(&val, DEV_CONF_SMP_DELAY_HALF_CYCLE,=20 > DEV_CONF_SMP_DELAY_MASK); > + writel(val, sfc->base + SFC_REG_DEV_CONF); > + > + return 0; > +} > + > +static int ingenic_sfc_probe(struct platform_device *pdev) > +{ > + struct ingenic_sfc *sfc; > + struct spi_controller *ctlr; > + int ret; > + > + ctlr =3D spi_alloc_master(&pdev->dev, sizeof(*sfc)); > + if (!ctlr) > + return -ENOMEM; > + > + sfc =3D spi_controller_get_devdata(ctlr); > + > + sfc->soc_info =3D of_device_get_match_data(&pdev->dev); > + if (!sfc->soc_info) { > + dev_err(&pdev->dev, "No of match data provided\n"); > + ret =3D -ENODEV; > + goto err_put_master; > + } > + > + sfc->base =3D devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(sfc->base)) { > + ret =3D PTR_ERR(sfc->base); > + goto err_put_master; > + } > + > + sfc->clk =3D devm_clk_get(&pdev->dev, "sfc"); > + if (IS_ERR(sfc->clk)) { > + ret =3D IS_ERR(sfc->clk); > + goto err_put_master; > + } > + > + ret =3D clk_prepare_enable(sfc->clk); > + if (ret) > + goto err_put_master; > + > + sfc->irq =3D platform_get_irq(pdev, 0); > + if (sfc->irq < 0) { > + ret =3D sfc->irq; > + goto err_put_master; > + } > + > + sfc->dev =3D &pdev->dev; > + > + platform_set_drvdata(pdev, sfc); > + > + ret =3D devm_request_irq(&pdev->dev, sfc->irq,=20 > ingenic_sfc_irq_handler, 0, > + dev_name(&pdev->dev), sfc); > + if (ret) { > + dev_err(&pdev->dev, "Failed to request irq%d, ret =3D %d\n",=20 > sfc->irq, ret); > + goto err_put_master; > + } > + > + ctlr->bus_num =3D -1; > + ctlr->num_chipselect =3D 1; > + ctlr->mem_ops =3D &ingenic_sfc_mem_ops; > + ctlr->dev.of_node =3D pdev->dev.of_node; > + ctlr->setup =3D ingenic_sfc_setup; > + ctlr->mode_bits =3D SPI_CPHA | SPI_CPOL | > + SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; > + if (sfc->soc_info->version >=3D ID_X2000) > + ctlr->mode_bits |=3D SPI_RX_OCTAL | SPI_TX_OCTAL; > + > + ret =3D devm_spi_register_controller(&pdev->dev, ctlr); > + if (ret) > + goto err_put_master; > + > + return 0; > + > +err_put_master: > + spi_master_put(ctlr); > + > + return ret; > +} > + > +static const struct ingenic_soc_info x1000_soc_info =3D { > + .version =3D ID_X1000, > + > + .max_bus_width =3D 4, > + > + .tran_mode_mask =3D TRAN_CONF_TRAN_MODE_MASK, > +}; > + > +static const struct ingenic_soc_info x1600_soc_info =3D { > + .version =3D ID_X1600, > + > + .max_bus_width =3D 4, > + > + .tran_mode_mask =3D TRAN_CONF_TRAN_MODE_MASK, > +}; > + > +static const struct ingenic_soc_info x2000_soc_info =3D { > + .version =3D ID_X2000, > + > + .max_bus_width =3D 8, > + > + .tran_mode_mask =3D TRAN_CFG1_TRAN_MODE_MASK, > +}; > + > +static const struct of_device_id ingenic_sfc_of_matches[] =3D { > + { .compatible =3D "ingenic,x1000-sfc", .data =3D &x1000_soc_info }, > + { .compatible =3D "ingenic,x1600-sfc", .data =3D &x1600_soc_info }, > + { .compatible =3D "ingenic,x2000-sfc", .data =3D &x2000_soc_info }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, ingenic_sfc_of_matches); > + > +static struct platform_driver ingenic_sfc_driver =3D { > + .driver =3D { > + .name =3D "ingenic-sfc", > + .of_match_table =3D ingenic_sfc_of_matches, > + }, > + .probe =3D ingenic_sfc_probe, > +}; > +module_platform_driver(ingenic_sfc_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("=E5=91=A8=E7=90=B0=E6=9D=B0 (Zhou Yanjie) "); > +MODULE_DESCRIPTION("Ingenic SoCs SPI Flash Controller Driver"); > -- > 2.7.4 >=20 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 8576CC433EF for ; Fri, 22 Jul 2022 20:04:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:Content-Type: Content-Transfer-Encoding:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Cc:To :Subject:From:Date:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=00ERRcoYMrrPOqbxu8BEb4+s+jCBVaZzsyWpVv7i96Q=; b=Halyfx31hFAb7TvVIYM9TO7VHg f5WAtSGhw8Dzve1nA1AmRAlZjCCTTdlGXc3+i8Xx2wX8kaPoFjqtXEXynGEPDzb3J8b1wA4D8XX2+ 9rUQnC5tnppNNTKQQnIqmHP4NSqAG8BB+EteiAM5OV8MJzJ46aEapYC5guf4kM2yeSrARHAcOZOeV tfaZR/nRfBrn99iQtj2i03nNf+BASS6INiOlPrVeyiYRxH05Jx7FCnCivTsSb2VCUs1U/aZ92aKUS ZTOj++LWsYq4UxQREf4InAKvlYSi0W8AkPCHd770qEGM4cs1hi9Kqa6U5j1vAyZNJ3eGBpIDhG+5e fWT1f2hg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oEysC-009hFA-WF; Fri, 22 Jul 2022 20:03:45 +0000 Received: from aposti.net ([89.234.176.197]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1oEys8-009h89-Dh for linux-mtd@lists.infradead.org; Fri, 22 Jul 2022 20:03:43 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1658520211; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4GUlLQB0aPpv22nxPOF0z62UWHL5GT/zBSnJNV62yLM=; b=L5oYvEmgKCcill8Gw3llzkRidYXGlkDxgZrDHgOKCuBbTnQbyCwVpEoAiHrAz0zqm5BOzV kvNsGpdv1ZEkleMTqIY+hOXTZC6LIHVI8wh4tKGVQuTHv3ZKgzcPIDDWrdkY3vx7pLV1AE zsKODExZfc8vfL5pm0D6xUPO9u+6Ji4= Date: Fri, 22 Jul 2022 21:03:19 +0100 From: Paul Cercueil Subject: Re: [PATCH 3/3] SPI: Ingenic: Add SFC support for Ingenic SoCs. To: =?UTF-8?b?5ZGo55Cw5p2w?= Cc: tudor.ambarus@microchip.com, p.yadav@ti.com, michael@walle.cc, miquel.raynal@bootlin.com, richard@nod.at, vigneshr@ti.com, broonie@kernel.org, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, linux-mtd@lists.infradead.org, linux-spi@vger.kernel.org, linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, aidanmacdonald.0x0@gmail.com, tmn505@gmail.com, dongsheng.qiu@ingenic.com, aric.pzqi@ingenic.com, rick.tyliu@ingenic.com, jinghui.liu@ingenic.com, sernia.zhou@foxmail.com, reimu@sudomaker.com Message-Id: In-Reply-To: <1658508510-15400-4-git-send-email-zhouyanjie@wanyeetech.com> References: <1658508510-15400-1-git-send-email-zhouyanjie@wanyeetech.com> <1658508510-15400-4-git-send-email-zhouyanjie@wanyeetech.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220722_130340_920073_9288F6E8 X-CRM114-Status: GOOD ( 32.93 ) X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: base64 Content-Type: text/plain; charset="utf-8"; Format="flowed" Sender: "linux-mtd" Errors-To: linux-mtd-bounces+linux-mtd=archiver.kernel.org@lists.infradead.org SGkgWmhvdSwKCgpMZSBzYW0uLCBqdWlsLiAyMyAyMDIyIGF0IDAwOjQ4OjMwICswODAwLCDlkajn kLDmnbAgKFpob3UgWWFuamllKSAKPHpob3V5YW5qaWVAd2FueWVldGVjaC5jb20+IGEgw6ljcml0 IDoKPiBBZGQgU0ZDIHN1cHBvcnQgZm9yIHRoZSBYMTAwMCBTb0MsIHRoZSBYMTYwMCBTb0MsIGFu ZCB0aGUgWDIwMDAgU29DCj4gZnJvbSBJbmdlbmljLgo+IAo+IFNpZ25lZC1vZmYtYnk6IOWRqOeQ sOadsCAoWmhvdSBZYW5qaWUpIDx6aG91eWFuamllQHdhbnllZXRlY2guY29tPgo+IC0tLQo+ICBk cml2ZXJzL3NwaS9LY29uZmlnICAgICAgICAgICB8ICAgOSArCj4gIGRyaXZlcnMvc3BpL01ha2Vm aWxlICAgICAgICAgIHwgICAxICsKPiAgZHJpdmVycy9zcGkvc3BpLWluZ2VuaWMtc2ZjLmMgfCA2 NjIgCj4gKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCj4gIDMgZmls ZXMgY2hhbmdlZCwgNjcyIGluc2VydGlvbnMoKykKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZl cnMvc3BpL3NwaS1pbmdlbmljLXNmYy5jCj4gCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvc3BpL0tj b25maWcgYi9kcml2ZXJzL3NwaS9LY29uZmlnCj4gaW5kZXggM2IxMDQ0ZS4uMTA3N2JkMyAxMDA2 NDQKPiAtLS0gYS9kcml2ZXJzL3NwaS9LY29uZmlnCj4gKysrIGIvZHJpdmVycy9zcGkvS2NvbmZp Zwo+IEBAIC00MzcsNiArNDM3LDE1IEBAIGNvbmZpZyBTUElfSU5HRU5JQwo+ICAJICBUbyBjb21w aWxlIHRoaXMgZHJpdmVyIGFzIGEgbW9kdWxlLCBjaG9vc2UgTSBoZXJlOiB0aGUgbW9kdWxlCj4g IAkgIHdpbGwgYmUgY2FsbGVkIHNwaS1pbmdlbmljLgo+IAo+ICtjb25maWcgU1BJX0lOR0VOSUNf U0ZDCj4gKwl0cmlzdGF0ZSAiSW5nZW5pYyBTb0NzIFNQSSBGbGFzaCBDb250cm9sbGVyIgo+ICsJ ZGVwZW5kcyBvbiBNQUNIX0lOR0VOSUMgfHwgQ09NUElMRV9URVNUCj4gKwloZWxwCj4gKwkgIFRo aXMgZW5hYmxlcyBzdXBwb3J0IGZvciB0aGUgSW5nZW5pYyBTb0NzIFNQSSBmbGFzaCBjb250cm9s bGVyLgo+ICsKPiArCSAgVG8gY29tcGlsZSB0aGlzIGRyaXZlciBhcyBhIG1vZHVsZSwgY2hvb3Nl IE0gaGVyZTogdGhlIG1vZHVsZQo+ICsJICB3aWxsIGJlIGNhbGxlZCBpbmdlbmljLXNmYy4KPiAr Cj4gIGNvbmZpZyBTUElfSU5URUwKPiAgCXRyaXN0YXRlCj4gCj4gZGlmZiAtLWdpdCBhL2RyaXZl cnMvc3BpL01ha2VmaWxlIGIvZHJpdmVycy9zcGkvTWFrZWZpbGUKPiBpbmRleCAwZjQ0ZWI2Li5m M2U0MmMwIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvc3BpL01ha2VmaWxlCj4gKysrIGIvZHJpdmVy cy9zcGkvTWFrZWZpbGUKPiBAQCAtNjIsNiArNjIsNyBAQCBvYmotJChDT05GSUdfU1BJX0hJU0lf U0ZDX1YzWFgpCQkrPSAKPiBzcGktaGlzaS1zZmMtdjN4eC5vCj4gIG9iai0kKENPTkZJR19TUElf SU1HX1NQRkkpCQkrPSBzcGktaW1nLXNwZmkubwo+ICBvYmotJChDT05GSUdfU1BJX0lNWCkJCQkr PSBzcGktaW14Lm8KPiAgb2JqLSQoQ09ORklHX1NQSV9JTkdFTklDKQkJKz0gc3BpLWluZ2VuaWMu bwo+ICtvYmotJChDT05GSUdfU1BJX0lOR0VOSUNfU0ZDKQkrPSBzcGktaW5nZW5pYy1zZmMubwo+ ICBvYmotJChDT05GSUdfU1BJX0lOVEVMKQkJCSs9IHNwaS1pbnRlbC5vCj4gIG9iai0kKENPTkZJ R19TUElfSU5URUxfUENJKQkJKz0gc3BpLWludGVsLXBjaS5vCj4gIG9iai0kKENPTkZJR19TUElf SU5URUxfUExBVEZPUk0pCSs9IHNwaS1pbnRlbC1wbGF0Zm9ybS5vCj4gZGlmZiAtLWdpdCBhL2Ry aXZlcnMvc3BpL3NwaS1pbmdlbmljLXNmYy5jIAo+IGIvZHJpdmVycy9zcGkvc3BpLWluZ2VuaWMt c2ZjLmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwLi5hNTY1NTQ2Cj4g LS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvc3BpL3NwaS1pbmdlbmljLXNmYy5jCj4gQEAg LTAsMCArMSw2NjIgQEAKPiArLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IChHUEwtMi4wLW9u bHkgT1IgQlNELTItQ2xhdXNlKQoKRHVhbC1saWNlbnNlIGRyaXZlcj8gVGhhdCdzIG5vdCB3aGF0 IE1PRFVMRV9MSUNFTlNFKCkgc2F5cy4KCj4gKy8qCj4gKyAqIEluZ2VuaWMgU29DcyBTUEkgRmxh c2ggQ29udHJvbGxlciBEcml2ZXIKPiArICogQ29weXJpZ2h0IChjKSAyMDIyIOWRqOeQsOadsCAo WmhvdSBZYW5qaWUpIAo+IDx6aG91eWFuamllQHdhbnllZXRlY2guY29tPgo+ICsgKi8KPiArCj4g KyNpbmNsdWRlIDxsaW51eC9iaXRmaWVsZC5oPgo+ICsjaW5jbHVkZSA8bGludXgvYml0b3BzLmg+ Cj4gKyNpbmNsdWRlIDxsaW51eC9jbGsuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2NvbXBsZXRpb24u aD4KPiArI2luY2x1ZGUgPGxpbnV4L2RtYS1tYXBwaW5nLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9p bnRlcnJ1cHQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2lvcG9sbC5oPgo+ICsjaW5jbHVkZSA8bGlu dXgvbW9kdWxlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9tdGQvbXRkLmg+Cj4gKyNpbmNsdWRlIDxs aW51eC9vZl9kZXZpY2UuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgo+ ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+ICsjaW5jbHVkZSA8bGludXgvc3BpL3NwaS5oPgo+ ICsjaW5jbHVkZSA8bGludXgvc3BpL3NwaS1tZW0uaD4KPiArCj4gKy8qIFNGQyByZWdpc3RlciBv ZmZzZXRzICovCj4gKyNkZWZpbmUgU0ZDX1JFR19HTEIJCQkJCQkweDAwMDAKPiArI2RlZmluZSBT RkNfUkVHX0RFVl9DT05GCQkJCTB4MDAwNAo+ICsjZGVmaW5lIFNGQ19SRUdfREVWX1NUQV9FWFAJ CQkJMHgwMDA4Cj4gKyNkZWZpbmUgU0ZDX1JFR19ERVZfU1RBX1JUCQkJCTB4MDAwYwo+ICsjZGVm aW5lIFNGQ19SRUdfREVWX1NUQV9NU0sJCQkJMHgwMDEwCj4gKyNkZWZpbmUgU0ZDX1JFR19UUkFO X0NPTkYobikJCQkoMHgwMDE0ICsgbiAqIDQpCj4gKyNkZWZpbmUgU0ZDX1JFR19UUkFOX0NGRzAo bikJCQkoMHgwMDE0ICsgbiAqIDQpCgpZb3Ugc2hvdWxkIHByb3RlY3QgdGhlIG1hY3JvIHBhcmFt ZXRlci4gSWYgeW91IGRvIGZvciBpbnN0YW5jZSAKU0ZDX1JFR19UUkFOX0NPTkYoeCArIDEpIGl0 IHdvdWxkIHJlc29sdmUgdG8gKDB4MDAxNCArIHggKyAxICogNCkgd2hpY2ggCmlzIG5vdCB3aGF0 IHlvdSdkIHdhbnQuCgpBbHNvIC0gbG9va3MgbGlrZSBTRkNfUkVHX1RSQU5fQ09ORigpIGFuZCBT RkNfUkVHX1RSQU5fQ0ZHMCgpIGFyZSB0aGUgCnNhbWUgdGhpbmcsIHRoYXQncyBvbiBwdXJwb3Nl PwoKPiArI2RlZmluZSBTRkNfUkVHX1RSQU5fTEVOCQkJCTB4MDAyYwo+ICsjZGVmaW5lIFNGQ19S RUdfREVWX0FERFIobikJCQkJKDB4MDAzMCArIG4gKiA0KQo+ICsjZGVmaW5lIFNGQ19SRUdfREVW X0FERFJfUExVUyhuKQkJKDB4MDA0OCArIG4gKiA0KQo+ICsjZGVmaW5lIFNGQ19SRUdfTUVNX0FE RFIJCQkJMHgwMDYwCj4gKyNkZWZpbmUgU0ZDX1JFR19UUklHCQkJCQkweDAwNjQKPiArI2RlZmlu ZSBTRkNfUkVHX1NSCQkJCQkJMHgwMDY4Cj4gKyNkZWZpbmUgU0ZDX1JFR19TQ1IJCQkJCQkweDAw NmMKPiArI2RlZmluZSBTRkNfUkVHX0lOVEMJCQkJCTB4MDA3MAo+ICsjZGVmaW5lIFNGQ19SRUdf RlNNCQkJCQkJMHgwMDc0Cj4gKyNkZWZpbmUgU0ZDX1JFR19DR0UJCQkJCQkweDAwNzgKPiArI2Rl ZmluZSBTRkNfUkVHX1RSQU5fQ0ZHMShuKQkJCSgweDAwOWMgKyBuICogNCkKPiArI2RlZmluZSBT RkNfUkVHX0RSCQkJCQkJMHgxMDAwCj4gKwo+ICsvKiBiaXRzIHdpdGhpbiB0aGUgR0xCIHJlZ2lz dGVyICovCj4gKyNkZWZpbmUgR0xCX1RSQU5fRElSX01BU0sJCQkJR0VOTUFTSygxMywgMTMpCj4g KyNkZWZpbmUgR0xCX1RSQU5fRElSX1dSSVRFCQkJCTB4MQo+ICsjZGVmaW5lIEdMQl9UUkFOX0RJ Ul9SRUFECQkJCTB4MAoKV2hlbiBpdCdzIGEgc2luZ2xlIGJpdCAtIGp1c3QgdXNlIEJJVCgpLgoK PiArI2RlZmluZSBHTEJfVEhSRVNIT0xEX01BU0sJCQkJR0VOTUFTSygxMiwgNykKPiArI2RlZmlu ZSBHTEJfT1BfTU9ERV9NQVNLCQkJCUdFTk1BU0soNiwgNikKClNhbWUgaGVyZSwgYW5kIEkgc2Vl IGl0IGEgZmV3IHRpbWVzIGJlbG93IGFzIHdlbGwuCgo+ICsjZGVmaW5lIEdMQl9PUF9NT0RFX0RN QQkJCQkJMHgxCj4gKyNkZWZpbmUgR0xCX09QX01PREVfU0xBVkUJCQkJMHgwCj4gKyNkZWZpbmUg R0xCX1BIQVNFX05VTV9NQVNLCQkJCUdFTk1BU0soNSwgMykKPiArI2RlZmluZSBHTEJfV1BfRU4J CQkJCQlCSVQoMikKPiArI2RlZmluZSBHTEJfQlVSU1RfTURfTUFTSwkJCQlHRU5NQVNLKDEsIDAp Cj4gKyNkZWZpbmUgR0xCX0JVUlNUX01EX0lOQ1IzMgkJCQkweDMKPiArI2RlZmluZSBHTEJfQlVS U1RfTURfSU5DUjE2CQkJCTB4Mgo+ICsjZGVmaW5lIEdMQl9CVVJTVF9NRF9JTkNSOAkJCQkweDEK PiArI2RlZmluZSBHTEJfQlVSU1RfTURfSU5DUjQJCQkJMHgwCj4gKwo+ICsvKiBiaXRzIHdpdGhp biB0aGUgREVWX0NPTkYgcmVnaXN0ZXIgKi8KPiArI2RlZmluZSBERVZfQ09ORl9TTVBfREVMQVlf TUFTSwkJCUdFTk1BU0soMjAsIDE2KQo+ICsjZGVmaW5lIERFVl9DT05GX1NNUF9ERUxBWV8xODBE RUcJCTB4NAo+ICsjZGVmaW5lIERFVl9DT05GX1NNUF9ERUxBWV9IQUxGX0NZQ0xFCTB4MQo+ICsj ZGVmaW5lIERFVl9DT05GX0NNRF9UWVBFX01BU0sJCQlHRU5NQVNLKDE1LCAxNSkKPiArI2RlZmlu ZSBERVZfQ09ORl9DTURfVFlQRV8xNkJJVAkJCTB4MQo+ICsjZGVmaW5lIERFVl9DT05GX0NNRF9U WVBFXzhCSVQJCQkweDAKPiArI2RlZmluZSBERVZfQ09ORl9TVEFfVFlQRV9NQVNLCQkJR0VOTUFT SygxNCwgMTMpCj4gKyNkZWZpbmUgREVWX0NPTkZfVEhPTERfTUFTSwkJCQlHRU5NQVNLKDEyLCAx MSkKPiArI2RlZmluZSBERVZfQ09ORl9UU0VUVVBfTUFTSwkJCUdFTk1BU0soMTAsIDkpCj4gKyNk ZWZpbmUgREVWX0NPTkZfVFNIX01BU0sJCQkJR0VOTUFTSyg4LCA1KQo+ICsjZGVmaW5lIERFVl9D T05GX0NQSEEJCQkJCUJJVCg0KQo+ICsjZGVmaW5lIERFVl9DT05GX0NQT0wJCQkJCUJJVCgzKQo+ ICsjZGVmaW5lIERFVl9DT05GX0NFX0RMCQkJCQlCSVQoMikKPiArI2RlZmluZSBERVZfQ09ORl9I T0xEX0RMCQkJCUJJVCgxKQo+ICsjZGVmaW5lIERFVl9DT05GX1dQX0RMCQkJCQlCSVQoMCkKPiAr Cj4gKy8qIGJpdHMgd2l0aGluIHRoZSBUUkFOX0NPTkYobikgcmVnaXN0ZXIgKi8KPiArI2RlZmlu ZSBUUkFOX0NPTkZfVFJBTl9NT0RFX01BU0sJCUdFTk1BU0soMzEsIDI5KQo+ICsjZGVmaW5lIFRS QU5fQ09ORl9BRERSX1dJRFRIX01BU0sJCUdFTk1BU0soMjgsIDI2KQo+ICsjZGVmaW5lIFRSQU5f Q09ORl9QT0xMX0VOCQkJCUJJVCgyNSkKPiArI2RlZmluZSBUUkFOX0NPTkZfQ01EX0VOCQkJCUJJ VCgyNCkKPiArI2RlZmluZSBUUkFOX0NPTkZfUEhBU0VfRk9STUFUX01BU0sJCUdFTk1BU0soMjMs IDIzKQo+ICsjZGVmaW5lIFRSQU5fQ09ORl9ETVlfQklUU19NQVNLCQkJR0VOTUFTSygyMiwgMTcp Cj4gKyNkZWZpbmUgVFJBTl9DT05GX0RBVEFfRU4JCQkJQklUKDE2KQo+ICsjZGVmaW5lIFRSQU5f Q09ORl9DTURfTUFTSwkJCQlHRU5NQVNLKDE1LCAwKQo+ICsKPiArLyogYml0cyB3aXRoaW4gdGhl IFRSSUcgcmVnaXN0ZXIgKi8KPiArI2RlZmluZSBUUklHX0ZMVVNICQkJCQkJQklUKDIpCj4gKyNk ZWZpbmUgVFJJR19TVE9QCQkJCQkJQklUKDEpCj4gKyNkZWZpbmUgVFJJR19TVEFSVAkJCQkJCUJJ VCgwKQo+ICsKPiArLyogYml0cyB3aXRoaW4gdGhlIFNSIHJlZ2lzdGVyICovCj4gKyNkZWZpbmUg U1JfRklGT19OVU1fTUFTSwkJCQlHRU5NQVNLKDIyLCAxNikKPiArI2RlZmluZSBTUl9FTkQJCQkJ CQkJQklUKDQpCj4gKyNkZWZpbmUgU1JfVFJBTl9SRVEJCQkJCQlCSVQoMykKPiArI2RlZmluZSBT Ul9SRUNFX1JFUQkJCQkJCUJJVCgyKQo+ICsjZGVmaW5lIFNSX09WRVIJCQkJCQkJQklUKDEpCj4g KyNkZWZpbmUgU1JfVU5ERVIJCQkJCQlCSVQoMCkKPiArCj4gKy8qIGJpdHMgd2l0aGluIHRoZSBT Q1IgcmVnaXN0ZXIgKi8KPiArI2RlZmluZSBTQ1JfQ0xSX0VORAkJCQkJCUJJVCg0KQo+ICsjZGVm aW5lIFNDUl9DTFJfVFJFUQkJCQkJQklUKDMpCj4gKyNkZWZpbmUgU0NSX0NMUl9SUkVRCQkJCQlC SVQoMikKPiArI2RlZmluZSBTQ1JfQ0xSX09WRVIJCQkJCUJJVCgxKQo+ICsjZGVmaW5lIFNDUl9D TFJfVU5ERVIJCQkJCUJJVCgwKQo+ICsKPiArLyogYml0cyB3aXRoaW4gdGhlIElOVEMgcmVnaXN0 ZXIgKi8KPiArI2RlZmluZSBJTlRDX01BU0tfRU5ECQkJCQlCSVQoNCkKPiArI2RlZmluZSBJTlRD X01BU0tfVFJFUQkJCQkJQklUKDMpCj4gKyNkZWZpbmUgSU5UQ19NQVNLX1JSRVEJCQkJCUJJVCgy KQo+ICsjZGVmaW5lIElOVENfTUFTS19PVkVSCQkJCQlCSVQoMSkKPiArI2RlZmluZSBJTlRDX01B U0tfVU5ERVIJCQkJCUJJVCgwKQo+ICsKPiArLyogYml0cyB3aXRoaW4gdGhlIFRSQU5fQ0ZHMShu KSByZWdpc3RlciAqLwo+ICsjZGVmaW5lIFRSQU5fQ0ZHMV9UUkFOX01PREVfTUFTSwkJR0VOTUFT Syg3LCA0KQo+ICsKPiArI2RlZmluZSBUUkFOX01PREVfU1RBTkRBUkQJCQkJMAo+ICsjZGVmaW5l IFRSQU5fTU9ERV9EVUFMX0RBVEEJCQkJMQo+ICsjZGVmaW5lIFRSQU5fTU9ERV9EVUFMX0lPCQkJ CTIKPiArI2RlZmluZSBUUkFOX01PREVfRFVBTF9GVUxMCQkJCTMKPiArI2RlZmluZSBUUkFOX01P REVfUVVBRF9EQVRBCQkJCTUKPiArI2RlZmluZSBUUkFOX01PREVfUVVBRF9JTwkJCQk2Cj4gKyNk ZWZpbmUgVFJBTl9NT0RFX1FVQURfRlVMTAkJCQk3Cj4gKyNkZWZpbmUgVFJBTl9NT0RFX09DVEFM X0RBVEEJCQk5Cj4gKyNkZWZpbmUgVFJBTl9NT0RFX09DVEFMX0lPCQkJCTEwCj4gKyNkZWZpbmUg VFJBTl9NT0RFX09DVEFMX0ZVTEwJCQkxMQo+ICsKPiArI2RlZmluZSBJTkdFTklDX1NGQ19GSUZP X1NJWkUJCQkoNjQgKiA0KQo+ICsKPiArI2RlZmluZSBJTkdFTklDX1NGQ19UUkFOU0ZFUl9USU1F T1VUCTEwMDAKCk1heWJlIGFkZCB0aGUgdW5pdCBuYW1lIGluIHRoZSBtYWNybyBhcyB3ZWxsIC0g CklOR0VOSUNfU0ZDX1RSQU5TRkVSX1RJTUVPVVRfTVMuCgo+ICsKPiArZW51bSBpbmdlbmljX3Nm Y192ZXJzaW9uIHsKPiArCUlEX1gxMDAwLAo+ICsJSURfWDE2MDAsCj4gKwlJRF9YMjAwMCwKPiAr fTsKPiArCj4gK3N0cnVjdCBpbmdlbmljX3NvY19pbmZvIHsKPiArCWVudW0gaW5nZW5pY19zZmNf dmVyc2lvbiB2ZXJzaW9uOwo+ICsKPiArCXVuc2lnbmVkIGludCBtYXhfYnVzX3dpZHRoOwo+ICsK PiArCWNvbnN0IHUzMiB0cmFuX21vZGVfbWFzazsKPiArfTsKPiArCj4gK3N0cnVjdCBpbmdlbmlj X3NmYyB7Cj4gKwljb25zdCBzdHJ1Y3QgaW5nZW5pY19zb2NfaW5mbyAqc29jX2luZm87Cj4gKwo+ ICsJdm9pZCBfX2lvbWVtICpiYXNlOwo+ICsJc3RydWN0IGRldmljZSAqZGV2Owo+ICsJc3RydWN0 IGNsayAqY2xrOwo+ICsJaW50IGlycTsKPiArCj4gKwlzdHJ1Y3QgY29tcGxldGlvbiBjb21wbGV0 aW9uOwo+ICt9Owo+ICsKPiArc3RhdGljIGlycXJldHVybl90IGluZ2VuaWNfc2ZjX2lycV9oYW5k bGVyKGludCBpcnEsIHZvaWQgKmRhdGEpCj4gK3sKPiArCXN0cnVjdCBpbmdlbmljX3NmYyAqc2Zj ID0gZGF0YTsKPiArCj4gKwl3cml0ZWwoMHgxZiwgc2ZjLT5iYXNlICsgU0ZDX1JFR19JTlRDKTsK PiArCj4gKwljb21wbGV0ZSgmc2ZjLT5jb21wbGV0aW9uKTsKPiArCj4gKwlyZXR1cm4gSVJRX0hB TkRMRUQ7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgaW5nZW5pY19zZmNfYWRqdXN0X29wX3NpemUo c3RydWN0IHNwaV9tZW0gKm1lbSwgc3RydWN0IAo+IHNwaV9tZW1fb3AgKm9wKQo+ICt7Cj4gKwl1 aW50cHRyX3QgYWRkciA9ICh1aW50cHRyX3Qpb3AtPmRhdGEuYnVmLmluOwo+ICsKPiArCWlmIChv cC0+ZGF0YS5uYnl0ZXMgPiBJTkdFTklDX1NGQ19GSUZPX1NJWkUgJiYgIUlTX0FMSUdORUQoYWRk ciwgNCkpCj4gKwkJb3AtPmRhdGEubmJ5dGVzID0gSU5HRU5JQ19TRkNfRklGT19TSVpFOwo+ICsK PiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgYm9vbCBpbmdlbmljX3NmY19zdXBwb3J0 c19vcChzdHJ1Y3Qgc3BpX21lbSAqbWVtLCBjb25zdCAKPiBzdHJ1Y3Qgc3BpX21lbV9vcCAqb3Ap Cj4gK3sKPiArCXN0cnVjdCBzcGlfZGV2aWNlICpzcGkgPSBtZW0tPnNwaTsKPiArCXN0cnVjdCBp bmdlbmljX3NmYyAqc2ZjID0gc3BpX2NvbnRyb2xsZXJfZ2V0X2RldmRhdGEoc3BpLT5tYXN0ZXIp Owo+ICsJdWludHB0cl90IGFkZHIgPSAodWludHB0cl90KW9wLT5kYXRhLmJ1Zi5pbjsKPiArCj4g KwkvKiBUaGUgY29udHJvbGxlciBvbmx5IHN1cHBvcnRzIFN0YW5kYXJkIFNQSSBtb2RlLCBEdWFs bCBtb2RlLCBRdWFkIAo+IG1vZGUgYW5kIE9jdGFsIG1vZGUuICovCgpEdWFsKgoKPiArCWlmIChv cC0+Y21kLmJ1c3dpZHRoID4gc2ZjLT5zb2NfaW5mby0+bWF4X2J1c193aWR0aCB8fAo+ICsJCW9w LT5hZGRyLmJ1c3dpZHRoID4gc2ZjLT5zb2NfaW5mby0+bWF4X2J1c193aWR0aCB8fAo+ICsJCW9w LT5kdW1teS5idXN3aWR0aCA+IHNmYy0+c29jX2luZm8tPm1heF9idXNfd2lkdGggfHwKPiArCQlv cC0+ZGF0YS5idXN3aWR0aCA+IHNmYy0+c29jX2luZm8tPm1heF9idXNfd2lkdGgpCj4gKwkJcmV0 dXJuIGZhbHNlOwo+ICsKPiArCS8qIE1heCAzMiBkdW1teSBjbG9jayBjeWNsZXMgc3VwcG9ydGVk ICovCj4gKwlpZiAob3AtPmR1bW15Lm5ieXRlcyAmJiBvcC0+ZHVtbXkubmJ5dGVzICogOCAvIG9w LT5kdW1teS5idXN3aWR0aCA+IAo+IDMyKQo+ICsJCXJldHVybiBmYWxzZTsKPiArCj4gKwkvKiBN YXggcnggZGF0YSBsZW5ndGgsIGNoZWNrIGNvbnRyb2xsZXIgbGltaXRzIGFuZCBhbGlnbm1lbnQg Ki8KPiArCWlmIChvcC0+ZGF0YS5kaXIgPT0gU1BJX01FTV9EQVRBX0lOICYmCj4gKwkJb3AtPmRh dGEubmJ5dGVzID4gSU5HRU5JQ19TRkNfRklGT19TSVpFICYmICFJU19BTElHTkVEKGFkZHIsIDQp KQoKVGhpcyBkb2VzIHRoZSBzYW1lIGNoZWNrIHRoYW4gaW4gaW5nZW5pY19zZmNfYWRqdXN0X29w X3NpemUoKSwgbWF5YmUgCm1vdmUgaXQgdG8gYSBuZXcgaW5saW5lIGZ1bmN0aW9uPwoKPiArCQly ZXR1cm4gZmFsc2U7Cj4gKwo+ICsJLyogTWF4IDYgYnl0ZXMgYWRkcmVzcyB3aWR0aCBzdXBwb3J0 ZWQgKi8KPiArCWlmIChvcC0+YWRkci5uYnl0ZXMgPiA2KQo+ICsJCXJldHVybiBmYWxzZTsKPiAr Cj4gKwlyZXR1cm4gc3BpX21lbV9kZWZhdWx0X3N1cHBvcnRzX29wKG1lbSwgb3ApOwo+ICt9Cj4g Kwo+ICtzdGF0aWMgdm9pZCBpbmdlbmljX3NmY19zZXRfdHJhbnNmZXJfbW9kZShzdHJ1Y3QgaW5n ZW5pY19zZmMgKnNmYywgCj4gY29uc3Qgc3RydWN0IHNwaV9tZW1fb3AgKm9wKQo+ICt7Cj4gKwlp bnQgdmFsOwo+ICsKPiArCXZhbCA9IHJlYWRsKHNmYy0+YmFzZSArIChzZmMtPnNvY19pbmZvLT52 ZXJzaW9uID49IElEX1gxNjAwID8KPiArCQkJU0ZDX1JFR19UUkFOX0NGRzEoMCkgOiBTRkNfUkVH X1RSQU5fQ09ORigwKSkpOwoKQXMgS3J6eXN6dG9mIHNhaWQgLSB1Z2guCgpBbHNvLCBpbnN0ZWFk IG9mIGhhdmluZyBhICJ2ZXJzaW9uIiBlbnVtIGluIHlvdXIgc29jX2luZm8sIHdoeSBub3QganVz dCAKaGF2ZSBhICJyZWdfY29uZiIgZmllbGQgdGhhdCBnaXZlcyB5b3UgZGlyZWN0bHkgdGhlIHJp Z2h0IHJlZ2lzdGVyPwoKCj4gKwl2YWwgJj0gfnNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNr Owo+ICsJaWYgKG9wLT5jbWQuYnVzd2lkdGggPT0gOCkKPiArCQl2YWwgfD0gKFRSQU5fTU9ERV9P Q1RBTF9GVUxMIDw8IAo+IChmZnMoc2ZjLT5zb2NfaW5mby0+dHJhbl9tb2RlX21hc2spIC0gMSkp ICYKPiArCQkJCXNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNrOwoKTG9va3MgbGlrZSB5b3Un cmUgcmVhbGx5IHRyeWluZyB0byByZWludmVudCB0aGUgd2hlZWwuCgp2YWwgfD0gRklFTERfUFJF UChzZmMtPnNvY19pbmZvLT50cmFuX21vZGVfbWFzaywgVFJBTl9NT0RFX09DVEFMX0ZVTEwpOwoK dXNpbmcgPGxpbnV4L2JpdGZpZWxkLmg+LgoKQWxzbywganVzdCBkZWZpbmUgYSAnbW9kZScgdmFy aWFibGUgYW5kIHNldCBpdCBpbiB5b3VyIGlmL2Vsc2UgYmxvY2tzLCAKdGhhdCB3b3VsZCBsb29r IG11Y2ggYmV0dGVyLiBUaGVuIHlvdSBjYW4gc2V0IHZhbCB8PSBGSUVMRF9QUkVQKC4uLiwgCm1v ZGUpIGF0IHRoZSBlbmQuCgo+ICsJZWxzZSBpZiAob3AtPmNtZC5idXN3aWR0aCA9PSA0KQo+ICsJ CXZhbCB8PSAoVFJBTl9NT0RFX1FVQURfRlVMTCA8PCAoZmZzKHNmYy0+c29jX2luZm8tPnRyYW5f bW9kZV9tYXNrKSAKPiAtIDEpKSAmCj4gKwkJCQlzZmMtPnNvY19pbmZvLT50cmFuX21vZGVfbWFz azsKPiArCWVsc2UgaWYgKG9wLT5jbWQuYnVzd2lkdGggPT0gMikKPiArCQl2YWwgfD0gKFRSQU5f TU9ERV9EVUFMX0ZVTEwgPDwgKGZmcyhzZmMtPnNvY19pbmZvLT50cmFuX21vZGVfbWFzaykgCj4g LSAxKSkgJgo+ICsJCQkJc2ZjLT5zb2NfaW5mby0+dHJhbl9tb2RlX21hc2s7Cj4gKwllbHNlIGlm IChvcC0+YWRkci5idXN3aWR0aCA9PSA4KQo+ICsJCXZhbCB8PSAoVFJBTl9NT0RFX09DVEFMX0lP IDw8IChmZnMoc2ZjLT5zb2NfaW5mby0+dHJhbl9tb2RlX21hc2spIAo+IC0gMSkpICYKPiArCQkJ CXNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNrOwo+ICsJZWxzZSBpZiAob3AtPmFkZHIuYnVz d2lkdGggPT0gNCkKPiArCQl2YWwgfD0gKFRSQU5fTU9ERV9RVUFEX0lPIDw8IChmZnMoc2ZjLT5z b2NfaW5mby0+dHJhbl9tb2RlX21hc2spIC0gCj4gMSkpICYKPiArCQkJCXNmYy0+c29jX2luZm8t PnRyYW5fbW9kZV9tYXNrOwo+ICsJZWxzZSBpZiAob3AtPmFkZHIuYnVzd2lkdGggPT0gMikKPiAr CQl2YWwgfD0gKFRSQU5fTU9ERV9EVUFMX0lPIDw8IChmZnMoc2ZjLT5zb2NfaW5mby0+dHJhbl9t b2RlX21hc2spIC0gCj4gMSkpICYKPiArCQkJCXNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNr Owo+ICsJZWxzZSBpZiAob3AtPmRhdGEuYnVzd2lkdGggPT0gOCkKPiArCQl2YWwgfD0gKFRSQU5f TU9ERV9PQ1RBTF9EQVRBIDw8IAo+IChmZnMoc2ZjLT5zb2NfaW5mby0+dHJhbl9tb2RlX21hc2sp IC0gMSkpICYKPiArCQkJCXNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNrOwo+ICsJZWxzZSBp ZiAob3AtPmRhdGEuYnVzd2lkdGggPT0gNCkKPiArCQl2YWwgfD0gKFRSQU5fTU9ERV9RVUFEX0RB VEEgPDwgKGZmcyhzZmMtPnNvY19pbmZvLT50cmFuX21vZGVfbWFzaykgCj4gLSAxKSkgJgo+ICsJ CQkJc2ZjLT5zb2NfaW5mby0+dHJhbl9tb2RlX21hc2s7Cj4gKwllbHNlIGlmIChvcC0+ZGF0YS5i dXN3aWR0aCA9PSAyKQo+ICsJCXZhbCB8PSAoVFJBTl9NT0RFX0RVQUxfREFUQSA8PCAoZmZzKHNm Yy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNrKSAKPiAtIDEpKSAmCj4gKwkJCQlzZmMtPnNvY19p bmZvLT50cmFuX21vZGVfbWFzazsKPiArCWVsc2UKPiArCQl2YWwgfD0gKFRSQU5fTU9ERV9TVEFO REFSRCA8PCAoZmZzKHNmYy0+c29jX2luZm8tPnRyYW5fbW9kZV9tYXNrKSAKPiAtIDEpKSAmCj4g KwkJCQlzZmMtPnNvY19pbmZvLT50cmFuX21vZGVfbWFzazsKPiArCXdyaXRlbCh2YWwsIHNmYy0+ YmFzZSArIChzZmMtPnNvY19pbmZvLT52ZXJzaW9uID49IElEX1gxNjAwID8KPiArCQkJU0ZDX1JF R19UUkFOX0NGRzEoMCkgOiBTRkNfUkVHX1RSQU5fQ09ORigwKSkpOwo+ICt9Cj4gKwo+ICsvKgo+ ICsgKiBXZSBvbmx5IG5lZWQgUElPIG1vZGUgdG8gaGFuZGxlIHRoZSBTUElfTUVNX05PX0RBVEEg dHJhbnNmZXJzLAo+ICsgKiBhbmQgdGhlIHVuYWxpZ25lZCBhY2Nlc3NlcyBpbiBTUElfTUVNX0RB VEFfSU4gdHJhbnNmZXJzLgo+ICsgKi8KPiArc3RhdGljIHZvaWQgaW5nZW5pY19zZmNfcmVhZF9y eGZpZm8oc3RydWN0IGluZ2VuaWNfc2ZjICpzZmMsIHU4ICp0bywgCj4gdW5zaWduZWQgaW50IGxl bikKPiArewo+ICsJdm9pZCBfX2lvbWVtICpmcm9tOwo+ICsKPiArCWZyb20gPSBzZmMtPmJhc2Ug KyBTRkNfUkVHX0RSOwo+ICsKPiArCWZvciAoOyBsZW4gPj0gNDsgbGVuIC09IDQsIHRvICs9IDQp IHsKPiArCQl1MzIgdmFsID0gX19yYXdfcmVhZGwoZnJvbSk7Cj4gKwkJbWVtY3B5KHRvLCAmdmFs LCA0KTsKCk5vIG5lZWQgdG8gdXNlIG1lbWNweSBmb3IgNCBieXRlcy4gWW91IGNhbiBkbzogcHV0 X3VuYWxpZ25lZCh2YWwsICh1MzIgCiopdG8pOwoKPiArCX0KPiArCj4gKwlpZiAobGVuKSB7Cj4g KwkJdTMyIHZhbCA9IF9fcmF3X3JlYWRsKGZyb20pOwo+ICsJCW1lbWNweSh0bywgJnZhbCwgbGVu KTsKCkhtbSwgSSdtIG5vdCBzdXJlIHRoYXQgaXMgZW5kaWFuLXNhZmUuIEkgd291bGQgcHJlZmVy IGlmIHlvdSBjb3BpZWQgCmJ5dGUgYnkgYnl0ZS4KCj4gKwl9Cj4gK30KPiArCj4gK3N0YXRpYyBp bnQgaW5nZW5pY19zZmNfZXhlY19vcF9waW8oc3RydWN0IGluZ2VuaWNfc2ZjICpzZmMsIGNvbnN0 IAo+IHN0cnVjdCBzcGlfbWVtX29wICpvcCkKPiArewo+ICsJaW50IHJldCwgdmFsOwo+ICsKPiAr CXZhbCA9IHJlYWRsKHNmYy0+YmFzZSArIFNGQ19SRUdfR0xCKTsKPiArCXUzMnBfcmVwbGFjZV9i aXRzKCZ2YWwsIEdMQl9UUkFOX0RJUl9SRUFELCBHTEJfVFJBTl9ESVJfTUFTSyk7Cj4gKwl1MzJw X3JlcGxhY2VfYml0cygmdmFsLCBHTEJfT1BfTU9ERV9TTEFWRSwgR0xCX09QX01PREVfTUFTSyk7 Cj4gKwl3cml0ZWwodmFsLCBzZmMtPmJhc2UgKyBTRkNfUkVHX0dMQik7CgpCeSB0aGUgd2F5LCBo YXZlIHlvdSBjb25zaWRlcmVkIHVzaW5nIHJlZ21hcD8KCkl0IHdvdWxkIGdpdmUgeW91IHRoaW5n cyBsaWtlIHJlZ21hcF91cGRhdGVfYml0cygpIGZvciB0aGlzIGtpbmQgb2YgCnRoaW5ncywgYW5k IHJlZ21hcF9maWVsZCgpIHRvIGhhbmRsZSB5b3VyIGNvbmYgcmVnaXN0ZXIgYmVpbmcgYXQgYSAK ZGlmZmVyZW50IGFkZHJlc3MgYWNyb3NzIFNvQ3MuCgo+ICsKPiArCXZhbCA9IFRSQU5fQ09ORl9D TURfRU4gfCBvcC0+Y21kLm9wY29kZTsKPiArCj4gKwlpZiAob3AtPmFkZHIubmJ5dGVzID4gMCkg ewo+ICsJCXZhbCB8PSBGSUVMRF9QUkVQKFRSQU5fQ09ORl9BRERSX1dJRFRIX01BU0ssIG9wLT5h ZGRyLm5ieXRlcyk7Cj4gKwo+ICsJCXdyaXRlbChvcC0+YWRkci52YWwgJiAweGZmZmZmZmZmLCBz ZmMtPmJhc2UgKyBTRkNfUkVHX0RFVl9BRERSKDApKTsKPiArCQl3cml0ZWwob3AtPmFkZHIudmFs ID4+IDMyLCBzZmMtPmJhc2UgKyBTRkNfUkVHX0RFVl9BRERSX1BMVVMoMCkpOwo+ICsJfQo+ICsK PiArCWlmIChvcC0+ZHVtbXkubmJ5dGVzID4gMCkKPiArCQl2YWwgfD0gRklFTERfUFJFUChUUkFO X0NPTkZfRE1ZX0JJVFNfTUFTSywKPiArCQkJCW9wLT5kdW1teS5uYnl0ZXMgKiA4IC8gb3AtPmR1 bW15LmJ1c3dpZHRoKTsKPiArCj4gKwlpZiAob3AtPmRhdGEubmJ5dGVzID4gMCkKPiArCQl2YWwg fD0gVFJBTl9DT05GX0RBVEFfRU47Cj4gKwo+ICsJd3JpdGVsKHZhbCwgc2ZjLT5iYXNlICsgU0ZD X1JFR19UUkFOX0NPTkYoMCkpOwo+ICsJd3JpdGVsKG9wLT5kYXRhLm5ieXRlcywgc2ZjLT5iYXNl ICsgU0ZDX1JFR19UUkFOX0xFTik7Cj4gKwo+ICsJaW5nZW5pY19zZmNfc2V0X3RyYW5zZmVyX21v ZGUoc2ZjLCBvcCk7Cj4gKwo+ICsJd3JpdGVsKDB4MWYsIHNmYy0+YmFzZSArIFNGQ19SRUdfU0NS KTsKClJhbmRvbSAweDFmIHZhbHVlIGhlcmUsIG1heWJlIHVzZSBhIG1hY3JvPwoKPiArCXdyaXRl bCh+KElOVENfTUFTS19FTkQgfCBJTlRDX01BU0tfUlJFUSksIHNmYy0+YmFzZSArIFNGQ19SRUdf SU5UQyk7Cj4gKwo+ICsJd3JpdGVsKDAsIHNmYy0+YmFzZSArIFNGQ19SRUdfTUVNX0FERFIpOwo+ ICsKPiArCXdyaXRlbChUUklHX0ZMVVNILCBzZmMtPmJhc2UgKyBTRkNfUkVHX1RSSUcpOwo+ICsJ d3JpdGVsKFRSSUdfU1RBUlQsIHNmYy0+YmFzZSArIFNGQ19SRUdfVFJJRyk7Cj4gKwo+ICsJcmV0 ID0gd2FpdF9mb3JfY29tcGxldGlvbl90aW1lb3V0KCZzZmMtPmNvbXBsZXRpb24sCj4gKwkJCW1z ZWNzX3RvX2ppZmZpZXMoSU5HRU5JQ19TRkNfVFJBTlNGRVJfVElNRU9VVCkpOwo+ICsJaWYgKCFy ZXQpIHsKPiArCQl3cml0ZWwoMHgxZiwgc2ZjLT5iYXNlICsgU0ZDX1JFR19JTlRDKTsKPiArCQl3 cml0ZWwoMHgxZiwgc2ZjLT5iYXNlICsgU0ZDX1JFR19TQ1IpOwo+ICsJCWRldl9lcnIoc2ZjLT5k ZXYsICJsaW5lOiVkIFRpbWVvdXQgZm9yIEFDSyBmcm9tIFNGQyBkZXZpY2VcbiIsIAo+IF9fTElO RV9fKTsKPiArCQlyZXR1cm4gLUVUSU1FRE9VVDsKPiArCX0KPiArCj4gKwlpbmdlbmljX3NmY19y ZWFkX3J4ZmlmbyhzZmMsIG9wLT5kYXRhLmJ1Zi5pbiwgb3AtPmRhdGEubmJ5dGVzKTsKPiArCXJl YWRsX3BvbGxfdGltZW91dChzZmMtPmJhc2UgKyBTRkNfUkVHX1NSLCB2YWwsIHZhbCAmIFNSX0VO RCwgMTAsIAo+IDApOwoKSW5maW5pdGUgdGltZW91dD8gSXMgdGhhdCB2ZXJ5IHdpc2U/Cgo+ICsK PiArCXdyaXRlbChJTlRDX01BU0tfRU5EIHwgSU5UQ19NQVNLX1JSRVEsIHNmYy0+YmFzZSArIFNG Q19SRUdfU0NSKTsKPiArCXdyaXRlbChUUklHX1NUT1AsIHNmYy0+YmFzZSArIFNGQ19SRUdfVFJJ Ryk7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgaW5nZW5pY19zZmNf ZXhlY19vcF9kbWEoc3RydWN0IGluZ2VuaWNfc2ZjICpzZmMsIGNvbnN0IAo+IHN0cnVjdCBzcGlf bWVtX29wICpvcCkKPiArewo+ICsJZG1hX2FkZHJfdCBhZGRyOwo+ICsJaW50IHJldCwgdmFsOwo+ ICsKPiArCXZhbCA9IHJlYWRsKHNmYy0+YmFzZSArIFNGQ19SRUdfR0xCKTsKPiArCXUzMnBfcmVw bGFjZV9iaXRzKCZ2YWwsIG9wLT5kYXRhLmRpciA9PSBTUElfTUVNX0RBVEFfSU4gPwo+ICsJCQlH TEJfVFJBTl9ESVJfUkVBRCA6IEdMQl9UUkFOX0RJUl9XUklURSwgR0xCX1RSQU5fRElSX01BU0sp Owo+ICsJdTMycF9yZXBsYWNlX2JpdHMoJnZhbCwgR0xCX09QX01PREVfRE1BLCBHTEJfT1BfTU9E RV9NQVNLKTsKPiArCXdyaXRlbCh2YWwsIHNmYy0+YmFzZSArIFNGQ19SRUdfR0xCKTsKPiArCj4g Kwl2YWwgPSBUUkFOX0NPTkZfQ01EX0VOIHwgb3AtPmNtZC5vcGNvZGU7Cj4gKwo+ICsJaWYgKG9w LT5hZGRyLm5ieXRlcyA+IDApIHsKPiArCQl2YWwgfD0gRklFTERfUFJFUChUUkFOX0NPTkZfQURE Ul9XSURUSF9NQVNLLCBvcC0+YWRkci5uYnl0ZXMpOwo+ICsJCXdyaXRlbChvcC0+YWRkci52YWwg JiAweGZmZmZmZmZmLCBzZmMtPmJhc2UgKyBTRkNfUkVHX0RFVl9BRERSKDApKTsKPiArCQl3cml0 ZWwob3AtPmFkZHIudmFsID4+IDMyLCBzZmMtPmJhc2UgKyBTRkNfUkVHX0RFVl9BRERSX1BMVVMo MCkpOwo+ICsJfQo+ICsKPiArCWlmIChvcC0+ZHVtbXkubmJ5dGVzID4gMCkKPiArCQl2YWwgfD0g RklFTERfUFJFUChUUkFOX0NPTkZfRE1ZX0JJVFNfTUFTSywKPiArCQkJCW9wLT5kdW1teS5uYnl0 ZXMgKiA4IC8gb3AtPmR1bW15LmJ1c3dpZHRoKTsKPiArCj4gKwlpZiAob3AtPmRhdGEubmJ5dGVz ID4gMCkKPiArCQl2YWwgfD0gVFJBTl9DT05GX0RBVEFfRU47CgpUaGVyZSdzIGEgbG90IG9mIGNv ZGUgZHVwbGljYXRpb24gaGVyZSB3aXRoIGluZ2VuaWNfc2ZjX2V4ZWNfb3BfcGlvKCkuIApBIGxv dCBjYW4gYmUgZmFjdG9yaXplZC4KCj4gKwo+ICsJd3JpdGVsKHZhbCwgc2ZjLT5iYXNlICsgU0ZD X1JFR19UUkFOX0NPTkYoMCkpOwo+ICsJd3JpdGVsKG9wLT5kYXRhLm5ieXRlcywgc2ZjLT5iYXNl ICsgU0ZDX1JFR19UUkFOX0xFTik7Cj4gKwo+ICsJaW5nZW5pY19zZmNfc2V0X3RyYW5zZmVyX21v ZGUoc2ZjLCBvcCk7Cj4gKwo+ICsJd3JpdGVsKDB4MWYsIHNmYy0+YmFzZSArIFNGQ19SRUdfU0NS KTsKPiArCXdyaXRlbCh+SU5UQ19NQVNLX0VORCwgc2ZjLT5iYXNlICsgU0ZDX1JFR19JTlRDKTsK PiArCj4gKwlzd2l0Y2ggKG9wLT5kYXRhLmRpcikgewo+ICsJY2FzZSBTUElfTUVNX0RBVEFfSU46 Cj4gKwkJYWRkciA9IGRtYV9tYXBfc2luZ2xlKHNmYy0+ZGV2LCBvcC0+ZGF0YS5idWYuaW4sIG9w LT5kYXRhLm5ieXRlcywgCj4gRE1BX0ZST01fREVWSUNFKTsKPiArCQlpZiAoZG1hX21hcHBpbmdf ZXJyb3Ioc2ZjLT5kZXYsIGFkZHIpKSB7Cj4gKwkJCWRldl9lcnIoc2ZjLT5kZXYsICJSWCBETUHj gIBtZW1vcnkgbm90IG1hcHBlZFxuIik7Cj4gKwkJCXJldHVybiAtRU5PTUVNOwo+ICsJCX0KPiAr Cj4gKwkJd3JpdGVsKGFkZHIsIHNmYy0+YmFzZSArIFNGQ19SRUdfTUVNX0FERFIpOwo+ICsJCWJy ZWFrOwo+ICsKPiArCWNhc2UgU1BJX01FTV9EQVRBX09VVDoKPiArCQlhZGRyID0gZG1hX21hcF9z aW5nbGUoc2ZjLT5kZXYsICh2b2lkICopb3AtPmRhdGEuYnVmLm91dCwKPiArCQkJCW9wLT5kYXRh Lm5ieXRlcywgRE1BX1RPX0RFVklDRSk7Cj4gKwkJaWYgKGRtYV9tYXBwaW5nX2Vycm9yKHNmYy0+ ZGV2LCBhZGRyKSkgewo+ICsJCQlkZXZfZXJyKHNmYy0+ZGV2LCAiVFggRE1B44CAbWVtb3J5IG5v dCBtYXBwZWRcbiIpOwo+ICsJCQlyZXR1cm4gLUVOT01FTTsKPiArCQl9Cj4gKwo+ICsJCXdyaXRl bChhZGRyLCBzZmMtPmJhc2UgKyBTRkNfUkVHX01FTV9BRERSKTsKPiArCQlicmVhazsKPiArCj4g KwlkZWZhdWx0Ogo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXdyaXRlbChUUklH X1NUQVJULCBzZmMtPmJhc2UgKyBTRkNfUkVHX1RSSUcpOwo+ICsKPiArCXJldCA9IHdhaXRfZm9y X2NvbXBsZXRpb25fdGltZW91dCgmc2ZjLT5jb21wbGV0aW9uLAo+ICsJCQltc2Vjc190b19qaWZm aWVzKElOR0VOSUNfU0ZDX1RSQU5TRkVSX1RJTUVPVVQpKTsKPiArCWlmICghcmV0KSB7Cj4gKwkJ d3JpdGVsKDB4MWYsIHNmYy0+YmFzZSArIFNGQ19SRUdfSU5UQyk7Cj4gKwkJd3JpdGVsKDB4MWYs IHNmYy0+YmFzZSArIFNGQ19SRUdfU0NSKTsKPiArCQlkZXZfZXJyKHNmYy0+ZGV2LCAibGluZTol ZCBUaW1lb3V0IGZvciBBQ0sgZnJvbSBTRkMgZGV2aWNlXG4iLCAKPiBfX0xJTkVfXyk7Cj4gKwkJ cmV0dXJuIC1FVElNRURPVVQ7Cj4gKwl9Cj4gKwo+ICsJZG1hX3VubWFwX3NpbmdsZShzZmMtPmRl diwgYWRkciwgb3AtPmRhdGEubmJ5dGVzLAo+ICsJCQlvcC0+ZGF0YS5kaXIgPT0gU1BJX01FTV9E QVRBX0lOID8gRE1BX0ZST01fREVWSUNFIDogCj4gRE1BX1RPX0RFVklDRSk7CgpVc2UgYSBzbWFs bCBpbmxpbmUgZnVuY3Rpb24gZm9yIHRoYXQgdG9vLiBNeSBwZXJzb25hbCBydWxlIGlzIHRoYXQg PzogCmlzIGZpbmUgaWYgdGhlIGxpbmUgZml0cyBpbiA4MCBjaGFyYWN0ZXJzLCBidXQgaWYgeW91 IGhhdmUgdG8gYnJlYWssIAp0aGVuIHlvdSByZWFsbHkgbmVlZCB0byBtb3ZlIGl0IHNvbWV3aGVy ZSBlbHNlLgoKPiArCj4gKwl3cml0ZWwoSU5UQ19NQVNLX0VORCwgc2ZjLT5iYXNlICsgU0ZDX1JF R19TQ1IpOwo+ICsJd3JpdGVsKFRSSUdfU1RPUCwgc2ZjLT5iYXNlICsgU0ZDX1JFR19UUklHKTsK PiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBpbmdlbmljX3NmY19leGVj X29wKHN0cnVjdCBzcGlfbWVtICptZW0sIGNvbnN0IHN0cnVjdCAKPiBzcGlfbWVtX29wICpvcCkK PiArewo+ICsJc3RydWN0IHNwaV9kZXZpY2UgKnNwaSA9IG1lbS0+c3BpOwo+ICsJc3RydWN0IGlu Z2VuaWNfc2ZjICpzZmMgPSBzcGlfY29udHJvbGxlcl9nZXRfZGV2ZGF0YShzcGktPm1hc3Rlcik7 Cj4gKwl1aW50cHRyX3QgYWRkciA9ICh1aW50cHRyX3Qpb3AtPmRhdGEuYnVmLmluOwo+ICsKPiAr CWluaXRfY29tcGxldGlvbigmc2ZjLT5jb21wbGV0aW9uKTsKPiArCj4gKwlzd2l0Y2ggKG9wLT5k YXRhLmRpcikgewo+ICsJY2FzZSBTUElfTUVNX0RBVEFfSU46Cj4gKwkJaWYgKHNmYy0+c29jX2lu Zm8tPnZlcnNpb24gPj0gSURfWDE2MDAgfHwgSVNfQUxJR05FRChhZGRyLCA0KSkKPiArCQkJYnJl YWs7Cj4gKwo+ICsJCWZhbGx0aHJvdWdoOwo+ICsKPiArCWNhc2UgU1BJX01FTV9OT19EQVRBOgo+ ICsJCXJldHVybiBpbmdlbmljX3NmY19leGVjX29wX3BpbyhzZmMsIG9wKTsKPiArCj4gKwlkZWZh dWx0Ogo+ICsJCWJyZWFrOwo+ICsJfQo+ICsKPiArCXJldHVybiBpbmdlbmljX3NmY19leGVjX29w X2RtYShzZmMsIG9wKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBpbmdlbmljX3NmY19wb2xsX3N0 YXR1cyhzdHJ1Y3Qgc3BpX21lbSAqbWVtLCBjb25zdCBzdHJ1Y3QgCj4gc3BpX21lbV9vcCAqb3As Cj4gKwkJCXUxNiBtYXNrLCB1MTYgbWF0Y2gsIHVuc2lnbmVkIGxvbmcgaW5pdGlhbF9kZWxheV91 cywKPiArCQkJdW5zaWduZWQgbG9uZyBwb2xsaW5nX2RlbGF5X3VzLCB1bnNpZ25lZCBsb25nIHRp bWVvdXRfbXMpCj4gK3sKPiArCXN0cnVjdCBzcGlfZGV2aWNlICpzcGkgPSBtZW0tPnNwaTsKPiAr CXN0cnVjdCBpbmdlbmljX3NmYyAqc2ZjID0gc3BpX2NvbnRyb2xsZXJfZ2V0X2RldmRhdGEoc3Bp LT5tYXN0ZXIpOwo+ICsJaW50IHJldCwgdmFsOwo+ICsKPiArCWluaXRfY29tcGxldGlvbigmc2Zj LT5jb21wbGV0aW9uKTsKPiArCj4gKwl2YWwgPSByZWFkbChzZmMtPmJhc2UgKyBTRkNfUkVHX0dM Qik7Cj4gKwl1MzJwX3JlcGxhY2VfYml0cygmdmFsLCBHTEJfVFJBTl9ESVJfUkVBRCwgR0xCX1RS QU5fRElSX01BU0spOwo+ICsJdTMycF9yZXBsYWNlX2JpdHMoJnZhbCwgR0xCX09QX01PREVfU0xB VkUsIEdMQl9PUF9NT0RFX01BU0spOwo+ICsJd3JpdGVsKHZhbCwgc2ZjLT5iYXNlICsgU0ZDX1JF R19HTEIpOwo+ICsKPiArCXdyaXRlbChtYXRjaCwgc2ZjLT5iYXNlICsgU0ZDX1JFR19ERVZfU1RB X0VYUCk7Cj4gKwl3cml0ZWwobWFzaywgc2ZjLT5iYXNlICsgU0ZDX1JFR19ERVZfU1RBX01TSyk7 Cj4gKwo+ICsJdmFsID0gVFJBTl9DT05GX1BPTExfRU4gfCBUUkFOX0NPTkZfQ01EX0VOIHwgb3At PmNtZC5vcGNvZGU7Cj4gKwo+ICsJaWYgKG9wLT5hZGRyLm5ieXRlcyA+IDApIHsKPiArCQl2YWwg fD0gRklFTERfUFJFUChUUkFOX0NPTkZfQUREUl9XSURUSF9NQVNLLCBvcC0+YWRkci5uYnl0ZXMp Owo+ICsKPiArCQl3cml0ZWwob3AtPmFkZHIudmFsICYgMHhmZmZmZmZmZiwgc2ZjLT5iYXNlICsg U0ZDX1JFR19ERVZfQUREUigwKSk7Cj4gKwkJd3JpdGVsKG9wLT5hZGRyLnZhbCA+PiAzMiwgc2Zj LT5iYXNlICsgU0ZDX1JFR19ERVZfQUREUl9QTFVTKDApKTsKPiArCX0KPiArCj4gKwlpZiAob3At PmR1bW15Lm5ieXRlcyA+IDApCj4gKwkJdmFsIHw9IEZJRUxEX1BSRVAoVFJBTl9DT05GX0RNWV9C SVRTX01BU0ssCj4gKwkJCQlvcC0+ZHVtbXkubmJ5dGVzICogOCAvIG9wLT5kdW1teS5idXN3aWR0 aCk7Cj4gKwo+ICsJaWYgKG9wLT5kYXRhLm5ieXRlcyA+IDApCj4gKwkJdmFsIHw9IFRSQU5fQ09O Rl9EQVRBX0VOOwo+ICsKPiArCXdyaXRlbCh2YWwsIHNmYy0+YmFzZSArIFNGQ19SRUdfVFJBTl9D T05GKDApKTsKPiArCXdyaXRlbChvcC0+ZGF0YS5uYnl0ZXMsIHNmYy0+YmFzZSArIFNGQ19SRUdf VFJBTl9MRU4pOwo+ICsKPiArCWluZ2VuaWNfc2ZjX3NldF90cmFuc2Zlcl9tb2RlKHNmYywgb3Ap Owo+ICsKPiArCXdyaXRlbCgweDFmLCBzZmMtPmJhc2UgKyBTRkNfUkVHX1NDUik7Cj4gKwl3cml0 ZWwofklOVENfTUFTS19FTkQsIHNmYy0+YmFzZSArIFNGQ19SRUdfSU5UQyk7Cj4gKwo+ICsJd3Jp dGVsKDAsIHNmYy0+YmFzZSArIFNGQ19SRUdfTUVNX0FERFIpOwo+ICsKPiArCXdyaXRlbChUUklH X1NUQVJULCBzZmMtPmJhc2UgKyBTRkNfUkVHX1RSSUcpOwo+ICsKPiArCXJldCA9IHdhaXRfZm9y X2NvbXBsZXRpb25fdGltZW91dCgmc2ZjLT5jb21wbGV0aW9uLAo+ICsJCQltc2Vjc190b19qaWZm aWVzKElOR0VOSUNfU0ZDX1RSQU5TRkVSX1RJTUVPVVQpKTsKPiArCWlmICghcmV0KSB7Cj4gKwkJ d3JpdGVsKDB4MWYsIHNmYy0+YmFzZSArIFNGQ19SRUdfSU5UQyk7Cj4gKwkJd3JpdGVsKDB4MWYs IHNmYy0+YmFzZSArIFNGQ19SRUdfU0NSKTsKPiArCQlkZXZfZXJyKHNmYy0+ZGV2LCAibGluZTol ZCBUaW1lb3V0IGZvciBBQ0sgZnJvbSBTRkMgZGV2aWNlXG4iLCAKPiBfX0xJTkVfXyk7Cj4gKwkJ cmV0dXJuIC1FVElNRURPVVQ7Cj4gKwl9Cj4gKwo+ICsJd3JpdGVsKFNDUl9DTFJfRU5ELCBzZmMt PmJhc2UgKyBTRkNfUkVHX1NDUik7Cj4gKwl3cml0ZWwoVFJJR19TVE9QLCBzZmMtPmJhc2UgKyBT RkNfUkVHX1RSSUcpOwo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgY29uc3Qg c3RydWN0IHNwaV9jb250cm9sbGVyX21lbV9vcHMgaW5nZW5pY19zZmNfbWVtX29wcyA9IHsKPiAr CS5hZGp1c3Rfb3Bfc2l6ZSA9IGluZ2VuaWNfc2ZjX2FkanVzdF9vcF9zaXplLAo+ICsJLnN1cHBv cnRzX29wID0gaW5nZW5pY19zZmNfc3VwcG9ydHNfb3AsCj4gKwkuZXhlY19vcCA9IGluZ2VuaWNf c2ZjX2V4ZWNfb3AsCj4gKwkucG9sbF9zdGF0dXMgPSBpbmdlbmljX3NmY19wb2xsX3N0YXR1cywK PiArfTsKPiArCj4gK3N0YXRpYyBpbnQgaW5nZW5pY19zZmNfc2V0dXAoc3RydWN0IHNwaV9kZXZp Y2UgKnNwaSkKPiArewo+ICsJc3RydWN0IGluZ2VuaWNfc2ZjICpzZmMgPSBzcGlfY29udHJvbGxl cl9nZXRfZGV2ZGF0YShzcGktPm1hc3Rlcik7Cj4gKwl1bnNpZ25lZCBsb25nIHJhdGU7Cj4gKwlp bnQgcmV0LCB2YWw7Cj4gKwo+ICsJaWYgKCFzcGktPm1heF9zcGVlZF9oeikKPiArCQlyZXR1cm4g LUVJTlZBTDsKCk1heWJlIHNldCBhIHNhbmUgZGVmYXVsdD8KCj4gKwo+ICsJcmV0ID0gY2xrX3Nl dF9yYXRlKHNmYy0+Y2xrLCBzcGktPm1heF9zcGVlZF9oeiAqIDIpOwo+ICsJaWYgKHJldCkKPiAr CQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwl3cml0ZWwoVFJJR19TVE9QLCBzZmMtPmJhc2UgKyBT RkNfUkVHX1RSSUcpOwo+ICsJd3JpdGVsKDAsIHNmYy0+YmFzZSArIFNGQ19SRUdfREVWX0NPTkYp Owo+ICsJd3JpdGVsKDAsIHNmYy0+YmFzZSArIFNGQ19SRUdfQ0dFKTsKPiArCj4gKwl2YWwgPSBy ZWFkbChzZmMtPmJhc2UgKyBTRkNfUkVHX0dMQik7Cj4gKwl1MzJwX3JlcGxhY2VfYml0cygmdmFs LCA2NCAtIDEsIEdMQl9USFJFU0hPTERfTUFTSyk7Cj4gKwl3cml0ZWwodmFsLCBzZmMtPmJhc2Ug KyBTRkNfUkVHX0dMQik7Cj4gKwo+ICsJdmFsID0gcmVhZGwoc2ZjLT5iYXNlICsgU0ZDX1JFR19E RVZfQ09ORik7Cj4gKwo+ICsJLyogY3BoYSBiaXQ6MCAsIGNwb2wgYml0OjAgKi8KPiArCXZhbCAm PSB+KERFVl9DT05GX0NQSEEgfCBERVZfQ09ORl9DUE9MKTsKPiArCXZhbCB8PSBzcGktPm1vZGUg JiBTUElfQ1BIQSA/IERFVl9DT05GX0NQSEEgOiAwOwo+ICsJdmFsIHw9IHNwaS0+bW9kZSAmIFNQ SV9DUE9MID8gREVWX0NPTkZfQ1BPTCA6IDA7Cj4gKwo+ICsJLyogY2VfZGwgYml0OjEsIGhvbGQg Yml0OjEsIHdwIGJpdDoxICovCj4gKwl2YWwgfD0gKERFVl9DT05GX0NFX0RMIHwgREVWX0NPTkZf SE9MRF9ETCB8IERFVl9DT05GX1dQX0RMKTsKPiArCj4gKwl3cml0ZWwodmFsLCBzZmMtPmJhc2Ug KyBTRkNfUkVHX0RFVl9DT05GKTsKPiArCj4gKwl2YWwgPSByZWFkbChzZmMtPmJhc2UgKyBTRkNf UkVHX0dMQik7Cj4gKwl1MzJwX3JlcGxhY2VfYml0cygmdmFsLCBHTEJfT1BfTU9ERV9TTEFWRSwg R0xCX09QX01PREVfTUFTSyk7Cj4gKwl3cml0ZWwodmFsLCBzZmMtPmJhc2UgKyBTRkNfUkVHX0dM Qik7Cj4gKwo+ICsJcmF0ZSA9IGNsa19nZXRfcmF0ZShzZmMtPmNsayk7CgpJJ2Qgc3VnZ2VzdCB1 c2luZyBjbGtfcm91bmRfcmF0ZSgpIGJlZm9yZSBjbGtfc2V0X3JhdGUoKSBiZWNhdXNlIHRoZW4g CnlvdSBrbm93IHdoYXQgZnJlcXVlbmN5IGl0J3MgZ29pbmcgdG8gYmUsIGFuZCB5b3UgZG9uJ3Qg aGF2ZSB0byBjYWxsIApjbGtfZ2V0X3JhdGUoKSBhZnRlcndhcmRzLgoKQ2hlZXJzLAotUGF1bAoK PiArCXZhbCA9IHJlYWRsKHNmYy0+YmFzZSArIFNGQ19SRUdfREVWX0NPTkYpOwo+ICsJaWYgKHNm Yy0+c29jX2luZm8tPnZlcnNpb24gPj0gSURfWDE2MDAgJiYgcmF0ZSA+PSAyMDAwMDAwMDApCj4g KwkJdTMycF9yZXBsYWNlX2JpdHMoJnZhbCwgREVWX0NPTkZfU01QX0RFTEFZXzE4MERFRywgCj4g REVWX0NPTkZfU01QX0RFTEFZX01BU0spOwo+ICsJZWxzZSBpZiAoc2ZjLT5zb2NfaW5mby0+dmVy c2lvbiA9PSBJRF9YMTAwMCAmJiByYXRlID49IDEwMDAwMDAwMCkKPiArCQl1MzJwX3JlcGxhY2Vf Yml0cygmdmFsLCBERVZfQ09ORl9TTVBfREVMQVlfSEFMRl9DWUNMRSwgCj4gREVWX0NPTkZfU01Q X0RFTEFZX01BU0spOwo+ICsJd3JpdGVsKHZhbCwgc2ZjLT5iYXNlICsgU0ZDX1JFR19ERVZfQ09O Rik7Cj4gKwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgaW5nZW5pY19zZmNf cHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKPiArewo+ICsJc3RydWN0IGluZ2Vu aWNfc2ZjICpzZmM7Cj4gKwlzdHJ1Y3Qgc3BpX2NvbnRyb2xsZXIgKmN0bHI7Cj4gKwlpbnQgcmV0 Owo+ICsKPiArCWN0bHIgPSBzcGlfYWxsb2NfbWFzdGVyKCZwZGV2LT5kZXYsIHNpemVvZigqc2Zj KSk7Cj4gKwlpZiAoIWN0bHIpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJc2ZjID0gc3Bp X2NvbnRyb2xsZXJfZ2V0X2RldmRhdGEoY3Rscik7Cj4gKwo+ICsJc2ZjLT5zb2NfaW5mbyA9IG9m X2RldmljZV9nZXRfbWF0Y2hfZGF0YSgmcGRldi0+ZGV2KTsKPiArCWlmICghc2ZjLT5zb2NfaW5m bykgewo+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgIk5vIG9mIG1hdGNoIGRhdGEgcHJvdmlkZWRc biIpOwo+ICsJCXJldCA9IC1FTk9ERVY7Cj4gKwkJZ290byBlcnJfcHV0X21hc3RlcjsKPiArCX0K PiArCj4gKwlzZmMtPmJhc2UgPSBkZXZtX3BsYXRmb3JtX2lvcmVtYXBfcmVzb3VyY2UocGRldiwg MCk7Cj4gKwlpZiAoSVNfRVJSKHNmYy0+YmFzZSkpIHsKPiArCQlyZXQgPSBQVFJfRVJSKHNmYy0+ YmFzZSk7Cj4gKwkJZ290byBlcnJfcHV0X21hc3RlcjsKPiArCX0KPiArCj4gKwlzZmMtPmNsayA9 IGRldm1fY2xrX2dldCgmcGRldi0+ZGV2LCAic2ZjIik7Cj4gKwlpZiAoSVNfRVJSKHNmYy0+Y2xr KSkgewo+ICsJCXJldCA9IElTX0VSUihzZmMtPmNsayk7Cj4gKwkJZ290byBlcnJfcHV0X21hc3Rl cjsKPiArCX0KPiArCj4gKwlyZXQgPSBjbGtfcHJlcGFyZV9lbmFibGUoc2ZjLT5jbGspOwo+ICsJ aWYgKHJldCkKPiArCQlnb3RvIGVycl9wdXRfbWFzdGVyOwo+ICsKPiArCXNmYy0+aXJxID0gcGxh dGZvcm1fZ2V0X2lycShwZGV2LCAwKTsKPiArCWlmIChzZmMtPmlycSA8IDApIHsKPiArCQlyZXQg PSBzZmMtPmlycTsKPiArCQlnb3RvIGVycl9wdXRfbWFzdGVyOwo+ICsJfQo+ICsKPiArCXNmYy0+ ZGV2ID0gJnBkZXYtPmRldjsKPiArCj4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBzZmMp Owo+ICsKPiArCXJldCA9IGRldm1fcmVxdWVzdF9pcnEoJnBkZXYtPmRldiwgc2ZjLT5pcnEsIAo+ IGluZ2VuaWNfc2ZjX2lycV9oYW5kbGVyLCAwLAo+ICsJCQlkZXZfbmFtZSgmcGRldi0+ZGV2KSwg c2ZjKTsKPiArCWlmIChyZXQpIHsKPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJGYWlsZWQgdG8g cmVxdWVzdCBpcnElZCwgcmV0ID0gJWRcbiIsIAo+IHNmYy0+aXJxLCByZXQpOwo+ICsJCWdvdG8g ZXJyX3B1dF9tYXN0ZXI7Cj4gKwl9Cj4gKwo+ICsJY3Rsci0+YnVzX251bSA9IC0xOwo+ICsJY3Rs ci0+bnVtX2NoaXBzZWxlY3QgPSAxOwo+ICsJY3Rsci0+bWVtX29wcyA9ICZpbmdlbmljX3NmY19t ZW1fb3BzOwo+ICsJY3Rsci0+ZGV2Lm9mX25vZGUgPSBwZGV2LT5kZXYub2Zfbm9kZTsKPiArCWN0 bHItPnNldHVwID0gaW5nZW5pY19zZmNfc2V0dXA7Cj4gKwljdGxyLT5tb2RlX2JpdHMgPSBTUElf Q1BIQSB8IFNQSV9DUE9MIHwKPiArCQkJU1BJX1JYX0RVQUwgfCBTUElfUlhfUVVBRCB8IFNQSV9U WF9EVUFMIHwgU1BJX1RYX1FVQUQ7Cj4gKwlpZiAoc2ZjLT5zb2NfaW5mby0+dmVyc2lvbiA+PSBJ RF9YMjAwMCkKPiArCQljdGxyLT5tb2RlX2JpdHMgfD0gU1BJX1JYX09DVEFMIHwgU1BJX1RYX09D VEFMOwo+ICsKPiArCXJldCA9IGRldm1fc3BpX3JlZ2lzdGVyX2NvbnRyb2xsZXIoJnBkZXYtPmRl diwgY3Rscik7Cj4gKwlpZiAocmV0KQo+ICsJCWdvdG8gZXJyX3B1dF9tYXN0ZXI7Cj4gKwo+ICsJ cmV0dXJuIDA7Cj4gKwo+ICtlcnJfcHV0X21hc3RlcjoKPiArCXNwaV9tYXN0ZXJfcHV0KGN0bHIp Owo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaW5n ZW5pY19zb2NfaW5mbyB4MTAwMF9zb2NfaW5mbyA9IHsKPiArCS52ZXJzaW9uID0gSURfWDEwMDAs Cj4gKwo+ICsJLm1heF9idXNfd2lkdGggPSA0LAo+ICsKPiArCS50cmFuX21vZGVfbWFzayA9IFRS QU5fQ09ORl9UUkFOX01PREVfTUFTSywKPiArfTsKPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qg aW5nZW5pY19zb2NfaW5mbyB4MTYwMF9zb2NfaW5mbyA9IHsKPiArCS52ZXJzaW9uID0gSURfWDE2 MDAsCj4gKwo+ICsJLm1heF9idXNfd2lkdGggPSA0LAo+ICsKPiArCS50cmFuX21vZGVfbWFzayA9 IFRSQU5fQ09ORl9UUkFOX01PREVfTUFTSywKPiArfTsKPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1 Y3QgaW5nZW5pY19zb2NfaW5mbyB4MjAwMF9zb2NfaW5mbyA9IHsKPiArCS52ZXJzaW9uID0gSURf WDIwMDAsCj4gKwo+ICsJLm1heF9idXNfd2lkdGggPSA4LAo+ICsKPiArCS50cmFuX21vZGVfbWFz ayA9IFRSQU5fQ0ZHMV9UUkFOX01PREVfTUFTSywKPiArfTsKPiArCj4gK3N0YXRpYyBjb25zdCBz dHJ1Y3Qgb2ZfZGV2aWNlX2lkIGluZ2VuaWNfc2ZjX29mX21hdGNoZXNbXSA9IHsKPiArCXsgLmNv bXBhdGlibGUgPSAiaW5nZW5pYyx4MTAwMC1zZmMiLCAuZGF0YSA9ICZ4MTAwMF9zb2NfaW5mbyB9 LAo+ICsJeyAuY29tcGF0aWJsZSA9ICJpbmdlbmljLHgxNjAwLXNmYyIsIC5kYXRhID0gJngxNjAw X3NvY19pbmZvIH0sCj4gKwl7IC5jb21wYXRpYmxlID0gImluZ2VuaWMseDIwMDAtc2ZjIiwgLmRh dGEgPSAmeDIwMDBfc29jX2luZm8gfSwKPiArCXsgLyogc2VudGluZWwgKi8gfQo+ICt9Owo+ICtN T0RVTEVfREVWSUNFX1RBQkxFKG9mLCBpbmdlbmljX3NmY19vZl9tYXRjaGVzKTsKPiArCj4gK3N0 YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGluZ2VuaWNfc2ZjX2RyaXZlciA9IHsKPiArCS5k cml2ZXIgPSB7Cj4gKwkJLm5hbWUgPSAiaW5nZW5pYy1zZmMiLAo+ICsJCS5vZl9tYXRjaF90YWJs ZSA9IGluZ2VuaWNfc2ZjX29mX21hdGNoZXMsCj4gKwl9LAo+ICsJLnByb2JlID0gaW5nZW5pY19z ZmNfcHJvYmUsCj4gK307Cj4gK21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIoaW5nZW5pY19zZmNfZHJp dmVyKTsKPiArCj4gK01PRFVMRV9MSUNFTlNFKCJHUEwiKTsKPiArTU9EVUxFX0FVVEhPUigi5ZGo 55Cw5p2wIChaaG91IFlhbmppZSkgPHpob3V5YW5qaWVAd2FueWVldGVjaC5jb20+Iik7Cj4gK01P RFVMRV9ERVNDUklQVElPTigiSW5nZW5pYyBTb0NzIFNQSSBGbGFzaCBDb250cm9sbGVyIERyaXZl ciIpOwo+IC0tCj4gMi43LjQKPiAKCgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fCkxpbnV4IE1URCBkaXNjdXNzaW9uIG1haWxpbmcgbGlzdApo dHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4LW10ZC8K