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.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS 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 28026C433DB for ; Tue, 22 Dec 2020 13:51:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E119B23105 for ; Tue, 22 Dec 2020 13:51:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727261AbgLVNv0 (ORCPT ); Tue, 22 Dec 2020 08:51:26 -0500 Received: from esa.microchip.iphmx.com ([68.232.153.233]:31094 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726904AbgLVNvZ (ORCPT ); Tue, 22 Dec 2020 08:51:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1608645083; x=1640181083; h=message-id:subject:from:to:cc:date:in-reply-to: references:mime-version:content-transfer-encoding; bh=hrj6leNWbiNlB1yMhkWpxPniGijUhb9xanYr79R/vXk=; b=MA8QtgbjIwFTbNdR9DSkf7BUd5AytilrS/Oyl9CMrwQGJBcqOVXR6r/j sR7MDwKb0F6APAix+W/yTvOPypbtbeGvzTjQMfY1IfIImIILDUS6QbhY4 k91qaQM+XkaQIuaGSwks5Jb0ntDv8PIsaT5eorJ15rwLkeN7YqcJjRivN zC3PPXkEkX/ZF04SLNE5fuUYyfjIqipPQH9Ox7palkPkdNqEcOFOz3enU 6siu9a5UaLPky3kJcD3Gutr0p6gK4/C4zuD6b5nejEpmHhaY9gv8YjxWZ bNb4c2pEPBQIQDcX6GxZeWnZtPXPsCTXLK/tpmNFI4b/z/nyPRC5OmIca g==; IronPort-SDR: L58ZmoQhv43ANMv4/H6fcZ5gbRm+5/gqDap2fMIvR3bX3rVtLf011lbPfBolS/o73CAgkZ1MxG jsUZL5cHAEgpISbBX2OHlV/F7x9siPqBSo1OV3JujHWv47lhZvl3aRIEk1mcnKfZr+a7w9KEuy Qn1PkbM0R5scjnByVA8UkmUkfAGEAdKbUP15PWV/dsY7wQlkVgeDCy870Uqrw7urGMkASIH+Qc fyN4RG75kh+K4jFQutFqHwO1U7wlsJr8+H1DFtWDb3a7xNob/4he5KFV/Sl0hCURKqmfUKoSM1 Zc4= X-IronPort-AV: E=Sophos;i="5.78,438,1599548400"; d="scan'208";a="108586615" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Dec 2020 06:50:07 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Tue, 22 Dec 2020 06:50:06 -0700 Received: from tyr.hegelund-hansen.dk (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Tue, 22 Dec 2020 06:50:03 -0700 Message-ID: <37309f64bf0bb94e55bc2db4c482c1e3e7f1be6f.camel@microchip.com> Subject: Re: [RFC PATCH v2 2/8] net: sparx5: add the basic sparx5 driver From: Steen Hegelund To: Andrew Lunn CC: "David S. Miller" , Jakub Kicinski , Russell King , Lars Povlsen , Bjarni Jonasson , Microchip Linux Driver Support , Alexandre Belloni , Madalin Bucur , Nicolas Ferre , Mark Einon , Masahiro Yamada , "Arnd Bergmann" , , , Date: Tue, 22 Dec 2020 14:50:02 +0100 In-Reply-To: <20201219191157.GC3026679@lunn.ch> References: <20201217075134.919699-1-steen.hegelund@microchip.com> <20201217075134.919699-3-steen.hegelund@microchip.com> <20201219191157.GC3026679@lunn.ch> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.38.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Andrew, On Sat, 2020-12-19 at 20:11 +0100, Andrew Lunn wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > On Thu, Dec 17, 2020 at 08:51:28AM +0100, Steen Hegelund wrote: > > > +static struct sparx5_io_resource sparx5_iomap[] =  { > > This could be made const i think,. Yes > > > +     { TARGET_DEV2G5,         0,         0 }, /* 0x610004000: > > dev2g5_0 */ > > +     { TARGET_DEV5G,          0x4000,    0 }, /* 0x610008000: > > dev5g_0 */ > > +     { TARGET_PCS5G_BR,       0x8000,    0 }, /* 0x61000c000: > > pcs5g_br_0 */ > > +     { TARGET_DEV2G5 + 1,     0xc000,    0 }, /* 0x610010000: > > dev2g5_1 */ > > > +static int sparx5_create_targets(struct sparx5 *sparx5) > > +{ > > +     int idx, jdx; > > +     struct resource *iores[IO_RANGES]; > > +     void __iomem *iomem[IO_RANGES]; > > +     void __iomem *begin[IO_RANGES]; > > +     int range_id[IO_RANGES]; > > Reverse Christmas tree. idx, jdx need to come last. Yes - I will check the entire file for RCT... > > > + > > +     /* Check if done previously (deferred by serdes load) */ > > +     if (sparx5->regs[sparx5_iomap[0].id]) > > +             return 0; > > Could you explain this a bit more. Do you mean -EPROBE_DEFER? Yes that was the intended usage. I will change the startup flow to try to avoid checking this- > > > +static int sparx5_probe_port(struct sparx5 *sparx5, > > +                          struct device_node *portnp, > > +                          struct phy *serdes, > > +                          u32 portno, > > +                          struct sparx5_port_config *conf) > > +{ > > +     struct sparx5_port *spx5_port; > > +     struct net_device *ndev; > > +     int err; > > + > > +     err = sparx5_create_targets(sparx5); > > +     if (err) > > +             return err; > > This sees odd here. Don't sparx5_create_targets() create all the > targets, where as this creates one specific port? Seems like > sparx5_create_targets() should be in the devices as a whole probe, > not > the port probe. You are right - the name does not really fit (anymore). I will rework this. > > > +     spx5_port = netdev_priv(ndev); > > +     spx5_port->of_node = portnp; > > +     spx5_port->serdes = serdes; > > +     spx5_port->pvid = NULL_VID; > > +     spx5_port->signd_internal = true; > > +     spx5_port->signd_active_high = true; > > +     spx5_port->signd_enable = true; > > +     spx5_port->flow_control = false; > > +     spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE; > > +     spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE; > > +     spx5_port->custom_etype = 0x8880; /* Vitesse */ > > +     conf->portmode = conf->phy_mode; > > +     spx5_port->conf.speed = SPEED_UNKNOWN; > > +     spx5_port->conf.power_down = true; > > +     sparx5->ports[portno] = spx5_port; > > +     return 0; > > I'm also not sure this has the correct name. This does not look like > a > typical probe function. Agree. > > > > +} > > + > > +static int sparx5_init_switchcore(struct sparx5 *sparx5) > > +{ > > +     u32 value, pending, jdx, idx; > > +     struct { > > +             bool gazwrap; > > +             void __iomem *init_reg; > > +             u32  init_val; > > +     } ram, ram_init_list[] = { > > +             {false, spx5_reg_get(sparx5, ANA_AC_STAT_RESET), > > +              ANA_AC_STAT_RESET_RESET}, > > +             {false, spx5_reg_get(sparx5, ASM_STAT_CFG), > > +              ASM_STAT_CFG_STAT_CNT_CLR_SHOT}, > > +             {true,  spx5_reg_get(sparx5, QSYS_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, REW_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, VOP_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, ANA_AC_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, ASM_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, EACL_RAM_INIT), 0}, > > +             {true,  spx5_reg_get(sparx5, VCAP_SUPER_RAM_INIT), > > 0}, > > +             {true,  spx5_reg_get(sparx5, DSM_RAM_INIT), 0} > > +     }; > > Looks like this could be const as well. And this does not really fit > reverse christmas tree. I will update this. > > > + > > +     spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(1), > > +              EACL_POL_EACL_CFG_EACL_FORCE_INIT, > > +              sparx5, > > +              EACL_POL_EACL_CFG); > > + > > +     spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(0), > > +              EACL_POL_EACL_CFG_EACL_FORCE_INIT, > > +              sparx5, > > +              EACL_POL_EACL_CFG); > > + > > +     /* Initialize memories, if not done already */ > > +     value = spx5_rd(sparx5, HSCH_RESET_CFG); > > + > > +     if (!(value & HSCH_RESET_CFG_CORE_ENA)) { > > +             for (idx = 0; idx < 10; idx++) { > > +                     pending = ARRAY_SIZE(ram_init_list); > > +                     for (jdx = 0; jdx < > > ARRAY_SIZE(ram_init_list); jdx++) { > > +                             ram = ram_init_list[jdx]; > > +                             if (ram.gazwrap) > > +                                     ram.init_val = > > QSYS_RAM_INIT_RAM_INIT; > > + > > +                             if (idx == 0) { > > +                                     writel(ram.init_val, > > ram.init_reg); > > +                             } else { > > +                                     value = readl(ram.init_reg); > > +                                     if ((value & ram.init_val) != > > +                                         ram.init_val) { > > +                                             pending--; > > +                                     } > > +                             } > > +                     } > > +                     if (!pending) > > +                             break; > > +                     usleep_range(USEC_PER_MSEC, 2 * > > USEC_PER_MSEC); > > +             } > > You are getting pretty deeply nested here. Might be better to pull > this out into a helpers. Yes. > > > + > > +             if (pending > 0) { > > +                     /* Still initializing, should be complete in > > +                      * less than 1ms > > +                      */ > > +                     dev_err(sparx5->dev, "Memory initialization > > error\n"); > > +                     return -EINVAL; > > +             } > > +     } > > + > > +     /* Reset counters */ > > +     spx5_wr(ANA_AC_STAT_RESET_RESET_SET(1), sparx5, > > ANA_AC_STAT_RESET); > > +     spx5_wr(ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(1), sparx5, > > ASM_STAT_CFG); > > + > > +     /* Enable switch-core and queue system */ > > +     spx5_wr(HSCH_RESET_CFG_CORE_ENA_SET(1), sparx5, > > HSCH_RESET_CFG); > > + > > +     return 0; > > +} > > + > > +static int sparx5_init_coreclock(struct sparx5 *sparx5) > > +{ > > +     u32 clk_div, clk_period, pol_upd_int, idx; > > +     enum sparx5_core_clockfreq freq = sparx5->coreclock; > > More reverse christmas tree. Please review the whole driver. I will do that. > > > + > > +     /* Verify if core clock frequency is supported on target. > > +      * If 'VTSS_CORE_CLOCK_DEFAULT' then the highest supported > > +      * freq. is used > > +      */ > > +     switch (sparx5->target_ct) { > > +     case SPX5_TARGET_CT_7546: > > +             if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) > > +                     freq = SPX5_CORE_CLOCK_250MHZ; > > +             else if (sparx5->coreclock != SPX5_CORE_CLOCK_250MHZ) > > +                     freq = 0; /* Not supported */ > > +             break; > > +     case SPX5_TARGET_CT_7549: > > +     case SPX5_TARGET_CT_7552: > > +     case SPX5_TARGET_CT_7556: > > +             if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) > > +                     freq = SPX5_CORE_CLOCK_500MHZ; > > +             else if (sparx5->coreclock != SPX5_CORE_CLOCK_500MHZ) > > +                     freq = 0; /* Not supported */ > > +             break; > > +     case SPX5_TARGET_CT_7558: > > +     case SPX5_TARGET_CT_7558TSN: > > +             if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) > > +                     freq = SPX5_CORE_CLOCK_625MHZ; > > +             else if (sparx5->coreclock != SPX5_CORE_CLOCK_625MHZ) > > +                     freq = 0; /* Not supported */ > > +             break; > > +     case SPX5_TARGET_CT_7546TSN: > > +             if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) > > +                     freq = SPX5_CORE_CLOCK_625MHZ; > > +             break; > > +     case SPX5_TARGET_CT_7549TSN: > > +     case SPX5_TARGET_CT_7552TSN: > > +     case SPX5_TARGET_CT_7556TSN: > > +             if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT) > > +                     freq = SPX5_CORE_CLOCK_625MHZ; > > +             else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ) > > +                     freq = 0; /* Not supported */ > > +             break; > > +     default: > > +             dev_err(sparx5->dev, "Target (%#04x) not > > supported\n", sparx5->target_ct); > > netdev is staying with 80 character lines. Please fold this, here and > every where else, where possible. The exception is, you should not > split a string. Will do. > > > +             return -ENODEV; > > +     } > > + > > +     switch (freq) { > > +     case SPX5_CORE_CLOCK_250MHZ: > > +             clk_div = 10; > > +             pol_upd_int = 312; > > +             break; > > +     case SPX5_CORE_CLOCK_500MHZ: > > +             clk_div = 5; > > +             pol_upd_int = 624; > > +             break; > > +     case SPX5_CORE_CLOCK_625MHZ: > > +             clk_div = 4; > > +             pol_upd_int = 780; > > +             break; > > +     default: > > +             dev_err(sparx5->dev, "%s: Frequency (%d) not > > supported on target (%#04x)\n", > > +                     __func__, > > +                     sparx5->coreclock, sparx5->target_ct); > > +             return 0; > > -EINVAL? Or is it not fatal to use an unsupported frequency? Yes - it should be fatal. > > > +static int sparx5_init(struct sparx5 *sparx5) > > +{ > > +     u32 idx; > > + > > +     if (sparx5_create_targets(sparx5)) > > +             return -ENODEV; > > Hum, sparx5_create_targets() again? Yes that was due to the PROBE_DEFER - but I will go over this again. > > > + > > +     /* Read chip ID to check CPU interface */ > > +     sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID); > > + > > +     sparx5->target_ct = (enum spx5_target_chiptype) > > +             GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id); > > + > > +     /* Initialize Switchcore and internal RAMs */ > > +     if (sparx5_init_switchcore(sparx5)) { > > +             dev_err(sparx5->dev, "Switchcore initialization > > error\n"); > > +             return -EINVAL; > > +     } > > + > > +     /* Initialize the LC-PLL (core clock) and set affected > > registers */ > > +     if (sparx5_init_coreclock(sparx5)) { > > +             dev_err(sparx5->dev, "LC-PLL initialization > > error\n"); > > +             return -EINVAL; > > +     } > > + > > +     /* Setup own UPSIDs */ > > +     for (idx = 0; idx < 3; idx++) { > > +             spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx)); > > +             spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx)); > > +             spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx)); > > +             spx5_wr(idx, sparx5, REW_OWN_UPSID(idx)); > > +     } > > + > > +     /* Enable switch ports */ > > +     for (idx = SPX5_PORTS; idx < SPX5_PORTS_ALL; idx++) { > > +             spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1), > > +                      QFWD_SWITCH_PORT_MODE_PORT_ENA, > > +                      sparx5, > > +                      QFWD_SWITCH_PORT_MODE(idx)); > > +     } > > What happens when you enable the ports? Why is this here, and not in > the port specific open call? The comment is not correct. This is just enabling the CPU ports, so it belongs with the other switch core initialization. I will update the comment. > > > +/* Some boards needs to map the SGPIO for signal detect explicitly > > to the > > + * port module > > + */ > > +static void sparx5_board_init(struct sparx5 *sparx5) > > +{ > > +     int idx; > > + > > +     if (!sparx5->sd_sgpio_remapping) > > +             return; > > + > > +     /* Enable SGPIO Signal Detect remapping */ > > +     spx5_rmw(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL, > > +              GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL, > > +              sparx5, > > +              GCB_HW_SGPIO_SD_CFG); > > + > > +     /* Refer to LOS SGPIO */ > > +     for (idx = 0; idx < SPX5_PORTS; idx++) { > > +             if (sparx5->ports[idx]) { > > +                     if (sparx5->ports[idx]->conf.sd_sgpio != ~0) > > { > > +                             spx5_wr(sparx5->ports[idx]- > > >conf.sd_sgpio, > > +                                     sparx5, > > +                                     > > GCB_HW_SGPIO_TO_SD_MAP_CFG(idx)); > > +                     } > > +             } > > +     } > > +} > > I've not looked at how you do SFP integration yet. Is this the LOS > from the SFP socket? Is there a Linux GPIO controller exported by > this > driver, so the SFP driver can use the GPIOs? Yes the SFP driver (used by the Sparx5 SerDes driver) will use the SGPIO LOS, Module Detect etc, and the Port Modules are aware of the location of the LOS, and use this by default without any driver configuration. But on the PCB134 the SGPIOs are shifted one bit by a mistake, and they are not located in the expected position, so we have this board remapping function to handle that aspect. > > > + > > +static int mchp_sparx5_probe(struct platform_device *pdev) > > +{ > > +     struct device_node *np = pdev->dev.of_node; > > +     struct sparx5 *sparx5; > > +     struct device_node *ports, *portnp; > > +     const u8 *mac_addr; > > +     int err = 0; > > + > > +     if (!np && !pdev->dev.platform_data) > > +             return -ENODEV; > > + > > +     sparx5 = devm_kzalloc(&pdev->dev, sizeof(*sparx5), > > GFP_KERNEL); > > +     if (!sparx5) > > +             return -ENOMEM; > > + > > +     platform_set_drvdata(pdev, sparx5); > > +     sparx5->pdev = pdev; > > +     sparx5->dev = &pdev->dev; > > + > > +     /* Default values, some from DT */ > > +     sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT; > > + > > +     mac_addr = of_get_mac_address(np); > > +     if (IS_ERR_OR_NULL(mac_addr)) { > > +             dev_info(sparx5->dev, "MAC addr was not set, use > > random MAC\n"); > > +             eth_random_addr(sparx5->base_mac); > > +             sparx5->base_mac[5] = 0; > > +     } else { > > +             ether_addr_copy(sparx5->base_mac, mac_addr); > > +     } > > The binding document does not say anything about a MAC address at the > top level. What is this used for? This the base MAC address used for generating the the switch NI's MAC addresses. > > + > > +     if (sparx5_init(sparx5)) { > > +             dev_err(sparx5->dev, "Init failed\n"); > > +             return -ENODEV; > > +     } > > +     ports = of_get_child_by_name(np, "ethernet-ports"); > > +     if (!ports) { > > +             dev_err(sparx5->dev, "no ethernet-ports child node > > found\n"); > > +             return -ENODEV; > > +     } > > +     sparx5->port_count = of_get_child_count(ports); > > + > > +     for_each_available_child_of_node(ports, portnp) { > > +             struct sparx5_port_config config = {}; > > +             u32 portno; > > +             struct phy *serdes; > > + > > +             err = of_property_read_u32(portnp, "reg", &portno); > > +             if (err) { > > +                     dev_err(sparx5->dev, "port reg property > > error\n"); > > +                     continue; > > +             } > > +             err = of_property_read_u32(portnp, "max-speed", > > +                                        &config.max_speed); > > +             if (err) { > > +                     dev_err(sparx5->dev, "port max-speed property > > error\n"); > > +                     continue; > > +             } > > +             config.speed = SPEED_UNKNOWN; > > +             err = of_property_read_u32(portnp, "sd_sgpio", > > &config.sd_sgpio); > > Not in the binding documentation. I think i need to withdraw my > Reviewed-by :-( Ooops - yes that is a mistake that these 2 items were not included. > > > +             if (err) > > +                     config.sd_sgpio = ~0; > > +             else > > +                     sparx5->sd_sgpio_remapping = true; > > +             serdes = devm_of_phy_get(sparx5->dev, portnp, NULL); > > +             if (IS_ERR(serdes)) { > > +                     err = PTR_ERR(serdes); > > +                     if (err != -EPROBE_DEFER) > > +                             dev_err(sparx5->dev, > > +                                     "missing SerDes phys for > > port%d\n", > > +                                     portno); > > +                     return err; > > +             } > > + > > +             err = of_get_phy_mode(portnp, &config.phy_mode); > > +             if (err) > > +                     config.power_down = true; > > You should indicate in the binding it is optional. And what happens > when it is missing. Will update the description. > > > +             config.media_type = ETH_MEDIA_DAC; > > +             config.serdes_reset = true; > > +             config.portmode = config.phy_mode; > > +             err = sparx5_probe_port(sparx5, portnp, serdes, > > portno, &config); > > +             if (err) { > > +                     dev_err(sparx5->dev, "port probe error\n"); > > +                     goto cleanup_ports; > > +             } > > +     } > > +     sparx5_board_init(sparx5); > > + > > +cleanup_ports: > > +     return err; > > Seems missed named, no cleanup. Ah - this comes later (as the driver was split in functional groups for reviewing). I hope this is OK, as it is only temporary - I could add a comment to that effect. > > > +static int __init sparx5_switch_reset(void) > > +{ > > +     const char *syscon_cpu = "microchip,sparx5-cpu-syscon", > > +             *syscon_gcb = "microchip,sparx5-gcb-syscon"; > > +     struct regmap *cpu_ctrl, *gcb_ctrl; > > +     u32 val; > > + > > +     cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon_cpu); > > +     if (IS_ERR(cpu_ctrl)) { > > +             pr_err("No '%s' syscon map\n", syscon_cpu); > > +             return PTR_ERR(cpu_ctrl); > > +     } > > + > > +     gcb_ctrl = syscon_regmap_lookup_by_compatible(syscon_gcb); > > +     if (IS_ERR(gcb_ctrl)) { > > +             pr_err("No '%s' syscon map\n", syscon_gcb); > > +             return PTR_ERR(gcb_ctrl); > > +     } > > + > > +     /* Make sure the core is PROTECTED from reset */ > > +     regmap_update_bits(cpu_ctrl, RESET_PROT_STAT, > > +                        SYS_RST_PROT_VCORE, SYS_RST_PROT_VCORE); > > + > > +     regmap_write(gcb_ctrl, spx5_offset(GCB_SOFT_RST), > > +                  GCB_SOFT_RST_SOFT_SWC_RST_SET(1)); > > + > > +     return readx_poll_timeout(sparx5_read_gcb_soft_rst, gcb_ctrl, > > val, > > +                               GCB_SOFT_RST_SOFT_SWC_RST_GET(val) > > == 0, > > +                               1, 100); > > +} > > +postcore_initcall(sparx5_switch_reset); > > That is pretty unusual. Why cannot this be done at probe time? The problem is that the switch core reset also affects (reset) the SGPIO controller. We tried to put this in the reset driver, but it was rejected. If the reset is done at probe time, the SGPIO driver may already have initialized state. The switch core reset will then reset all SGPIO registers. > > > +/* Clock period in picoseconds */ > > +static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq > > cclock) > > +{ > > +     switch (cclock) { > > +     case SPX5_CORE_CLOCK_250MHZ: > > +             return 4000; > > +     case SPX5_CORE_CLOCK_500MHZ: > > +             return 2000; > > +     case SPX5_CORE_CLOCK_625MHZ: > > +     default: > > +             return 1600; > > +     } > > +} > > Is this something which is used in the hot path? No - so maybe this should just be a regular function? > > > --- /dev/null > > +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h > > @@ -0,0 +1,3922 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ > > + * Microchip Sparx5 Switch driver > > + * > > + * Copyright (c) 2020 Microchip Technology Inc. > > + */ > > + > > +/* This file is autogenerated by cml-utils 2020-11-19 10:41:34 > > +0100. > > + * Commit ID: f34790e69dc252103e2cc3e85b1a5e4d9e3aa190 > > + */ > > How reproducible this is generation process? If you have to run it > again, will it keep the same order of lines? As long as the CML (Chip Markup Language) file has not changed (documentation fields not considered), this is reproducible. The tool parses the XML nodes in a deterministic order. > >        Andrew Thanks for your comments /Steen 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.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED 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 7E604C433DB for ; Tue, 22 Dec 2020 13:51:40 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (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 2463523105 for ; Tue, 22 Dec 2020 13:51:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2463523105 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=microchip.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+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=merlin.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=69c2H9dDEis7S+C5zF2zUy9OdQlpKlk+Zy2H+/3cGiM=; b=GOhvB/P+RiqTldQ4Dx9RssNsu PEn5I9Aa9gmkmHnhtGYJM3gUwE4c3Vho0zChe1Sx71kzW9xIxZHp7IGwCsRr7tuv3Fh9pg44CskR/ 31lXNweyqmRQskw56vmpWxvGp0Pn0/Ubo7wHz7ntw+Z02XBZtVjY4BzboIvl5wxPZE9i2DiVLnXv6 SZrNRKko5+8zG2l6pC2YUUukXz0w3XzbUyzQ3OQFkEFKjJrcOB1SPfT2+yK74BRSWEAmGi/yGNZY0 SJSt6WrlK8z/rUbz14bNjgCJWVRXVNBCMIl1Sd5x/UyHx/tNqIDTfsmGLIS4WC9qwITU9enqPMtiF 9emnePIzA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kri3M-0002bJ-Jx; Tue, 22 Dec 2020 13:50:16 +0000 Received: from esa.microchip.iphmx.com ([68.232.153.233]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kri3G-0002aU-GO for linux-arm-kernel@lists.infradead.org; Tue, 22 Dec 2020 13:50:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1608645010; x=1640181010; h=message-id:subject:from:to:cc:date:in-reply-to: references:mime-version:content-transfer-encoding; bh=hrj6leNWbiNlB1yMhkWpxPniGijUhb9xanYr79R/vXk=; b=MXXj6+J+hnNjeHCKa7QVc6LR3swXkmRoeCzgigqpYd0zunf0U99E8G76 beatn6Fg/a0ZYiXrlzBb+Xse2SKCIBFZ2//u4EfpKx54DTST4l3d1EiO2 Vcn3seaEa8B/Zdc367xeJ5bP5wprJIl9byMSPnu3NhcUOq7y1dUtA89Wk MAejFvypDdEPcP//ek5LlZ9uD3KxGROKRuynJYRBhkc2LGe+NK+xzao/s JLQ1PXDzbyed0wi10k443QvkWy+tfNHZBHrHhYL3dpcx20B4yfPbAEn0Q Qhp8SRxFy4ysQg8ZuHwRoQbKLnM3nMryPrx3A2eYiR6CZwwLvvshXhqJs A==; IronPort-SDR: L58ZmoQhv43ANMv4/H6fcZ5gbRm+5/gqDap2fMIvR3bX3rVtLf011lbPfBolS/o73CAgkZ1MxG jsUZL5cHAEgpISbBX2OHlV/F7x9siPqBSo1OV3JujHWv47lhZvl3aRIEk1mcnKfZr+a7w9KEuy Qn1PkbM0R5scjnByVA8UkmUkfAGEAdKbUP15PWV/dsY7wQlkVgeDCy870Uqrw7urGMkASIH+Qc fyN4RG75kh+K4jFQutFqHwO1U7wlsJr8+H1DFtWDb3a7xNob/4he5KFV/Sl0hCURKqmfUKoSM1 Zc4= X-IronPort-AV: E=Sophos;i="5.78,438,1599548400"; d="scan'208";a="108586615" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Dec 2020 06:50:07 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Tue, 22 Dec 2020 06:50:06 -0700 Received: from tyr.hegelund-hansen.dk (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.1979.3 via Frontend Transport; Tue, 22 Dec 2020 06:50:03 -0700 Message-ID: <37309f64bf0bb94e55bc2db4c482c1e3e7f1be6f.camel@microchip.com> Subject: Re: [RFC PATCH v2 2/8] net: sparx5: add the basic sparx5 driver From: Steen Hegelund To: Andrew Lunn Date: Tue, 22 Dec 2020 14:50:02 +0100 In-Reply-To: <20201219191157.GC3026679@lunn.ch> References: <20201217075134.919699-1-steen.hegelund@microchip.com> <20201217075134.919699-3-steen.hegelund@microchip.com> <20201219191157.GC3026679@lunn.ch> User-Agent: Evolution 3.38.2 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201222_085010_833852_094B12A0 X-CRM114-Status: GOOD ( 35.42 ) 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: Bjarni Jonasson , Alexandre Belloni , linux-kernel@vger.kernel.org, Arnd Bergmann , Madalin Bucur , netdev@vger.kernel.org, Masahiro Yamada , Russell King , Microchip Linux Driver Support , linux-arm-kernel@lists.infradead.org, Mark Einon , Jakub Kicinski , "David S. Miller" , Lars Povlsen Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org SGkgQW5kcmV3LAoKT24gU2F0LCAyMDIwLTEyLTE5IGF0IDIwOjExICswMTAwLCBBbmRyZXcgTHVu biB3cm90ZToKPiBFWFRFUk5BTCBFTUFJTDogRG8gbm90IGNsaWNrIGxpbmtzIG9yIG9wZW4gYXR0 YWNobWVudHMgdW5sZXNzIHlvdQo+IGtub3cgdGhlIGNvbnRlbnQgaXMgc2FmZQo+IAo+IE9uIFRo dSwgRGVjIDE3LCAyMDIwIGF0IDA4OjUxOjI4QU0gKzAxMDAsIFN0ZWVuIEhlZ2VsdW5kIHdyb3Rl Ogo+IAo+ID4gK3N0YXRpYyBzdHJ1Y3Qgc3Bhcng1X2lvX3Jlc291cmNlIHNwYXJ4NV9pb21hcFtd ID3CoCB7Cj4gCj4gVGhpcyBjb3VsZCBiZSBtYWRlIGNvbnN0IGkgdGhpbmssLgoKWWVzCgo+IAo+ ID4gK8KgwqDCoMKgIHsgVEFSR0VUX0RFVjJHNSzCoMKgwqDCoMKgwqDCoMKgIDAswqDCoMKgwqDC oMKgwqDCoCAwIH0sIC8qIDB4NjEwMDA0MDAwOgo+ID4gZGV2Mmc1XzAgKi8KPiA+ICvCoMKgwqDC oCB7IFRBUkdFVF9ERVY1RyzCoMKgwqDCoMKgwqDCoMKgwqAgMHg0MDAwLMKgwqDCoCAwIH0sIC8q IDB4NjEwMDA4MDAwOgo+ID4gZGV2NWdfMCAqLwo+ID4gK8KgwqDCoMKgIHsgVEFSR0VUX1BDUzVH X0JSLMKgwqDCoMKgwqDCoCAweDgwMDAswqDCoMKgIDAgfSwgLyogMHg2MTAwMGMwMDA6Cj4gPiBw Y3M1Z19icl8wICovCj4gPiArwqDCoMKgwqAgeyBUQVJHRVRfREVWMkc1ICsgMSzCoMKgwqDCoCAw eGMwMDAswqDCoMKgIDAgfSwgLyogMHg2MTAwMTAwMDA6Cj4gPiBkZXYyZzVfMSAqLwo+IAo+ID4g K3N0YXRpYyBpbnQgc3Bhcng1X2NyZWF0ZV90YXJnZXRzKHN0cnVjdCBzcGFyeDUgKnNwYXJ4NSkK PiA+ICt7Cj4gPiArwqDCoMKgwqAgaW50IGlkeCwgamR4Owo+ID4gK8KgwqDCoMKgIHN0cnVjdCBy ZXNvdXJjZSAqaW9yZXNbSU9fUkFOR0VTXTsKPiA+ICvCoMKgwqDCoCB2b2lkIF9faW9tZW0gKmlv bWVtW0lPX1JBTkdFU107Cj4gPiArwqDCoMKgwqAgdm9pZCBfX2lvbWVtICpiZWdpbltJT19SQU5H RVNdOwo+ID4gK8KgwqDCoMKgIGludCByYW5nZV9pZFtJT19SQU5HRVNdOwo+IAo+IFJldmVyc2Ug Q2hyaXN0bWFzIHRyZWUuIGlkeCwgamR4IG5lZWQgdG8gY29tZSBsYXN0LgoKWWVzIC0gSSB3aWxs IGNoZWNrIHRoZSBlbnRpcmUgZmlsZSBmb3IgUkNULi4uCj4gCj4gPiArCj4gPiArwqDCoMKgwqAg LyogQ2hlY2sgaWYgZG9uZSBwcmV2aW91c2x5IChkZWZlcnJlZCBieSBzZXJkZXMgbG9hZCkgKi8K PiA+ICvCoMKgwqDCoCBpZiAoc3Bhcng1LT5yZWdzW3NwYXJ4NV9pb21hcFswXS5pZF0pCj4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiAwOwo+IAo+IENvdWxkIHlvdSBleHBsYWlu IHRoaXMgYSBiaXQgbW9yZS4gRG8geW91IG1lYW4gLUVQUk9CRV9ERUZFUj8KClllcyB0aGF0IHdh cyB0aGUgaW50ZW5kZWQgdXNhZ2UuIEkgd2lsbCBjaGFuZ2UgdGhlIHN0YXJ0dXAgZmxvdyB0byB0 cnkKdG8gYXZvaWQgY2hlY2tpbmcgdGhpcy0KPiAKPiA+ICtzdGF0aWMgaW50IHNwYXJ4NV9wcm9i ZV9wb3J0KHN0cnVjdCBzcGFyeDUgKnNwYXJ4NSwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgZGV2aWNlX25vZGUgKnBvcnRucCwK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBz dHJ1Y3QgcGh5ICpzZXJkZXMsCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgdTMyIHBvcnRubywKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1X3BvcnRfY29uZmlnICpj b25mKQo+ID4gK3sKPiA+ICvCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1X3BvcnQgKnNweDVfcG9ydDsK PiA+ICvCoMKgwqDCoCBzdHJ1Y3QgbmV0X2RldmljZSAqbmRldjsKPiA+ICvCoMKgwqDCoCBpbnQg ZXJyOwo+ID4gKwo+ID4gK8KgwqDCoMKgIGVyciA9IHNwYXJ4NV9jcmVhdGVfdGFyZ2V0cyhzcGFy eDUpOwo+ID4gK8KgwqDCoMKgIGlmIChlcnIpCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHJldHVybiBlcnI7Cj4gCj4gVGhpcyBzZWVzIG9kZCBoZXJlLiBEb24ndCBzcGFyeDVfY3JlYXRl X3RhcmdldHMoKSBjcmVhdGUgYWxsIHRoZQo+IHRhcmdldHMsIHdoZXJlIGFzIHRoaXMgY3JlYXRl cyBvbmUgc3BlY2lmaWMgcG9ydD8gU2VlbXMgbGlrZQo+IHNwYXJ4NV9jcmVhdGVfdGFyZ2V0cygp IHNob3VsZCBiZSBpbiB0aGUgZGV2aWNlcyBhcyBhIHdob2xlIHByb2JlLAo+IG5vdAo+IHRoZSBw b3J0IHByb2JlLgoKWW91IGFyZSByaWdodCAtIHRoZSBuYW1lIGRvZXMgbm90IHJlYWxseSBmaXQg KGFueW1vcmUpLiBJIHdpbGwgcmV3b3JrCnRoaXMuCj4gCj4gPiArwqDCoMKgwqAgc3B4NV9wb3J0 ID0gbmV0ZGV2X3ByaXYobmRldik7Cj4gPiArwqDCoMKgwqAgc3B4NV9wb3J0LT5vZl9ub2RlID0g cG9ydG5wOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+c2VyZGVzID0gc2VyZGVzOwo+ID4gK8Kg wqDCoMKgIHNweDVfcG9ydC0+cHZpZCA9IE5VTExfVklEOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9y dC0+c2lnbmRfaW50ZXJuYWwgPSB0cnVlOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+c2lnbmRf YWN0aXZlX2hpZ2ggPSB0cnVlOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+c2lnbmRfZW5hYmxl ID0gdHJ1ZTsKPiA+ICvCoMKgwqDCoCBzcHg1X3BvcnQtPmZsb3dfY29udHJvbCA9IGZhbHNlOwo+ ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+bWF4X3ZsYW5fdGFncyA9IFNQWDVfUE9SVF9NQVhfVEFH U19OT05FOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+dmxhbl90eXBlID0gU1BYNV9WTEFOX1BP UlRfVFlQRV9VTkFXQVJFOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+Y3VzdG9tX2V0eXBlID0g MHg4ODgwOyAvKiBWaXRlc3NlICovCj4gPiArwqDCoMKgwqAgY29uZi0+cG9ydG1vZGUgPSBjb25m LT5waHlfbW9kZTsKPiA+ICvCoMKgwqDCoCBzcHg1X3BvcnQtPmNvbmYuc3BlZWQgPSBTUEVFRF9V TktOT1dOOwo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+Y29uZi5wb3dlcl9kb3duID0gdHJ1ZTsK PiA+ICvCoMKgwqDCoCBzcGFyeDUtPnBvcnRzW3BvcnRub10gPSBzcHg1X3BvcnQ7Cj4gPiArwqDC oMKgwqAgcmV0dXJuIDA7Cj4gCj4gSSdtIGFsc28gbm90IHN1cmUgdGhpcyBoYXMgdGhlIGNvcnJl Y3QgbmFtZS4gVGhpcyBkb2VzIG5vdCBsb29rIGxpa2UKPiBhCj4gdHlwaWNhbCBwcm9iZSBmdW5j dGlvbi4KCkFncmVlLgo+IAo+IAo+ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMgaW50IHNwYXJ4NV9p bml0X3N3aXRjaGNvcmUoc3RydWN0IHNwYXJ4NSAqc3Bhcng1KQo+ID4gK3sKPiA+ICvCoMKgwqDC oCB1MzIgdmFsdWUsIHBlbmRpbmcsIGpkeCwgaWR4Owo+ID4gK8KgwqDCoMKgIHN0cnVjdCB7Cj4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJvb2wgZ2F6d3JhcDsKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgdm9pZCBfX2lvbWVtICppbml0X3JlZzsKPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgdTMywqAgaW5pdF92YWw7Cj4gPiArwqDCoMKgwqAgfSByYW0sIHJhbV9pbml0 X2xpc3RbXSA9IHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAge2ZhbHNlLCBzcHg1X3Jl Z19nZXQoc3Bhcng1LCBBTkFfQUNfU1RBVF9SRVNFVCksCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgQU5BX0FDX1NUQVRfUkVTRVRfUkVTRVR9LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCB7ZmFsc2UsIHNweDVfcmVnX2dldChzcGFyeDUsIEFTTV9TVEFUX0NGRyksCj4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgQVNNX1NUQVRfQ0ZHX1NUQVRfQ05UX0NMUl9TSE9U fSwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAge3RydWUswqAgc3B4NV9yZWdfZ2V0KHNw YXJ4NSwgUVNZU19SQU1fSU5JVCksIDB9LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB7 dHJ1ZSzCoCBzcHg1X3JlZ19nZXQoc3Bhcng1LCBSRVdfUkFNX0lOSVQpLCAwfSwKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAge3RydWUswqAgc3B4NV9yZWdfZ2V0KHNwYXJ4NSwgVk9QX1JB TV9JTklUKSwgMH0sCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHt0cnVlLMKgIHNweDVf cmVnX2dldChzcGFyeDUsIEFOQV9BQ19SQU1fSU5JVCksIDB9LAo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCB7dHJ1ZSzCoCBzcHg1X3JlZ19nZXQoc3Bhcng1LCBBU01fUkFNX0lOSVQpLCAw fSwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAge3RydWUswqAgc3B4NV9yZWdfZ2V0KHNw YXJ4NSwgRUFDTF9SQU1fSU5JVCksIDB9LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB7 dHJ1ZSzCoCBzcHg1X3JlZ19nZXQoc3Bhcng1LCBWQ0FQX1NVUEVSX1JBTV9JTklUKSwKPiA+IDB9 LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB7dHJ1ZSzCoCBzcHg1X3JlZ19nZXQoc3Bh cng1LCBEU01fUkFNX0lOSVQpLCAwfQo+ID4gK8KgwqDCoMKgIH07Cj4gCj4gTG9va3MgbGlrZSB0 aGlzIGNvdWxkIGJlIGNvbnN0IGFzIHdlbGwuIEFuZCB0aGlzIGRvZXMgbm90IHJlYWxseSBmaXQK PiByZXZlcnNlIGNocmlzdG1hcyB0cmVlLgoKSSB3aWxsIHVwZGF0ZSB0aGlzLgo+IAo+ID4gKwo+ ID4gK8KgwqDCoMKgIHNweDVfcm13KEVBQ0xfUE9MX0VBQ0xfQ0ZHX0VBQ0xfRk9SQ0VfSU5JVF9T RVQoMSksCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgRUFDTF9QT0xfRUFDTF9DRkdf RUFDTF9GT1JDRV9JTklULAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNwYXJ4NSwK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBFQUNMX1BPTF9FQUNMX0NGRyk7Cj4gPiAr Cj4gPiArwqDCoMKgwqAgc3B4NV9ybXcoRUFDTF9QT0xfRUFDTF9DRkdfRUFDTF9GT1JDRV9JTklU X1NFVCgwKSwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBFQUNMX1BPTF9FQUNMX0NG R19FQUNMX0ZPUkNFX0lOSVQsCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3Bhcng1 LAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEVBQ0xfUE9MX0VBQ0xfQ0ZHKTsKPiA+ ICsKPiA+ICvCoMKgwqDCoCAvKiBJbml0aWFsaXplIG1lbW9yaWVzLCBpZiBub3QgZG9uZSBhbHJl YWR5ICovCj4gPiArwqDCoMKgwqAgdmFsdWUgPSBzcHg1X3JkKHNwYXJ4NSwgSFNDSF9SRVNFVF9D RkcpOwo+ID4gKwo+ID4gK8KgwqDCoMKgIGlmICghKHZhbHVlICYgSFNDSF9SRVNFVF9DRkdfQ09S RV9FTkEpKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGZvciAoaWR4ID0gMDsgaWR4 IDwgMTA7IGlkeCsrKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBwZW5kaW5nID0gQVJSQVlfU0laRShyYW1faW5pdF9saXN0KTsKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGZvciAoamR4ID0gMDsgamR4IDwKPiA+IEFS UkFZX1NJWkUocmFtX2luaXRfbGlzdCk7IGpkeCsrKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmFtID0gcmFtX2luaXRfbGlz dFtqZHhdOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGlmIChyYW0uZ2F6d3JhcCkKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmFtLmlu aXRfdmFsID0KPiA+IFFTWVNfUkFNX0lOSVRfUkFNX0lOSVQ7Cj4gPiArCj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKGlkeCA9 PSAwKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHdyaXRlbChyYW0uaW5pdF92YWwsCj4gPiByYW0u aW5pdF9yZWcpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIH0gZWxzZSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHZhbHVlID0gcmVh ZGwocmFtLmluaXRfcmVnKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKCh2YWx1ZSAmIHJhbS5p bml0X3ZhbCkgIT0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByYW0uaW5pdF92YWwpIHsK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHBlbmRpbmctLTsKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgfQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIH0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIH0KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGlmICghcGVuZGluZykKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBicmVhazsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIHVzbGVlcF9yYW5nZShVU0VDX1BFUl9NU0VDLCAyICoKPiA+IFVTRUNf UEVSX01TRUMpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB9Cj4gCj4gWW91IGFyZSBn ZXR0aW5nIHByZXR0eSBkZWVwbHkgbmVzdGVkIGhlcmUuIE1pZ2h0IGJlIGJldHRlciB0byBwdWxs Cj4gdGhpcyBvdXQgaW50byBhIGhlbHBlcnMuCgpZZXMuCgo+IAo+ID4gKwo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBpZiAocGVuZGluZyA+IDApIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIC8qIFN0aWxsIGluaXRpYWxpemluZywgc2hvdWxkIGJl IGNvbXBsZXRlIGluCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgICogbGVzcyB0aGFuIDFtcwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCAqLwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgZGV2X2VycihzcGFyeDUtPmRldiwgIk1lbW9yeSBpbml0aWFsaXphdGlvbgo+ID4gZXJyb3Jc biIpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJu IC1FSU5WQUw7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIH0KPiA+ICvCoMKgwqDCoCB9 Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogUmVzZXQgY291bnRlcnMgKi8KPiA+ICvCoMKgwqDCoCBz cHg1X3dyKEFOQV9BQ19TVEFUX1JFU0VUX1JFU0VUX1NFVCgxKSwgc3Bhcng1LAo+ID4gQU5BX0FD X1NUQVRfUkVTRVQpOwo+ID4gK8KgwqDCoMKgIHNweDVfd3IoQVNNX1NUQVRfQ0ZHX1NUQVRfQ05U X0NMUl9TSE9UX1NFVCgxKSwgc3Bhcng1LAo+ID4gQVNNX1NUQVRfQ0ZHKTsKPiA+ICsKPiA+ICvC oMKgwqDCoCAvKiBFbmFibGUgc3dpdGNoLWNvcmUgYW5kIHF1ZXVlIHN5c3RlbSAqLwo+ID4gK8Kg wqDCoMKgIHNweDVfd3IoSFNDSF9SRVNFVF9DRkdfQ09SRV9FTkFfU0VUKDEpLCBzcGFyeDUsCj4g PiBIU0NIX1JFU0VUX0NGRyk7Cj4gPiArCj4gPiArwqDCoMKgwqAgcmV0dXJuIDA7Cj4gPiArfQo+ ID4gKwo+ID4gK3N0YXRpYyBpbnQgc3Bhcng1X2luaXRfY29yZWNsb2NrKHN0cnVjdCBzcGFyeDUg KnNwYXJ4NSkKPiA+ICt7Cj4gPiArwqDCoMKgwqAgdTMyIGNsa19kaXYsIGNsa19wZXJpb2QsIHBv bF91cGRfaW50LCBpZHg7Cj4gPiArwqDCoMKgwqAgZW51bSBzcGFyeDVfY29yZV9jbG9ja2ZyZXEg ZnJlcSA9IHNwYXJ4NS0+Y29yZWNsb2NrOwo+IAo+IE1vcmUgcmV2ZXJzZSBjaHJpc3RtYXMgdHJl ZS4gUGxlYXNlIHJldmlldyB0aGUgd2hvbGUgZHJpdmVyLgoKSSB3aWxsIGRvIHRoYXQuCgo+IAo+ ID4gKwo+ID4gK8KgwqDCoMKgIC8qIFZlcmlmeSBpZiBjb3JlIGNsb2NrIGZyZXF1ZW5jeSBpcyBz dXBwb3J0ZWQgb24gdGFyZ2V0Lgo+ID4gK8KgwqDCoMKgwqAgKiBJZiAnVlRTU19DT1JFX0NMT0NL X0RFRkFVTFQnIHRoZW4gdGhlIGhpZ2hlc3Qgc3VwcG9ydGVkCj4gPiArwqDCoMKgwqDCoCAqIGZy ZXEuIGlzIHVzZWQKPiA+ICvCoMKgwqDCoMKgICovCj4gPiArwqDCoMKgwqAgc3dpdGNoIChzcGFy eDUtPnRhcmdldF9jdCkgewo+ID4gK8KgwqDCoMKgIGNhc2UgU1BYNV9UQVJHRVRfQ1RfNzU0NjoK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKHNwYXJ4NS0+Y29yZWNsb2NrID09IFNQ WDVfQ09SRV9DTE9DS19ERUZBVUxUKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgZnJlcSA9IFNQWDVfQ09SRV9DTE9DS18yNTBNSFo7Cj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGVsc2UgaWYgKHNwYXJ4NS0+Y29yZWNsb2NrICE9IFNQWDVfQ09SRV9D TE9DS18yNTBNSFopCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBmcmVxID0gMDsgLyogTm90IHN1cHBvcnRlZCAqLwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBicmVhazsKPiA+ICvCoMKgwqDCoCBjYXNlIFNQWDVfVEFSR0VUX0NUXzc1NDk6Cj4gPiAr wqDCoMKgwqAgY2FzZSBTUFg1X1RBUkdFVF9DVF83NTUyOgo+ID4gK8KgwqDCoMKgIGNhc2UgU1BY NV9UQVJHRVRfQ1RfNzU1NjoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKHNwYXJ4 NS0+Y29yZWNsb2NrID09IFNQWDVfQ09SRV9DTE9DS19ERUZBVUxUKQo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZnJlcSA9IFNQWDVfQ09SRV9DTE9DS181MDBN SFo7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVsc2UgaWYgKHNwYXJ4NS0+Y29yZWNs b2NrICE9IFNQWDVfQ09SRV9DTE9DS181MDBNSFopCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBmcmVxID0gMDsgLyogTm90IHN1cHBvcnRlZCAqLwo+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBicmVhazsKPiA+ICvCoMKgwqDCoCBjYXNlIFNQWDVfVEFS R0VUX0NUXzc1NTg6Cj4gPiArwqDCoMKgwqAgY2FzZSBTUFg1X1RBUkdFVF9DVF83NTU4VFNOOgo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoc3Bhcng1LT5jb3JlY2xvY2sgPT0gU1BY NV9DT1JFX0NMT0NLX0RFRkFVTFQpCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBmcmVxID0gU1BYNV9DT1JFX0NMT0NLXzYyNU1IWjsKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgZWxzZSBpZiAoc3Bhcng1LT5jb3JlY2xvY2sgIT0gU1BYNV9DT1JFX0NM T0NLXzYyNU1IWikKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGZyZXEgPSAwOyAvKiBOb3Qgc3VwcG9ydGVkICovCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIGJyZWFrOwo+ID4gK8KgwqDCoMKgIGNhc2UgU1BYNV9UQVJHRVRfQ1RfNzU0NlRTTjoKPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKHNwYXJ4NS0+Y29yZWNsb2NrID09IFNQWDVf Q09SRV9DTE9DS19ERUZBVUxUKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgZnJlcSA9IFNQWDVfQ09SRV9DTE9DS182MjVNSFo7Cj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGJyZWFrOwo+ID4gK8KgwqDCoMKgIGNhc2UgU1BYNV9UQVJHRVRfQ1RfNzU0 OVRTTjoKPiA+ICvCoMKgwqDCoCBjYXNlIFNQWDVfVEFSR0VUX0NUXzc1NTJUU046Cj4gPiArwqDC oMKgwqAgY2FzZSBTUFg1X1RBUkdFVF9DVF83NTU2VFNOOgo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBpZiAoc3Bhcng1LT5jb3JlY2xvY2sgPT0gU1BYNV9DT1JFX0NMT0NLX0RFRkFVTFQp Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBmcmVxID0gU1BY NV9DT1JFX0NMT0NLXzYyNU1IWjsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZWxzZSBp ZiAoc3Bhcng1LT5jb3JlY2xvY2sgPT0gU1BYNV9DT1JFX0NMT0NLXzI1ME1IWikKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGZyZXEgPSAwOyAvKiBOb3Qgc3Vw cG9ydGVkICovCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJyZWFrOwo+ID4gK8KgwqDC oMKgIGRlZmF1bHQ6Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGRldl9lcnIoc3Bhcng1 LT5kZXYsICJUYXJnZXQgKCUjMDR4KSBub3QKPiA+IHN1cHBvcnRlZFxuIiwgc3Bhcng1LT50YXJn ZXRfY3QpOwo+IAo+IG5ldGRldiBpcyBzdGF5aW5nIHdpdGggODAgY2hhcmFjdGVyIGxpbmVzLiBQ bGVhc2UgZm9sZCB0aGlzLCBoZXJlIGFuZAo+IGV2ZXJ5IHdoZXJlIGVsc2UsIHdoZXJlIHBvc3Np YmxlLiBUaGUgZXhjZXB0aW9uIGlzLCB5b3Ugc2hvdWxkIG5vdAo+IHNwbGl0IGEgc3RyaW5nLgoK V2lsbCBkby4KCj4gCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiAtRU5PREVW Owo+ID4gK8KgwqDCoMKgIH0KPiA+ICsKPiA+ICvCoMKgwqDCoCBzd2l0Y2ggKGZyZXEpIHsKPiA+ ICvCoMKgwqDCoCBjYXNlIFNQWDVfQ09SRV9DTE9DS18yNTBNSFo6Cj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGNsa19kaXYgPSAxMDsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg cG9sX3VwZF9pbnQgPSAzMTI7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJyZWFrOwo+ ID4gK8KgwqDCoMKgIGNhc2UgU1BYNV9DT1JFX0NMT0NLXzUwME1IWjoKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgY2xrX2RpdiA9IDU7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IHBvbF91cGRfaW50ID0gNjI0Owo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBicmVhazsK PiA+ICvCoMKgwqDCoCBjYXNlIFNQWDVfQ09SRV9DTE9DS182MjVNSFo6Cj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGNsa19kaXYgPSA0Owo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oCBwb2xfdXBkX2ludCA9IDc4MDsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgYnJlYWs7 Cj4gPiArwqDCoMKgwqAgZGVmYXVsdDoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGV2 X2VycihzcGFyeDUtPmRldiwgIiVzOiBGcmVxdWVuY3kgKCVkKSBub3QKPiA+IHN1cHBvcnRlZCBv biB0YXJnZXQgKCUjMDR4KVxuIiwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIF9fZnVuY19fLAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgc3Bhcng1LT5jb3JlY2xvY2ssIHNwYXJ4NS0+dGFyZ2V0X2N0KTsKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIDA7Cj4gCj4gLUVJTlZBTD8gT3IgaXMgaXQgbm90 IGZhdGFsIHRvIHVzZSBhbiB1bnN1cHBvcnRlZCBmcmVxdWVuY3k/CgpZZXMgLSBpdCBzaG91bGQg YmUgZmF0YWwuCj4gCj4gPiArc3RhdGljIGludCBzcGFyeDVfaW5pdChzdHJ1Y3Qgc3Bhcng1ICpz cGFyeDUpCj4gPiArewo+ID4gK8KgwqDCoMKgIHUzMiBpZHg7Cj4gPiArCj4gPiArwqDCoMKgwqAg aWYgKHNwYXJ4NV9jcmVhdGVfdGFyZ2V0cyhzcGFyeDUpKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCByZXR1cm4gLUVOT0RFVjsKPiAKPiBIdW0sIHNwYXJ4NV9jcmVhdGVfdGFyZ2V0cygp IGFnYWluPwoKWWVzIHRoYXQgd2FzIGR1ZSB0byB0aGUgUFJPQkVfREVGRVIgLSBidXQgSSB3aWxs IGdvIG92ZXIgdGhpcyBhZ2Fpbi4KCj4gCj4gPiArCj4gPiArwqDCoMKgwqAgLyogUmVhZCBjaGlw IElEIHRvIGNoZWNrIENQVSBpbnRlcmZhY2UgKi8KPiA+ICvCoMKgwqDCoCBzcGFyeDUtPmNoaXBf aWQgPSBzcHg1X3JkKHNwYXJ4NSwgR0NCX0NISVBfSUQpOwo+ID4gKwo+ID4gK8KgwqDCoMKgIHNw YXJ4NS0+dGFyZ2V0X2N0ID0gKGVudW0gc3B4NV90YXJnZXRfY2hpcHR5cGUpCj4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIEdDQl9DSElQX0lEX1BBUlRfSURfR0VUKHNwYXJ4NS0+Y2hpcF9p ZCk7Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogSW5pdGlhbGl6ZSBTd2l0Y2hjb3JlIGFuZCBpbnRl cm5hbCBSQU1zICovCj4gPiArwqDCoMKgwqAgaWYgKHNwYXJ4NV9pbml0X3N3aXRjaGNvcmUoc3Bh cng1KSkgewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXZfZXJyKHNwYXJ4NS0+ZGV2 LCAiU3dpdGNoY29yZSBpbml0aWFsaXphdGlvbgo+ID4gZXJyb3JcbiIpOwo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCByZXR1cm4gLUVJTlZBTDsKPiA+ICvCoMKgwqDCoCB9Cj4gPiArCj4g PiArwqDCoMKgwqAgLyogSW5pdGlhbGl6ZSB0aGUgTEMtUExMIChjb3JlIGNsb2NrKSBhbmQgc2V0 IGFmZmVjdGVkCj4gPiByZWdpc3RlcnMgKi8KPiA+ICvCoMKgwqDCoCBpZiAoc3Bhcng1X2luaXRf Y29yZWNsb2NrKHNwYXJ4NSkpIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGV2X2Vy cihzcGFyeDUtPmRldiwgIkxDLVBMTCBpbml0aWFsaXphdGlvbgo+ID4gZXJyb3JcbiIpOwo+ID4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1cm4gLUVJTlZBTDsKPiA+ICvCoMKgwqDCoCB9 Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogU2V0dXAgb3duIFVQU0lEcyAqLwo+ID4gK8KgwqDCoMKg IGZvciAoaWR4ID0gMDsgaWR4IDwgMzsgaWR4KyspIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqAgc3B4NV93cihpZHgsIHNwYXJ4NSwgQU5BX0FDX09XTl9VUFNJRChpZHgpKTsKPiA+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3B4NV93cihpZHgsIHNwYXJ4NSwgQU5BX0NMX09XTl9V UFNJRChpZHgpKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3B4NV93cihpZHgsIHNw YXJ4NSwgQU5BX0wyX09XTl9VUFNJRChpZHgpKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgc3B4NV93cihpZHgsIHNwYXJ4NSwgUkVXX09XTl9VUFNJRChpZHgpKTsKPiA+ICvCoMKgwqDC oCB9Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogRW5hYmxlIHN3aXRjaCBwb3J0cyAqLwo+ID4gK8Kg wqDCoMKgIGZvciAoaWR4ID0gU1BYNV9QT1JUUzsgaWR4IDwgU1BYNV9QT1JUU19BTEw7IGlkeCsr KSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNweDVfcm13KFFGV0RfU1dJVENIX1BP UlRfTU9ERV9QT1JUX0VOQV9TRVQoMSksCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIFFGV0RfU1dJVENIX1BPUlRfTU9ERV9QT1JUX0VOQSwKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3Bhcng1LAo+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBRRldEX1NXSVRDSF9QT1JUX01P REUoaWR4KSk7Cj4gPiArwqDCoMKgwqAgfQo+IAo+IFdoYXQgaGFwcGVucyB3aGVuIHlvdSBlbmFi bGUgdGhlIHBvcnRzPyBXaHkgaXMgdGhpcyBoZXJlLCBhbmQgbm90IGluCj4gdGhlIHBvcnQgc3Bl Y2lmaWMgb3BlbiBjYWxsPwoKVGhlIGNvbW1lbnQgaXMgbm90IGNvcnJlY3QuICBUaGlzIGlzIGp1 c3QgZW5hYmxpbmcgdGhlIENQVSBwb3J0cywgc28gaXQKYmVsb25ncyB3aXRoIHRoZSBvdGhlciBz d2l0Y2ggY29yZSBpbml0aWFsaXphdGlvbi4gSSB3aWxsIHVwZGF0ZSB0aGUKY29tbWVudC4KCj4g Cj4gPiArLyogU29tZSBib2FyZHMgbmVlZHMgdG8gbWFwIHRoZSBTR1BJTyBmb3Igc2lnbmFsIGRl dGVjdCBleHBsaWNpdGx5Cj4gPiB0byB0aGUKPiA+ICsgKiBwb3J0IG1vZHVsZQo+ID4gKyAqLwo+ ID4gK3N0YXRpYyB2b2lkIHNwYXJ4NV9ib2FyZF9pbml0KHN0cnVjdCBzcGFyeDUgKnNwYXJ4NSkK PiA+ICt7Cj4gPiArwqDCoMKgwqAgaW50IGlkeDsKPiA+ICsKPiA+ICvCoMKgwqDCoCBpZiAoIXNw YXJ4NS0+c2Rfc2dwaW9fcmVtYXBwaW5nKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBy ZXR1cm47Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogRW5hYmxlIFNHUElPIFNpZ25hbCBEZXRlY3Qg cmVtYXBwaW5nICovCj4gPiArwqDCoMKgwqAgc3B4NV9ybXcoR0NCX0hXX1NHUElPX1NEX0NGR19T RF9NQVBfU0VMLAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIEdDQl9IV19TR1BJT19T RF9DRkdfU0RfTUFQX1NFTCwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzcGFyeDUs Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgR0NCX0hXX1NHUElPX1NEX0NGRyk7Cj4g PiArCj4gPiArwqDCoMKgwqAgLyogUmVmZXIgdG8gTE9TIFNHUElPICovCj4gPiArwqDCoMKgwqAg Zm9yIChpZHggPSAwOyBpZHggPCBTUFg1X1BPUlRTOyBpZHgrKykgewo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBpZiAoc3Bhcng1LT5wb3J0c1tpZHhdKSB7Cj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoc3Bhcng1LT5wb3J0c1tpZHhdLT5jb25m LnNkX3NncGlvICE9IH4wKQo+ID4gewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNweDVfd3Ioc3Bhcng1LT5wb3J0c1tpZHhdLQo+ ID4gPmNvbmYuc2Rfc2dwaW8sCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNwYXJ4NSwKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAKPiA+IEdDQl9IV19TR1BJT19UT19TRF9NQVBfQ0ZHKGlkeCkpOwo+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgfQo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCB9Cj4gPiArwqDCoMKgwqAgfQo+ID4gK30KPiAKPiBJJ3ZlIG5vdCBsb29r ZWQgYXQgaG93IHlvdSBkbyBTRlAgaW50ZWdyYXRpb24geWV0LiBJcyB0aGlzIHRoZSBMT1MKPiBm cm9tIHRoZSBTRlAgc29ja2V0PyBJcyB0aGVyZSBhIExpbnV4IEdQSU8gY29udHJvbGxlciBleHBv cnRlZCBieQo+IHRoaXMKPiBkcml2ZXIsIHNvIHRoZSBTRlAgZHJpdmVyIGNhbiB1c2UgdGhlIEdQ SU9zPwoKWWVzIHRoZSBTRlAgZHJpdmVyICh1c2VkIGJ5IHRoZSBTcGFyeDUgU2VyRGVzIGRyaXZl cikgd2lsbCB1c2UgdGhlClNHUElPIExPUywgTW9kdWxlIERldGVjdCBldGMsIGFuZCB0aGUgUG9y dCBNb2R1bGVzIGFyZSBhd2FyZSBvZiB0aGUKbG9jYXRpb24gb2YgdGhlIExPUywgYW5kIHVzZSB0 aGlzIGJ5IGRlZmF1bHQgd2l0aG91dCBhbnkgZHJpdmVyCmNvbmZpZ3VyYXRpb24uCkJ1dCBvbiB0 aGUgUENCMTM0IHRoZSBTR1BJT3MgYXJlIHNoaWZ0ZWQgb25lIGJpdCBieSBhIG1pc3Rha2UsIGFu ZCB0aGV5CmFyZSBub3QgbG9jYXRlZCBpbiB0aGUgZXhwZWN0ZWQgcG9zaXRpb24sIHNvIHdlIGhh dmUgdGhpcyBib2FyZApyZW1hcHBpbmcgZnVuY3Rpb24gdG8gaGFuZGxlIHRoYXQgYXNwZWN0LgoK PiAKPiA+ICsKPiA+ICtzdGF0aWMgaW50IG1jaHBfc3Bhcng1X3Byb2JlKHN0cnVjdCBwbGF0Zm9y bV9kZXZpY2UgKnBkZXYpCj4gPiArewo+ID4gK8KgwqDCoMKgIHN0cnVjdCBkZXZpY2Vfbm9kZSAq bnAgPSBwZGV2LT5kZXYub2Zfbm9kZTsKPiA+ICvCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1ICpzcGFy eDU7Cj4gPiArwqDCoMKgwqAgc3RydWN0IGRldmljZV9ub2RlICpwb3J0cywgKnBvcnRucDsKPiA+ ICvCoMKgwqDCoCBjb25zdCB1OCAqbWFjX2FkZHI7Cj4gPiArwqDCoMKgwqAgaW50IGVyciA9IDA7 Cj4gPiArCj4gPiArwqDCoMKgwqAgaWYgKCFucCAmJiAhcGRldi0+ZGV2LnBsYXRmb3JtX2RhdGEp Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiAtRU5PREVWOwo+ID4gKwo+ID4g K8KgwqDCoMKgIHNwYXJ4NSA9IGRldm1fa3phbGxvYygmcGRldi0+ZGV2LCBzaXplb2YoKnNwYXJ4 NSksCj4gPiBHRlBfS0VSTkVMKTsKPiA+ICvCoMKgwqDCoCBpZiAoIXNwYXJ4NSkKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIC1FTk9NRU07Cj4gPiArCj4gPiArwqDCoMKgwqAg cGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgc3Bhcng1KTsKPiA+ICvCoMKgwqDCoCBzcGFyeDUt PnBkZXYgPSBwZGV2Owo+ID4gK8KgwqDCoMKgIHNwYXJ4NS0+ZGV2ID0gJnBkZXYtPmRldjsKPiA+ ICsKPiA+ICvCoMKgwqDCoCAvKiBEZWZhdWx0IHZhbHVlcywgc29tZSBmcm9tIERUICovCj4gPiAr wqDCoMKgwqAgc3Bhcng1LT5jb3JlY2xvY2sgPSBTUFg1X0NPUkVfQ0xPQ0tfREVGQVVMVDsKPiA+ ICsKPiA+ICvCoMKgwqDCoCBtYWNfYWRkciA9IG9mX2dldF9tYWNfYWRkcmVzcyhucCk7Cj4gPiAr wqDCoMKgwqAgaWYgKElTX0VSUl9PUl9OVUxMKG1hY19hZGRyKSkgewo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBkZXZfaW5mbyhzcGFyeDUtPmRldiwgIk1BQyBhZGRyIHdhcyBub3Qgc2V0 LCB1c2UKPiA+IHJhbmRvbSBNQUNcbiIpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBl dGhfcmFuZG9tX2FkZHIoc3Bhcng1LT5iYXNlX21hYyk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHNwYXJ4NS0+YmFzZV9tYWNbNV0gPSAwOwo+ID4gK8KgwqDCoMKgIH0gZWxzZSB7Cj4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGV0aGVyX2FkZHJfY29weShzcGFyeDUtPmJhc2Vf bWFjLCBtYWNfYWRkcik7Cj4gPiArwqDCoMKgwqAgfQo+IAo+IFRoZSBiaW5kaW5nIGRvY3VtZW50 IGRvZXMgbm90IHNheSBhbnl0aGluZyBhYm91dCBhIE1BQyBhZGRyZXNzIGF0IHRoZQo+IHRvcCBs ZXZlbC4gV2hhdCBpcyB0aGlzIHVzZWQgZm9yPwoKVGhpcyB0aGUgYmFzZSBNQUMgYWRkcmVzcyB1 c2VkIGZvciBnZW5lcmF0aW5nIHRoZSB0aGUgc3dpdGNoIE5JJ3MgTUFDCmFkZHJlc3Nlcy4KPiAK PiArCj4gPiArwqDCoMKgwqAgaWYgKHNwYXJ4NV9pbml0KHNwYXJ4NSkpIHsKPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgZGV2X2VycihzcGFyeDUtPmRldiwgIkluaXQgZmFpbGVkXG4iKTsK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIC1FTk9ERVY7Cj4gPiArwqDCoMKg wqAgfQo+ID4gK8KgwqDCoMKgIHBvcnRzID0gb2ZfZ2V0X2NoaWxkX2J5X25hbWUobnAsICJldGhl cm5ldC1wb3J0cyIpOwo+ID4gK8KgwqDCoMKgIGlmICghcG9ydHMpIHsKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgZGV2X2VycihzcGFyeDUtPmRldiwgIm5vIGV0aGVybmV0LXBvcnRzIGNo aWxkIG5vZGUKPiA+IGZvdW5kXG4iKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0 dXJuIC1FTk9ERVY7Cj4gPiArwqDCoMKgwqAgfQo+ID4gK8KgwqDCoMKgIHNwYXJ4NS0+cG9ydF9j b3VudCA9IG9mX2dldF9jaGlsZF9jb3VudChwb3J0cyk7Cj4gPiArCj4gPiArwqDCoMKgwqAgZm9y X2VhY2hfYXZhaWxhYmxlX2NoaWxkX29mX25vZGUocG9ydHMsIHBvcnRucCkgewo+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1X3BvcnRfY29uZmlnIGNvbmZpZyA9IHt9 Owo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1MzIgcG9ydG5vOwo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBzdHJ1Y3QgcGh5ICpzZXJkZXM7Cj4gPiArCj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGVyciA9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKHBvcnRucCwgInJlZyIs ICZwb3J0bm8pOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoZXJyKSB7Cj4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBkZXZfZXJyKHNwYXJ4NS0+ ZGV2LCAicG9ydCByZWcgcHJvcGVydHkKPiA+IGVycm9yXG4iKTsKPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNvbnRpbnVlOwo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCB9Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGVyciA9IG9mX3Byb3Bl cnR5X3JlYWRfdTMyKHBvcnRucCwgIm1heC1zcGVlZCIsCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgICZjb25maWcubWF4X3NwZWVkKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYg KGVycikgewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGV2 X2VycihzcGFyeDUtPmRldiwgInBvcnQgbWF4LXNwZWVkIHByb3BlcnR5Cj4gPiBlcnJvclxuIik7 Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb250aW51ZTsK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgfQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBjb25maWcuc3BlZWQgPSBTUEVFRF9VTktOT1dOOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBlcnIgPSBvZl9wcm9wZXJ0eV9yZWFkX3UzMihwb3J0bnAsICJzZF9zZ3BpbyIsCj4g PiAmY29uZmlnLnNkX3NncGlvKTsKPiAKPiBOb3QgaW4gdGhlIGJpbmRpbmcgZG9jdW1lbnRhdGlv bi4gSSB0aGluayBpIG5lZWQgdG8gd2l0aGRyYXcgbXkKPiBSZXZpZXdlZC1ieSA6LSgKCk9vb3Bz IC0geWVzIHRoYXQgaXMgYSBtaXN0YWtlIHRoYXQgdGhlc2UgMiBpdGVtcyB3ZXJlIG5vdCBpbmNs dWRlZC4KCj4gCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmIChlcnIpCj4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb25maWcuc2Rfc2dwaW8gPSB+ MDsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZWxzZQo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3Bhcng1LT5zZF9zZ3Bpb19yZW1hcHBpbmcgPSB0 cnVlOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzZXJkZXMgPSBkZXZtX29mX3BoeV9n ZXQoc3Bhcng1LT5kZXYsIHBvcnRucCwgTlVMTCk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIGlmIChJU19FUlIoc2VyZGVzKSkgewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqAgZXJyID0gUFRSX0VSUihzZXJkZXMpOwo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKGVyciAhPSAtRVBST0JFX0RFRkVSKQo+ID4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGRldl9lcnIoc3Bhcng1LT5kZXYsCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICJtaXNzaW5nIFNlckRl cyBwaHlzIGZvcgo+ID4gcG9ydCVkXG4iLAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBwb3J0bm8pOwo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIGVycjsK PiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgfQo+ID4gKwo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBlcnIgPSBvZl9nZXRfcGh5X21vZGUocG9ydG5wLCAmY29uZmlnLnBoeV9tb2Rl KTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKGVycikKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNvbmZpZy5wb3dlcl9kb3duID0gdHJ1ZTsK PiAKPiBZb3Ugc2hvdWxkIGluZGljYXRlIGluIHRoZSBiaW5kaW5nIGl0IGlzIG9wdGlvbmFsLiBB bmQgd2hhdCBoYXBwZW5zCj4gd2hlbiBpdCBpcyBtaXNzaW5nLgoKV2lsbCB1cGRhdGUgdGhlIGRl c2NyaXB0aW9uLgoKPiAKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29uZmlnLm1lZGlh X3R5cGUgPSBFVEhfTUVESUFfREFDOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjb25m aWcuc2VyZGVzX3Jlc2V0ID0gdHJ1ZTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY29u ZmlnLnBvcnRtb2RlID0gY29uZmlnLnBoeV9tb2RlOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBlcnIgPSBzcGFyeDVfcHJvYmVfcG9ydChzcGFyeDUsIHBvcnRucCwgc2VyZGVzLAo+ID4g cG9ydG5vLCAmY29uZmlnKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKGVycikg ewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGV2X2Vycihz cGFyeDUtPmRldiwgInBvcnQgcHJvYmUgZXJyb3JcbiIpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBjbGVhbnVwX3BvcnRzOwo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCB9Cj4gPiArwqDCoMKgwqAgfQo+ID4gK8KgwqDCoMKgIHNwYXJ4NV9i b2FyZF9pbml0KHNwYXJ4NSk7Cj4gPiArCj4gPiArY2xlYW51cF9wb3J0czoKPiA+ICvCoMKgwqDC oCByZXR1cm4gZXJyOwo+IAo+IFNlZW1zIG1pc3NlZCBuYW1lZCwgbm8gY2xlYW51cC4KCkFoIC0g dGhpcyBjb21lcyBsYXRlciAoYXMgdGhlIGRyaXZlciB3YXMgc3BsaXQgaW4gZnVuY3Rpb25hbCBn cm91cHMgZm9yCnJldmlld2luZykuIEkgaG9wZSB0aGlzIGlzIE9LLCBhcyBpdCBpcyBvbmx5IHRl bXBvcmFyeSAtIEkgY291bGQgYWRkIGEKY29tbWVudCB0byB0aGF0IGVmZmVjdC4KCj4gCj4gPiAr c3RhdGljIGludCBfX2luaXQgc3Bhcng1X3N3aXRjaF9yZXNldCh2b2lkKQo+ID4gK3sKPiA+ICvC oMKgwqDCoCBjb25zdCBjaGFyICpzeXNjb25fY3B1ID0gIm1pY3JvY2hpcCxzcGFyeDUtY3B1LXN5 c2NvbiIsCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICpzeXNjb25fZ2NiID0gIm1pY3Jv Y2hpcCxzcGFyeDUtZ2NiLXN5c2NvbiI7Cj4gPiArwqDCoMKgwqAgc3RydWN0IHJlZ21hcCAqY3B1 X2N0cmwsICpnY2JfY3RybDsKPiA+ICvCoMKgwqDCoCB1MzIgdmFsOwo+ID4gKwo+ID4gK8KgwqDC oMKgIGNwdV9jdHJsID0gc3lzY29uX3JlZ21hcF9sb29rdXBfYnlfY29tcGF0aWJsZShzeXNjb25f Y3B1KTsKPiA+ICvCoMKgwqDCoCBpZiAoSVNfRVJSKGNwdV9jdHJsKSkgewo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBwcl9lcnIoIk5vICclcycgc3lzY29uIG1hcFxuIiwgc3lzY29uX2Nw dSk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiBQVFJfRVJSKGNwdV9jdHJs KTsKPiA+ICvCoMKgwqDCoCB9Cj4gPiArCj4gPiArwqDCoMKgwqAgZ2NiX2N0cmwgPSBzeXNjb25f cmVnbWFwX2xvb2t1cF9ieV9jb21wYXRpYmxlKHN5c2Nvbl9nY2IpOwo+ID4gK8KgwqDCoMKgIGlm IChJU19FUlIoZ2NiX2N0cmwpKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByX2Vy cigiTm8gJyVzJyBzeXNjb24gbWFwXG4iLCBzeXNjb25fZ2NiKTsKPiA+ICvCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgcmV0dXJuIFBUUl9FUlIoZ2NiX2N0cmwpOwo+ID4gK8KgwqDCoMKgIH0KPiA+ ICsKPiA+ICvCoMKgwqDCoCAvKiBNYWtlIHN1cmUgdGhlIGNvcmUgaXMgUFJPVEVDVEVEIGZyb20g cmVzZXQgKi8KPiA+ICvCoMKgwqDCoCByZWdtYXBfdXBkYXRlX2JpdHMoY3B1X2N0cmwsIFJFU0VU X1BST1RfU1RBVCwKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIFNZU19SU1RfUFJPVF9WQ09SRSwgU1lTX1JTVF9QUk9UX1ZDT1JFKTsKPiA+ICsKPiA+ ICvCoMKgwqDCoCByZWdtYXBfd3JpdGUoZ2NiX2N0cmwsIHNweDVfb2Zmc2V0KEdDQl9TT0ZUX1JT VCksCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBHQ0JfU09GVF9SU1Rf U09GVF9TV0NfUlNUX1NFVCgxKSk7Cj4gPiArCj4gPiArwqDCoMKgwqAgcmV0dXJuIHJlYWR4X3Bv bGxfdGltZW91dChzcGFyeDVfcmVhZF9nY2Jfc29mdF9yc3QsIGdjYl9jdHJsLAo+ID4gdmFsLAo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBHQ0JfU09GVF9SU1RfU09GVF9TV0NfUlNUX0dFVCh2YWwpCj4gPiA9PSAwLAo+ID4g K8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCAxLCAxMDApOwo+ID4gK30KPiA+ICtwb3N0Y29yZV9pbml0Y2FsbChzcGFyeDVfc3dpdGNo X3Jlc2V0KTsKPiAKPiBUaGF0IGlzIHByZXR0eSB1bnVzdWFsLiBXaHkgY2Fubm90IHRoaXMgYmUg ZG9uZSBhdCBwcm9iZSB0aW1lPwoKVGhlIHByb2JsZW0gaXMgdGhhdCB0aGUgc3dpdGNoIGNvcmUg cmVzZXQgYWxzbyBhZmZlY3RzIChyZXNldCkgdGhlClNHUElPIGNvbnRyb2xsZXIuCgpXZSB0cmll ZCB0byBwdXQgdGhpcyBpbiB0aGUgcmVzZXQgZHJpdmVyLCBidXQgaXQgd2FzIHJlamVjdGVkLiBJ ZiB0aGUKcmVzZXQgaXMgZG9uZSBhdCBwcm9iZSB0aW1lLCB0aGUgU0dQSU8gZHJpdmVyIG1heSBh bHJlYWR5IGhhdmUKaW5pdGlhbGl6ZWQgc3RhdGUuCgpUaGUgc3dpdGNoIGNvcmUgcmVzZXQgd2ls bCB0aGVuIHJlc2V0IGFsbCBTR1BJTyByZWdpc3RlcnMuIAoKPiAKPiA+ICsvKiBDbG9jayBwZXJp b2QgaW4gcGljb3NlY29uZHMgKi8KPiA+ICtzdGF0aWMgaW5saW5lIHUzMiBzcGFyeDVfY2xrX3Bl cmlvZChlbnVtIHNwYXJ4NV9jb3JlX2Nsb2NrZnJlcQo+ID4gY2Nsb2NrKQo+ID4gK3sKPiA+ICvC oMKgwqDCoCBzd2l0Y2ggKGNjbG9jaykgewo+ID4gK8KgwqDCoMKgIGNhc2UgU1BYNV9DT1JFX0NM T0NLXzI1ME1IWjoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIDQwMDA7Cj4g PiArwqDCoMKgwqAgY2FzZSBTUFg1X0NPUkVfQ0xPQ0tfNTAwTUhaOgo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCByZXR1cm4gMjAwMDsKPiA+ICvCoMKgwqDCoCBjYXNlIFNQWDVfQ09SRV9D TE9DS182MjVNSFo6Cj4gPiArwqDCoMKgwqAgZGVmYXVsdDoKPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgcmV0dXJuIDE2MDA7Cj4gPiArwqDCoMKgwqAgfQo+ID4gK30KPiAKPiBJcyB0aGlz IHNvbWV0aGluZyB3aGljaCBpcyB1c2VkIGluIHRoZSBob3QgcGF0aD8KCk5vIC0gc28gbWF5YmUg dGhpcyBzaG91bGQganVzdCBiZSBhIHJlZ3VsYXIgZnVuY3Rpb24/Cj4gCj4gPiAtLS0gL2Rldi9u dWxsCj4gPiArKysgYi9kcml2ZXJzL25ldC9ldGhlcm5ldC9taWNyb2NoaXAvc3Bhcng1L3NwYXJ4 NV9tYWluX3JlZ3MuaAo+ID4gQEAgLTAsMCArMSwzOTIyIEBACj4gPiArLyogU1BEWC1MaWNlbnNl LUlkZW50aWZpZXI6IEdQTC0yLjArCj4gPiArICogTWljcm9jaGlwIFNwYXJ4NSBTd2l0Y2ggZHJp dmVyCj4gPiArICoKPiA+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMjAgTWljcm9jaGlwIFRlY2hub2xv Z3kgSW5jLgo+ID4gKyAqLwo+ID4gKwo+ID4gKy8qIFRoaXMgZmlsZSBpcyBhdXRvZ2VuZXJhdGVk IGJ5IGNtbC11dGlscyAyMDIwLTExLTE5IDEwOjQxOjM0Cj4gPiArMDEwMC4KPiA+ICsgKiBDb21t aXQgSUQ6IGYzNDc5MGU2OWRjMjUyMTAzZTJjYzNlODViMWE1ZTRkOWUzYWExOTAKPiA+ICsgKi8K PiAKPiBIb3cgcmVwcm9kdWNpYmxlIHRoaXMgaXMgZ2VuZXJhdGlvbiBwcm9jZXNzPyBJZiB5b3Ug aGF2ZSB0byBydW4gaXQKPiBhZ2Fpbiwgd2lsbCBpdCBrZWVwIHRoZSBzYW1lIG9yZGVyIG9mIGxp bmVzPwoKQXMgbG9uZyBhcyB0aGUgQ01MIChDaGlwIE1hcmt1cCBMYW5ndWFnZSkgZmlsZSBoYXMg bm90IGNoYW5nZWQKKGRvY3VtZW50YXRpb24gZmllbGRzIG5vdCBjb25zaWRlcmVkKSwgdGhpcyBp cyByZXByb2R1Y2libGUuIFRoZSB0b29sCnBhcnNlcyB0aGUgWE1MIG5vZGVzIGluIGEgZGV0ZXJt aW5pc3RpYyBvcmRlci4KCgo+IAo+IMKgwqDCoMKgwqDCoCBBbmRyZXcKClRoYW5rcyBmb3IgeW91 ciBjb21tZW50cwovU3RlZW4KCgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX18KbGludXgtYXJtLWtlcm5lbCBtYWlsaW5nIGxpc3QKbGludXgtYXJtLWtlcm5l bEBsaXN0cy5pbmZyYWRlYWQub3JnCmh0dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4v bGlzdGluZm8vbGludXgtYXJtLWtlcm5lbAo=