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=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B9CF0C433DB for ; Tue, 22 Dec 2020 09:47:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7FC942312E for ; Tue, 22 Dec 2020 09:47:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726327AbgLVJre (ORCPT ); Tue, 22 Dec 2020 04:47:34 -0500 Received: from esa.microchip.iphmx.com ([68.232.154.123]:20091 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725847AbgLVJrd (ORCPT ); Tue, 22 Dec 2020 04:47:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1608630453; x=1640166453; h=message-id:subject:from:to:cc:date:in-reply-to: references:mime-version:content-transfer-encoding; bh=hKE3KsWXrZ6vLx3BxsacqoYKb46PJCxvRuIfCWT3H4s=; b=AO0cMBwGLGkhqdaMHHqeRFOn/Oi876YcB0s5Kfqer08nXLiUQhQQmtAW HmjefiCoBDHGNvwy8kZUEfzW0/EZT13EYYwkuSxQ1N2QmfgnwsD6OB3E5 bpRqfNsjB6jJwBf5tUbHWzIrJ9DLB94YCO+bGBMpQ3q5J+la4AwHFaBco UcNDAOgfXH+lT3Jz8vVcpn5NHJfM2rW23R86KYOLMKP8BeZfhn6MI9zTp Stw6eLbzK+NQ9jQE6Wokn2aPjGgFcrQIfjxJXc3F5JUzIkuhM4oysN8kG MxJ7h3UwOQEg1ELoXc3DC3Ku4RxvGTCleRxBcb5NNdzsJOcbxSG5h3PhS Q==; IronPort-SDR: W8WV96LUInc1fl09haIMKnJvRjdvIRS05QKLKF32fNl6K+6Tij9K8fq/8foaxhMaP6zIAspREJ nhbE9ePzfYU/76SvxZTWoA05tLI8Flexl13h2kRQHy47JDYR0m6HbKvBQ48cZCjrKcPe86c2H3 //CP7qqRkbGDbBbzLSDJHY65cAbLRTpyXWyDckn9NRL4Dp9jGYzRTlmgELPhXiU0nUn0r+OV/s QikD6VTEKNggDSEEx2sGsO2Yxql+2FiURW3BV9sTQ+1weayNMKfZ1qLpPy9eOsXhRkphHi60bm eS4= X-IronPort-AV: E=Sophos;i="5.78,438,1599548400"; d="scan'208";a="97932876" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Dec 2020 02:46:17 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex03.mchp-main.com (10.10.85.151) 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 02:46:16 -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 02:46:13 -0700 Message-ID: Subject: Re: [RFC PATCH v2 3/8] net: sparx5: add hostmode with phylink support 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 10:46:12 +0100 In-Reply-To: <20201219195133.GD3026679@lunn.ch> References: <20201217075134.919699-1-steen.hegelund@microchip.com> <20201217075134.919699-4-steen.hegelund@microchip.com> <20201219195133.GD3026679@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:51 +0100, Andrew Lunn wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > > +     /* Create a phylink for PHY management.  Also handles SFPs */ > > +     spx5_port->phylink_config.dev = &spx5_port->ndev->dev; > > +     spx5_port->phylink_co > > nfig.type = PHYLINK_NETDEV; > > +     spx5_port->phylink_config.pcs_poll = true; > > + > > +     /* phylink needs a valid interface mode to parse dt node */ > > +     if (phy_mode == PHY_INTERFACE_MODE_NA) > > +             phy_mode = PHY_INTERFACE_MODE_10GBASER; > > Maybe just enforce a valid value in DT? Maybe I need to clarify that you must choose between an Ethernet cuPHY or an SFP, so it is optional. > > > +/* Configuration */ > > +static inline bool sparx5_use_cu_phy(struct sparx5_port *port) > > +{ > > +     return port->conf.phy_mode != PHY_INTERFACE_MODE_NA; > > +} > > That is a rather odd definition of copper. Should I rather use a bool property to select between the two options (cuPHY or SFP)? > > > diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c > > b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c > > new file mode 100644 > > index 000000000000..6f9282e9d3f4 > > --- /dev/null > > +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c > > @@ -0,0 +1,203 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* Microchip Sparx5 Switch driver > > + * > > + * Copyright (c) 2020 Microchip Technology Inc. and its > > subsidiaries. > > + */ > > + > > +#include "sparx5_main.h" > > I don't actually know what is preferred here, but very few drivers > i've reviewed put all the required headers into another header > file. They normally list them in each .c file. I will look at reworking this. > > > +static int sparx5_port_open(struct net_device *ndev) > > +{ > > +     struct sparx5_port *port = netdev_priv(ndev); > > +     int err = 0; > > + > > +     err = phylink_of_phy_connect(port->phylink, port->of_node, > > 0); > > +     if (err) { > > +             netdev_err(ndev, "Could not attach to PHY\n"); > > +             return err; > > +     } > > + > > +     phylink_start(port->phylink); > > + > > +     if (!ndev->phydev) { > > Humm. When is ndev->phydev set? I don't think phylink ever sets it. Indirectly: phylink_of_phy_connect uses phy_attach_direct and that sets the phydev. > > > +             /* power up serdes */ > > +             port->conf.power_down = false; > > +             err = phy_power_on(port->serdes); > > +             if (err) > > +                     netdev_err(ndev, "%s failed\n", __func__); > > +     } > > + > > +     return err; > > +} > > > +struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 > > portno) > > +{ > > +     struct net_device *ndev; > > +     struct sparx5_port *spx5_port; > > + > > +     ndev = devm_alloc_etherdev(sparx5->dev, sizeof(struct > > sparx5_port)); > > +     if (!ndev) > > +             return ERR_PTR(-ENOMEM); > > + > > +     SET_NETDEV_DEV(ndev, sparx5->dev); > > +     spx5_port = netdev_priv(ndev); > > +     spx5_port->ndev = ndev; > > +     spx5_port->sparx5 = sparx5; > > +     spx5_port->portno = portno; > > +     sparx5_set_port_ifh(spx5_port->ifh, portno); > > +     snprintf(ndev->name, IFNAMSIZ, "eth%d", portno); > > + > > +     ether_setup(ndev); > > devm_alloc_etherdev() should of already called ether_setup(). Ah - yes it is the setup(dev) call in alloc_netdev_mqs. I will remove that then. > > > +     ndev->netdev_ops = &sparx5_port_netdev_ops; > > +     ndev->features |= NETIF_F_LLTX; /* software tx */ > > + > > +     ether_addr_copy(ndev->dev_addr, sparx5->base_mac); > > +     ndev->dev_addr[ETH_ALEN - 1] += portno + 1; > > That will cause some surprises with wrap around. Use eth_addr_inc() OK - will do. > > > +static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool > > byte_swap) > > +{ > > +     int i, byte_cnt = 0; > > +     bool eof_flag = false, pruned_flag = false, abort_flag = > > false; > > +     u32 ifh[IFH_LEN]; > > +     struct sk_buff *skb; > > +     struct frame_info fi; > > +     struct sparx5_port *port; > > +     struct net_device *netdev; > > +     u32 *rxbuf; > > + > > +     /* Get IFH */ > > +     for (i = 0; i < IFH_LEN; i++) > > +             ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp)); > > + > > +     /* Decode IFH (whats needed) */ > > +     sparx5_ifh_parse(ifh, &fi); > > + > > +     /* Map to port netdev */ > > +     port = fi.src_port < SPX5_PORTS ? > > +             sparx5->ports[fi.src_port] : NULL; > > +     if (!port || !port->ndev) { > > +             dev_err(sparx5->dev, "Data on inactive port %d\n", > > fi.src_port); > > +             sparx5_xtr_flush(sparx5, grp); > > +             return; > > +     } > > + > > +     /* Have netdev, get skb */ > > +     netdev = port->ndev; > > +     skb = netdev_alloc_skb(netdev, netdev->mtu + ETH_HLEN); > > +     if (!skb) { > > +             sparx5_xtr_flush(sparx5, grp); > > +             dev_err(sparx5->dev, "No skb allocated\n"); > > +             return; > > +     } > > +     rxbuf = (u32 *)skb->data; > > + > > +     /* Now, pull frame data */ > > +     while (!eof_flag) { > > +             u32 val = spx5_rd(sparx5, QS_XTR_RD(grp)); > > +             u32 cmp = val; > > + > > +             if (byte_swap) > > +                     cmp = ntohl((__force __be32)val); > > + > > +             switch (cmp) { > > +             case XTR_NOT_READY: > > +                     break; > > +             case XTR_ABORT: > > +                     /* No accompanying data */ > > +                     abort_flag = true; > > +                     eof_flag = true; > > +                     break; > > +             case XTR_EOF_0: > > +             case XTR_EOF_1: > > +             case XTR_EOF_2: > > +             case XTR_EOF_3: > > +                     /* This assumes STATUS_WORD_POS == 1, Status > > +                      * just after last data > > +                      */ > > +                     byte_cnt -= (4 - XTR_VALID_BYTES(val)); > > +                     eof_flag = true; > > +                     break; > > +             case XTR_PRUNED: > > +                     /* But get the last 4 bytes as well */ > > +                     eof_flag = true; > > +                     pruned_flag = true; > > +                     fallthrough; > > +             case XTR_ESCAPE: > > +                     *rxbuf = spx5_rd(sparx5, QS_XTR_RD(grp)); > > +                     byte_cnt += 4; > > +                     rxbuf++; > > +                     break; > > +             default: > > +                     *rxbuf = val; > > +                     byte_cnt += 4; > > +                     rxbuf++; > > +             } > > +     } > > + > > +     if (abort_flag || pruned_flag || !eof_flag) { > > +             netdev_err(netdev, "Discarded frame: abort:%d > > pruned:%d eof:%d\n", > > +                        abort_flag, pruned_flag, eof_flag); > > +             kfree_skb(skb); > > +             return; > > +     } > > + > > +     if (!netif_oper_up(netdev)) { > > +             netdev_err(netdev, "Discarded frame: Interface not > > up\n"); > > +             kfree_skb(skb); > > +             return; > > +     } > > Why is it sending frames when it is not up? This is intended for received frames. A situation where the lower layers have been enabled correctly but not the port. > > > +static int sparx5_inject(struct sparx5 *sparx5, > > +                      u32 *ifh, > > +                      struct sk_buff *skb) > > +{ > > +     u32 val, w, count; > > +     int grp = INJ_QUEUE; > > +     u8 *buf; > > + > > +     val = spx5_rd(sparx5, QS_INJ_STATUS); > > +     if (!(QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp))) { > > +             pr_err("Injection: Queue not ready: 0x%lx\n", > > +                    QS_INJ_STATUS_FIFO_RDY_GET(val)); > > +             return -1; > > Always use -ESOMETHING. Yes. > > > +     } > > + > > +     if (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)) { > > +             pr_err("Injection: Watermark reached: 0x%lx\n", > > +                    QS_INJ_STATUS_WMARK_REACHED_GET(val)); > > +             return -1; > > +     } > > + > > +     /* Indicate SOF */ > > +     spx5_wr(QS_INJ_CTRL_SOF_SET(1) | > > +             QS_INJ_CTRL_GAP_SIZE_SET(1), > > +             sparx5, QS_INJ_CTRL(grp)); > > + > > +     // Write the IFH to the chip. > > +     for (w = 0; w < IFH_LEN; w++) > > +             spx5_wr(ifh[w], sparx5, QS_INJ_WR(grp)); > > + > > +     /* Write words, round up */ > > +     count = ((skb->len + 3) / 4); > > +     buf = skb->data; > > +     for (w = 0; w < count; w++, buf += 4) { > > +             val = get_unaligned((const u32 *)buf); > > +             spx5_wr(val, sparx5, QS_INJ_WR(grp)); > > +     } > > No DMA? What sort of performance do you get? Enough for the odd BPDU, > IGMP frame etc, but i guess you don't want any real bulk data to be > sent this way? Yes the register based injection/extration is not going to be fast, but the FDMA and its driver is being sent later as separate series to keep the size of this review down. > > > +irqreturn_t sparx5_xtr_handler(int irq, void *_sparx5) > > +{ > > +     struct sparx5 *sparx5 = _sparx5; > > + > > +     /* Check data in queue */ > > +     while (spx5_rd(sparx5, QS_XTR_DATA_PRESENT) & BIT(XTR_QUEUE)) > > +             sparx5_xtr_grp(sparx5, XTR_QUEUE, false); > > + > > +     return IRQ_HANDLED; > > +} > > Is there any sort of limit how many times this will loop? If somebody > is blasting 10Gbps at the CPU, will it ever get out of this loop? Hmmm, not at the moment but this is because the FDMA driver is intended to be used in these scenarios. > >    Andrew Thanks for your comments BR 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 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 33291C433DB for ; Tue, 22 Dec 2020 09:48:07 +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 CE7C223120 for ; Tue, 22 Dec 2020 09:48:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CE7C223120 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=81rRxG82/U81LKtnCh34ROOawX1p01nDFkQ0ltnT+Uo=; b=Ex/fNqiVfQziBfkIPsQewc5qX ru63ToBUWAm3aM3bBrwnYb06yHwMGovQJocbnpFjtAEQH5SauerkA2EIR9Xnvr6qNBK4lB4rv90oR sDe574KJthcOloy8uV3mEp6rjNDaK4KLgUpW+sd2Az6H48bF4eHS0X9qBjymVtr/fxLyMCoU6mZYh SrqVeOYIQUc8w3fcag70nFMlBcEQDP9qrjvXczASuSBO5KeH4PxmZoLiW370zrLgDMDN5eevR4KlP zmqMxPUClCe32I2SUCgBG95j6IPtexjjSF4QBTxwca59//GwKuI8xrWHl6ElqJSRzz0zXDX6wzQeH DIHCTK6vg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kreFL-0001iN-5x; Tue, 22 Dec 2020 09:46:23 +0000 Received: from esa.microchip.iphmx.com ([68.232.154.123]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kreFH-0001hg-Ir for linux-arm-kernel@lists.infradead.org; Tue, 22 Dec 2020 09:46:20 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1608630379; x=1640166379; h=message-id:subject:from:to:cc:date:in-reply-to: references:mime-version:content-transfer-encoding; bh=hKE3KsWXrZ6vLx3BxsacqoYKb46PJCxvRuIfCWT3H4s=; b=XXEpJlnyFjrF3/KyaSHRFTJ+cU/CxKmlZCy+X1gErvwFKJonL9i4oO0k /sE8xucfLc7fQA98IHj5clRpUp5iX5D1VRNyFAShnrVjZZRuMGI3o8nq4 sZysGfFr26IXV9X1kIo1s67lB637Cz/LgrJagEt5mcINCkTxG7BeqR3CR kZxXvJV70ViDhOdobsTaVIe5tXhX8edl+ouh1mQIJTvFDzURssaqby7Zf YXx61YATqWp6R5hJuPncICxN/MCgBAGL/0iqlNvJJsbuR0fqXapWL5HLi ePviDsoVSpl0vZpPFl0f6atfcYeSxsQb4L99cctP5TVxFUA5Jcqp+EOZQ g==; IronPort-SDR: W8WV96LUInc1fl09haIMKnJvRjdvIRS05QKLKF32fNl6K+6Tij9K8fq/8foaxhMaP6zIAspREJ nhbE9ePzfYU/76SvxZTWoA05tLI8Flexl13h2kRQHy47JDYR0m6HbKvBQ48cZCjrKcPe86c2H3 //CP7qqRkbGDbBbzLSDJHY65cAbLRTpyXWyDckn9NRL4Dp9jGYzRTlmgELPhXiU0nUn0r+OV/s QikD6VTEKNggDSEEx2sGsO2Yxql+2FiURW3BV9sTQ+1weayNMKfZ1qLpPy9eOsXhRkphHi60bm eS4= X-IronPort-AV: E=Sophos;i="5.78,438,1599548400"; d="scan'208";a="97932876" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa4.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 22 Dec 2020 02:46:17 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex03.mchp-main.com (10.10.85.151) 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 02:46:16 -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 02:46:13 -0700 Message-ID: Subject: Re: [RFC PATCH v2 3/8] net: sparx5: add hostmode with phylink support From: Steen Hegelund To: Andrew Lunn Date: Tue, 22 Dec 2020 10:46:12 +0100 In-Reply-To: <20201219195133.GD3026679@lunn.ch> References: <20201217075134.919699-1-steen.hegelund@microchip.com> <20201217075134.919699-4-steen.hegelund@microchip.com> <20201219195133.GD3026679@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_044619_879515_70636934 X-CRM114-Status: GOOD ( 37.21 ) 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 SGkgQW5kcmV3LAoKT24gU2F0LCAyMDIwLTEyLTE5IGF0IDIwOjUxICswMTAwLCBBbmRyZXcgTHVu biB3cm90ZToKPiBFWFRFUk5BTCBFTUFJTDogRG8gbm90IGNsaWNrIGxpbmtzIG9yIG9wZW4gYXR0 YWNobWVudHMgdW5sZXNzIHlvdQo+IGtub3cgdGhlIGNvbnRlbnQgaXMgc2FmZQo+IAo+ID4gK8Kg wqDCoMKgIC8qIENyZWF0ZSBhIHBoeWxpbmsgZm9yIFBIWSBtYW5hZ2VtZW50LsKgIEFsc28gaGFu ZGxlcyBTRlBzICovCj4gPiArwqDCoMKgwqAgc3B4NV9wb3J0LT5waHlsaW5rX2NvbmZpZy5kZXYg PSAmc3B4NV9wb3J0LT5uZGV2LT5kZXY7Cj4gPiArwqDCoMKgwqAgc3B4NV9wb3J0LT5waHlsaW5r X2NvCj4gPiBuZmlnLnR5cGUgPSBQSFlMSU5LX05FVERFVjsKPiA+ICvCoMKgwqDCoCBzcHg1X3Bv cnQtPnBoeWxpbmtfY29uZmlnLnBjc19wb2xsID0gdHJ1ZTsKPiA+ICsKPiA+ICvCoMKgwqDCoCAv KiBwaHlsaW5rIG5lZWRzIGEgdmFsaWQgaW50ZXJmYWNlIG1vZGUgdG8gcGFyc2UgZHQgbm9kZSAq Lwo+ID4gK8KgwqDCoMKgIGlmIChwaHlfbW9kZSA9PSBQSFlfSU5URVJGQUNFX01PREVfTkEpCj4g PiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHBoeV9tb2RlID0gUEhZX0lOVEVSRkFDRV9NT0RF XzEwR0JBU0VSOwo+IAo+IE1heWJlIGp1c3QgZW5mb3JjZSBhIHZhbGlkIHZhbHVlIGluIERUPwoK TWF5YmUgSSBuZWVkIHRvIGNsYXJpZnkgdGhhdCB5b3UgbXVzdCBjaG9vc2UgYmV0d2VlbiBhbiBF dGhlcm5ldCBjdVBIWQpvciBhbiBTRlAsIHNvIGl0IGlzIG9wdGlvbmFsLgo+IAo+ID4gKy8qIENv bmZpZ3VyYXRpb24gKi8KPiA+ICtzdGF0aWMgaW5saW5lIGJvb2wgc3Bhcng1X3VzZV9jdV9waHko c3RydWN0IHNwYXJ4NV9wb3J0ICpwb3J0KQo+ID4gK3sKPiA+ICvCoMKgwqDCoCByZXR1cm4gcG9y dC0+Y29uZi5waHlfbW9kZSAhPSBQSFlfSU5URVJGQUNFX01PREVfTkE7Cj4gPiArfQo+IAo+IFRo YXQgaXMgYSByYXRoZXIgb2RkIGRlZmluaXRpb24gb2YgY29wcGVyLgoKU2hvdWxkIEkgcmF0aGVy IHVzZSBhIGJvb2wgcHJvcGVydHkgdG8gc2VsZWN0IGJldHdlZW4gdGhlIHR3byBvcHRpb25zCihj dVBIWSBvciBTRlApPwoKPiAKPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC9ldGhlcm5ldC9t aWNyb2NoaXAvc3Bhcng1L3NwYXJ4NV9uZXRkZXYuYwo+ID4gYi9kcml2ZXJzL25ldC9ldGhlcm5l dC9taWNyb2NoaXAvc3Bhcng1L3NwYXJ4NV9uZXRkZXYuYwo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2 NDQKPiA+IGluZGV4IDAwMDAwMDAwMDAwMC4uNmY5MjgyZTlkM2Y0Cj4gPiAtLS0gL2Rldi9udWxs Cj4gPiArKysgYi9kcml2ZXJzL25ldC9ldGhlcm5ldC9taWNyb2NoaXAvc3Bhcng1L3NwYXJ4NV9u ZXRkZXYuYwo+ID4gQEAgLTAsMCArMSwyMDMgQEAKPiA+ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRp ZmllcjogR1BMLTIuMCsKPiA+ICsvKiBNaWNyb2NoaXAgU3Bhcng1IFN3aXRjaCBkcml2ZXIKPiA+ ICsgKgo+ID4gKyAqIENvcHlyaWdodCAoYykgMjAyMCBNaWNyb2NoaXAgVGVjaG5vbG9neSBJbmMu IGFuZCBpdHMKPiA+IHN1YnNpZGlhcmllcy4KPiA+ICsgKi8KPiA+ICsKPiA+ICsjaW5jbHVkZSAi c3Bhcng1X21haW4uaCIKPiAKPiBJIGRvbid0IGFjdHVhbGx5IGtub3cgd2hhdCBpcyBwcmVmZXJy ZWQgaGVyZSwgYnV0IHZlcnkgZmV3IGRyaXZlcnMKPiBpJ3ZlIHJldmlld2VkIHB1dCBhbGwgdGhl IHJlcXVpcmVkIGhlYWRlcnMgaW50byBhbm90aGVyIGhlYWRlcgo+IGZpbGUuIFRoZXkgbm9ybWFs bHkgbGlzdCB0aGVtIGluIGVhY2ggLmMgZmlsZS4KCkkgd2lsbCBsb29rIGF0IHJld29ya2luZyB0 aGlzLiAKCj4gCj4gPiArc3RhdGljIGludCBzcGFyeDVfcG9ydF9vcGVuKHN0cnVjdCBuZXRfZGV2 aWNlICpuZGV2KQo+ID4gK3sKPiA+ICvCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1X3BvcnQgKnBvcnQg PSBuZXRkZXZfcHJpdihuZGV2KTsKPiA+ICvCoMKgwqDCoCBpbnQgZXJyID0gMDsKPiA+ICsKPiA+ ICvCoMKgwqDCoCBlcnIgPSBwaHlsaW5rX29mX3BoeV9jb25uZWN0KHBvcnQtPnBoeWxpbmssIHBv cnQtPm9mX25vZGUsCj4gPiAwKTsKPiA+ICvCoMKgwqDCoCBpZiAoZXJyKSB7Cj4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgIG5ldGRldl9lcnIobmRldiwgIkNvdWxkIG5vdCBhdHRhY2ggdG8g UEhZXG4iKTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuIGVycjsKPiA+ICvC oMKgwqDCoCB9Cj4gPiArCj4gPiArwqDCoMKgwqAgcGh5bGlua19zdGFydChwb3J0LT5waHlsaW5r KTsKPiA+ICsKPiA+ICvCoMKgwqDCoCBpZiAoIW5kZXYtPnBoeWRldikgewo+IAo+IEh1bW0uIFdo ZW4gaXMgbmRldi0+cGh5ZGV2IHNldD8gSSBkb24ndCB0aGluayBwaHlsaW5rIGV2ZXIgc2V0cyBp dC4KCkluZGlyZWN0bHk6IHBoeWxpbmtfb2ZfcGh5X2Nvbm5lY3QgdXNlcyBwaHlfYXR0YWNoX2Rp cmVjdCBhbmQgdGhhdCBzZXRzCnRoZSBwaHlkZXYuCgo+IAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCAvKiBwb3dlciB1cCBzZXJkZXMgKi8KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqAgcG9ydC0+Y29uZi5wb3dlcl9kb3duID0gZmFsc2U7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGVyciA9IHBoeV9wb3dlcl9vbihwb3J0LT5zZXJkZXMpOwo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBpZiAoZXJyKQo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqAgbmV0ZGV2X2VycihuZGV2LCAiJXMgZmFpbGVkXG4iLCBfX2Z1bmNfXyk7Cj4g PiArwqDCoMKgwqAgfQo+ID4gKwo+ID4gK8KgwqDCoMKgIHJldHVybiBlcnI7Cj4gPiArfQo+IAo+ ID4gK3N0cnVjdCBuZXRfZGV2aWNlICpzcGFyeDVfY3JlYXRlX25ldGRldihzdHJ1Y3Qgc3Bhcng1 ICpzcGFyeDUsIHUzMgo+ID4gcG9ydG5vKQo+ID4gK3sKPiA+ICvCoMKgwqDCoCBzdHJ1Y3QgbmV0 X2RldmljZSAqbmRldjsKPiA+ICvCoMKgwqDCoCBzdHJ1Y3Qgc3Bhcng1X3BvcnQgKnNweDVfcG9y dDsKPiA+ICsKPiA+ICvCoMKgwqDCoCBuZGV2ID0gZGV2bV9hbGxvY19ldGhlcmRldihzcGFyeDUt PmRldiwgc2l6ZW9mKHN0cnVjdAo+ID4gc3Bhcng1X3BvcnQpKTsKPiA+ICvCoMKgwqDCoCBpZiAo IW5kZXYpCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybiBFUlJfUFRSKC1FTk9N RU0pOwo+ID4gKwo+ID4gK8KgwqDCoMKgIFNFVF9ORVRERVZfREVWKG5kZXYsIHNwYXJ4NS0+ZGV2 KTsKPiA+ICvCoMKgwqDCoCBzcHg1X3BvcnQgPSBuZXRkZXZfcHJpdihuZGV2KTsKPiA+ICvCoMKg wqDCoCBzcHg1X3BvcnQtPm5kZXYgPSBuZGV2Owo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+c3Bh cng1ID0gc3Bhcng1Owo+ID4gK8KgwqDCoMKgIHNweDVfcG9ydC0+cG9ydG5vID0gcG9ydG5vOwo+ ID4gK8KgwqDCoMKgIHNwYXJ4NV9zZXRfcG9ydF9pZmgoc3B4NV9wb3J0LT5pZmgsIHBvcnRubyk7 Cj4gPiArwqDCoMKgwqAgc25wcmludGYobmRldi0+bmFtZSwgSUZOQU1TSVosICJldGglZCIsIHBv cnRubyk7Cj4gPiArCj4gPiArwqDCoMKgwqAgZXRoZXJfc2V0dXAobmRldik7Cj4gCj4gZGV2bV9h bGxvY19ldGhlcmRldigpIHNob3VsZCBvZiBhbHJlYWR5IGNhbGxlZCBldGhlcl9zZXR1cCgpLgoK QWggLSB5ZXMgaXQgaXMgdGhlIHNldHVwKGRldikgY2FsbCBpbiBhbGxvY19uZXRkZXZfbXFzLiBJ IHdpbGwgcmVtb3ZlCnRoYXQgdGhlbi4KPiAKPiA+ICvCoMKgwqDCoCBuZGV2LT5uZXRkZXZfb3Bz ID0gJnNwYXJ4NV9wb3J0X25ldGRldl9vcHM7Cj4gPiArwqDCoMKgwqAgbmRldi0+ZmVhdHVyZXMg fD0gTkVUSUZfRl9MTFRYOyAvKiBzb2Z0d2FyZSB0eCAqLwo+ID4gKwo+ID4gK8KgwqDCoMKgIGV0 aGVyX2FkZHJfY29weShuZGV2LT5kZXZfYWRkciwgc3Bhcng1LT5iYXNlX21hYyk7Cj4gPiArwqDC oMKgwqAgbmRldi0+ZGV2X2FkZHJbRVRIX0FMRU4gLSAxXSArPSBwb3J0bm8gKyAxOwo+IAo+IFRo YXQgd2lsbCBjYXVzZSBzb21lIHN1cnByaXNlcyB3aXRoIHdyYXAgYXJvdW5kLiBVc2UgZXRoX2Fk ZHJfaW5jKCkKCk9LIC0gd2lsbCBkby4KCj4gCj4gPiArc3RhdGljIHZvaWQgc3Bhcng1X3h0cl9n cnAoc3RydWN0IHNwYXJ4NSAqc3Bhcng1LCB1OCBncnAsIGJvb2wKPiA+IGJ5dGVfc3dhcCkKPiA+ ICt7Cj4gPiArwqDCoMKgwqAgaW50IGksIGJ5dGVfY250ID0gMDsKPiA+ICvCoMKgwqDCoCBib29s IGVvZl9mbGFnID0gZmFsc2UsIHBydW5lZF9mbGFnID0gZmFsc2UsIGFib3J0X2ZsYWcgPQo+ID4g ZmFsc2U7Cj4gPiArwqDCoMKgwqAgdTMyIGlmaFtJRkhfTEVOXTsKPiA+ICvCoMKgwqDCoCBzdHJ1 Y3Qgc2tfYnVmZiAqc2tiOwo+ID4gK8KgwqDCoMKgIHN0cnVjdCBmcmFtZV9pbmZvIGZpOwo+ID4g K8KgwqDCoMKgIHN0cnVjdCBzcGFyeDVfcG9ydCAqcG9ydDsKPiA+ICvCoMKgwqDCoCBzdHJ1Y3Qg bmV0X2RldmljZSAqbmV0ZGV2Owo+ID4gK8KgwqDCoMKgIHUzMiAqcnhidWY7Cj4gPiArCj4gPiAr wqDCoMKgwqAgLyogR2V0IElGSCAqLwo+ID4gK8KgwqDCoMKgIGZvciAoaSA9IDA7IGkgPCBJRkhf TEVOOyBpKyspCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGlmaFtpXSA9IHNweDVfcmQo c3Bhcng1LCBRU19YVFJfUkQoZ3JwKSk7Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogRGVjb2RlIElG SCAod2hhdHMgbmVlZGVkKSAqLwo+ID4gK8KgwqDCoMKgIHNwYXJ4NV9pZmhfcGFyc2UoaWZoLCAm ZmkpOwo+ID4gKwo+ID4gK8KgwqDCoMKgIC8qIE1hcCB0byBwb3J0IG5ldGRldiAqLwo+ID4gK8Kg wqDCoMKgIHBvcnQgPSBmaS5zcmNfcG9ydCA8IFNQWDVfUE9SVFMgPwo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBzcGFyeDUtPnBvcnRzW2ZpLnNyY19wb3J0XSA6IE5VTEw7Cj4gPiArwqDC oMKgwqAgaWYgKCFwb3J0IHx8ICFwb3J0LT5uZGV2KSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGRldl9lcnIoc3Bhcng1LT5kZXYsICJEYXRhIG9uIGluYWN0aXZlIHBvcnQgJWRcbiIs Cj4gPiBmaS5zcmNfcG9ydCk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNwYXJ4NV94 dHJfZmx1c2goc3Bhcng1LCBncnApOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZXR1 cm47Cj4gPiArwqDCoMKgwqAgfQo+ID4gKwo+ID4gK8KgwqDCoMKgIC8qIEhhdmUgbmV0ZGV2LCBn ZXQgc2tiICovCj4gPiArwqDCoMKgwqAgbmV0ZGV2ID0gcG9ydC0+bmRldjsKPiA+ICvCoMKgwqDC oCBza2IgPSBuZXRkZXZfYWxsb2Nfc2tiKG5ldGRldiwgbmV0ZGV2LT5tdHUgKyBFVEhfSExFTik7 Cj4gPiArwqDCoMKgwqAgaWYgKCFza2IpIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg c3Bhcng1X3h0cl9mbHVzaChzcGFyeDUsIGdycCk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgIGRldl9lcnIoc3Bhcng1LT5kZXYsICJObyBza2IgYWxsb2NhdGVkXG4iKTsKPiA+ICvCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqAgcmV0dXJuOwo+ID4gK8KgwqDCoMKgIH0KPiA+ICvCoMKgwqDC oCByeGJ1ZiA9ICh1MzIgKilza2ItPmRhdGE7Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogTm93LCBw dWxsIGZyYW1lIGRhdGEgKi8KPiA+ICvCoMKgwqDCoCB3aGlsZSAoIWVvZl9mbGFnKSB7Cj4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHUzMiB2YWwgPSBzcHg1X3JkKHNwYXJ4NSwgUVNfWFRS X1JEKGdycCkpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1MzIgY21wID0gdmFsOwo+ ID4gKwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBpZiAoYnl0ZV9zd2FwKQo+ID4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY21wID0gbnRvaGwoKF9fZm9y Y2UgX19iZTMyKXZhbCk7Cj4gPiArCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHN3aXRj aCAoY21wKSB7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNhc2UgWFRSX05PVF9SRUFE WToKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJyZWFrOwo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjYXNlIFhUUl9BQk9SVDoKPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIC8qIE5vIGFjY29tcGFueWluZyBkYXRh ICovCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBhYm9ydF9m bGFnID0gdHJ1ZTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGVvZl9mbGFnID0gdHJ1ZTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIGJyZWFrOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjYXNlIFhUUl9FT0Zf MDoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY2FzZSBYVFJfRU9GXzE6Cj4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIGNhc2UgWFRSX0VPRl8yOgo+ID4gK8KgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCBjYXNlIFhUUl9FT0ZfMzoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIC8qIFRoaXMgYXNzdW1lcyBTVEFUVVNfV09SRF9QT1MgPT0gMSwgU3Rh dHVzCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICoganVz dCBhZnRlciBsYXN0IGRhdGEKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgKi8KPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IGJ5dGVfY250IC09ICg0IC0gWFRSX1ZBTElEX0JZVEVTKHZhbCkpOwo+ID4gK8KgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZW9mX2ZsYWcgPSB0cnVlOwo+ID4gK8KgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgYnJlYWs7Cj4gPiArwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgIGNhc2UgWFRSX1BSVU5FRDoKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIC8qIEJ1dCBnZXQgdGhlIGxhc3QgNCBieXRlcyBhcyB3ZWxs ICovCj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBlb2ZfZmxh ZyA9IHRydWU7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBw cnVuZWRfZmxhZyA9IHRydWU7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBmYWxsdGhyb3VnaDsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgY2FzZSBY VFJfRVNDQVBFOgo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg KnJ4YnVmID0gc3B4NV9yZChzcGFyeDUsIFFTX1hUUl9SRChncnApKTsKPiA+ICvCoMKgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGJ5dGVfY250ICs9IDQ7Cj4gPiArwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByeGJ1ZisrOwo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgYnJlYWs7Cj4gPiArwqDCoMKgwqDCoMKg wqDCoMKgwqDCoMKgIGRlZmF1bHQ6Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqDCoCAqcnhidWYgPSB2YWw7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoCBieXRlX2NudCArPSA0Owo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAgcnhidWYrKzsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg fQo+ID4gK8KgwqDCoMKgIH0KPiA+ICsKPiA+ICvCoMKgwqDCoCBpZiAoYWJvcnRfZmxhZyB8fCBw cnVuZWRfZmxhZyB8fCAhZW9mX2ZsYWcpIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAg bmV0ZGV2X2VycihuZXRkZXYsICJEaXNjYXJkZWQgZnJhbWU6IGFib3J0OiVkCj4gPiBwcnVuZWQ6 JWQgZW9mOiVkXG4iLAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgYWJvcnRfZmxhZywgcHJ1bmVkX2ZsYWcsIGVvZl9mbGFnKTsKPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqAga2ZyZWVfc2tiKHNrYik7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKg wqDCoMKgIHJldHVybjsKPiA+ICvCoMKgwqDCoCB9Cj4gPiArCj4gPiArwqDCoMKgwqAgaWYgKCFu ZXRpZl9vcGVyX3VwKG5ldGRldikpIHsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbmV0 ZGV2X2VycihuZXRkZXYsICJEaXNjYXJkZWQgZnJhbWU6IEludGVyZmFjZSBub3QKPiA+IHVwXG4i KTsKPiA+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAga2ZyZWVfc2tiKHNrYik7Cj4gPiArwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJldHVybjsKPiA+ICvCoMKgwqDCoCB9Cj4gCj4gV2h5IGlz IGl0IHNlbmRpbmcgZnJhbWVzIHdoZW4gaXQgaXMgbm90IHVwPwoKVGhpcyBpcyBpbnRlbmRlZCBm b3IgcmVjZWl2ZWQgZnJhbWVzLiBBIHNpdHVhdGlvbiB3aGVyZSB0aGUgbG93ZXIKbGF5ZXJzIGhh dmUgYmVlbiBlbmFibGVkIGNvcnJlY3RseSBidXQgbm90IHRoZSBwb3J0LgoKPiAKPiA+ICtzdGF0 aWMgaW50IHNwYXJ4NV9pbmplY3Qoc3RydWN0IHNwYXJ4NSAqc3Bhcng1LAo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB1MzIgKmlmaCwKPiA+ICvCoMKgwqDC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgc3RydWN0IHNrX2J1ZmYgKnNrYikK PiA+ICt7Cj4gPiArwqDCoMKgwqAgdTMyIHZhbCwgdywgY291bnQ7Cj4gPiArwqDCoMKgwqAgaW50 IGdycCA9IElOSl9RVUVVRTsKPiA+ICvCoMKgwqDCoCB1OCAqYnVmOwo+ID4gKwo+ID4gK8KgwqDC oMKgIHZhbCA9IHNweDVfcmQoc3Bhcng1LCBRU19JTkpfU1RBVFVTKTsKPiA+ICvCoMKgwqDCoCBp ZiAoIShRU19JTkpfU1RBVFVTX0ZJRk9fUkRZX0dFVCh2YWwpICYgQklUKGdycCkpKSB7Cj4gPiAr wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHByX2VycigiSW5qZWN0aW9uOiBRdWV1ZSBub3QgcmVh ZHk6IDB4JWx4XG4iLAo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg IFFTX0lOSl9TVEFUVVNfRklGT19SRFlfR0VUKHZhbCkpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCByZXR1cm4gLTE7Cj4gCj4gQWx3YXlzIHVzZSAtRVNPTUVUSElORy4KClllcy4KCj4g Cj4gPiArwqDCoMKgwqAgfQo+ID4gKwo+ID4gK8KgwqDCoMKgIGlmIChRU19JTkpfU1RBVFVTX1dN QVJLX1JFQUNIRURfR0VUKHZhbCkgJiBCSVQoZ3JwKSkgewo+ID4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBwcl9lcnIoIkluamVjdGlvbjogV2F0ZXJtYXJrIHJlYWNoZWQ6IDB4JWx4XG4iLAo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIFFTX0lOSl9TVEFUVVNf V01BUktfUkVBQ0hFRF9HRVQodmFsKSk7Cj4gPiArwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHJl dHVybiAtMTsKPiA+ICvCoMKgwqDCoCB9Cj4gPiArCj4gPiArwqDCoMKgwqAgLyogSW5kaWNhdGUg U09GICovCj4gPiArwqDCoMKgwqAgc3B4NV93cihRU19JTkpfQ1RSTF9TT0ZfU0VUKDEpIHwKPiA+ ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgUVNfSU5KX0NUUkxfR0FQX1NJWkVfU0VUKDEpLAo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzcGFyeDUsIFFTX0lOSl9DVFJMKGdycCkpOwo+ ID4gKwo+ID4gK8KgwqDCoMKgIC8vIFdyaXRlIHRoZSBJRkggdG8gdGhlIGNoaXAuCj4gPiArwqDC oMKgwqAgZm9yICh3ID0gMDsgdyA8IElGSF9MRU47IHcrKykKPiA+ICvCoMKgwqDCoMKgwqDCoMKg wqDCoMKgwqAgc3B4NV93cihpZmhbd10sIHNwYXJ4NSwgUVNfSU5KX1dSKGdycCkpOwo+ID4gKwo+ ID4gK8KgwqDCoMKgIC8qIFdyaXRlIHdvcmRzLCByb3VuZCB1cCAqLwo+ID4gK8KgwqDCoMKgIGNv dW50ID0gKChza2ItPmxlbiArIDMpIC8gNCk7Cj4gPiArwqDCoMKgwqAgYnVmID0gc2tiLT5kYXRh Owo+ID4gK8KgwqDCoMKgIGZvciAodyA9IDA7IHcgPCBjb3VudDsgdysrLCBidWYgKz0gNCkgewo+ ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCB2YWwgPSBnZXRfdW5hbGlnbmVkKChjb25zdCB1 MzIgKilidWYpOwo+ID4gK8KgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBzcHg1X3dyKHZhbCwgc3Bh cng1LCBRU19JTkpfV1IoZ3JwKSk7Cj4gPiArwqDCoMKgwqAgfQo+IAo+IE5vIERNQT8gV2hhdCBz b3J0IG9mIHBlcmZvcm1hbmNlIGRvIHlvdSBnZXQ/IEVub3VnaCBmb3IgdGhlIG9kZCBCUERVLAo+ IElHTVAgZnJhbWUgZXRjLCBidXQgaSBndWVzcyB5b3UgZG9uJ3Qgd2FudCBhbnkgcmVhbCBidWxr IGRhdGEgdG8gYmUKPiBzZW50IHRoaXMgd2F5PwoKWWVzIHRoZSByZWdpc3RlciBiYXNlZCBpbmpl Y3Rpb24vZXh0cmF0aW9uIGlzIG5vdCBnb2luZyB0byBiZSBmYXN0LCBidXQKdGhlIEZETUEgYW5k IGl0cyBkcml2ZXIgaXMgYmVpbmcgc2VudCBsYXRlciBhcyBzZXBhcmF0ZSBzZXJpZXMgdG8ga2Vl cAp0aGUgc2l6ZSBvZiB0aGlzIHJldmlldyBkb3duLgoKPiAKPiA+ICtpcnFyZXR1cm5fdCBzcGFy eDVfeHRyX2hhbmRsZXIoaW50IGlycSwgdm9pZCAqX3NwYXJ4NSkKPiA+ICt7Cj4gPiArwqDCoMKg wqAgc3RydWN0IHNwYXJ4NSAqc3Bhcng1ID0gX3NwYXJ4NTsKPiA+ICsKPiA+ICvCoMKgwqDCoCAv KiBDaGVjayBkYXRhIGluIHF1ZXVlICovCj4gPiArwqDCoMKgwqAgd2hpbGUgKHNweDVfcmQoc3Bh cng1LCBRU19YVFJfREFUQV9QUkVTRU5UKSAmIEJJVChYVFJfUVVFVUUpKQo+ID4gK8KgwqDCoMKg wqDCoMKgwqDCoMKgwqDCoCBzcGFyeDVfeHRyX2dycChzcGFyeDUsIFhUUl9RVUVVRSwgZmFsc2Up Owo+ID4gKwo+ID4gK8KgwqDCoMKgIHJldHVybiBJUlFfSEFORExFRDsKPiA+ICt9Cj4gCj4gSXMg dGhlcmUgYW55IHNvcnQgb2YgbGltaXQgaG93IG1hbnkgdGltZXMgdGhpcyB3aWxsIGxvb3A/IElm IHNvbWVib2R5Cj4gaXMgYmxhc3RpbmcgMTBHYnBzIGF0IHRoZSBDUFUsIHdpbGwgaXQgZXZlciBn ZXQgb3V0IG9mIHRoaXMgbG9vcD8KCkhtbW0sIG5vdCBhdCB0aGUgbW9tZW50IGJ1dCB0aGlzIGlz IGJlY2F1c2UgdGhlIEZETUEgZHJpdmVyIGlzIGludGVuZGVkCnRvIGJlIHVzZWQgaW4gdGhlc2Ug c2NlbmFyaW9zLgoKPiAKPiDCoMKgIEFuZHJldwoKVGhhbmtzIGZvciB5b3VyIGNvbW1lbnRzCgpC UgpTdGVlbgoKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f CmxpbnV4LWFybS1rZXJuZWwgbWFpbGluZyBsaXN0CmxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5m cmFkZWFkLm9yZwpodHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xp bnV4LWFybS1rZXJuZWwK