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=-9.0 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT 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 7D776C5CFFE for ; Mon, 10 Dec 2018 12:40:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7DE2E20821 for ; Mon, 10 Dec 2018 12:40:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=cadence.com header.i=@cadence.com header.b="tNjuW8r0"; dkim=pass (1024-bit key) header.d=cadence.com header.i=@cadence.com header.b="IlKZQ2Xw" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7DE2E20821 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=cadence.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727792AbeLJMkv (ORCPT ); Mon, 10 Dec 2018 07:40:51 -0500 Received: from mx0b-0014ca01.pphosted.com ([208.86.201.193]:48392 "EHLO mx0a-0014ca01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726699AbeLJMku (ORCPT ); Mon, 10 Dec 2018 07:40:50 -0500 Received: from pps.filterd (m0042333.ppops.net [127.0.0.1]) by mx0b-0014ca01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id wBACcqgC009072; Mon, 10 Dec 2018 04:40:33 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cadence.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=proofpoint; bh=XliXZTkkfHNk6jcAZ3e/8xqpH0PJIftGYLrRujAQ1zo=; b=tNjuW8r0QD0Ugb/P7ljuKIzq9TJ0TErHFtuE46ymT+PVXRsWARWSfz8fPvhM4HSjnOw9 pOMkfLUrsg1nMMAdHL+FBTgvi9dhP2m5LR7qFHADBS3jCVgdPMh5MKsxf2kR3JoqxsJK KsxcSJRMAxCoUXXcgSwOLwxeU70wYvVH0kZ+moBTkZhIOdqCUbQLAnByK6OSnS4dYmYP ZsKtVDExpKSLvdP/CyvjMnTUyepoxFyqHIeuL81qetZrox2YiSl2z6u9uQJfV9ul5YXm NgM1rLK0TifcRNJWUH54FwiCcs/Jl708+RKSWbf6WBLeQw1aK52gpCxqYXypVTuOP0p3 DA== Authentication-Results: cadence.com; spf=pass smtp.mailfrom=pawell@cadence.com Received: from nam03-dm3-obe.outbound.protection.outlook.com (mail-dm3nam03lp2057.outbound.protection.outlook.com [104.47.41.57]) by mx0b-0014ca01.pphosted.com with ESMTP id 2p8ae2hxyu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 10 Dec 2018 04:40:31 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cadence.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XliXZTkkfHNk6jcAZ3e/8xqpH0PJIftGYLrRujAQ1zo=; b=IlKZQ2Xwt0gHWCDsDOOLrpp6bK8EFlJWrVvjxpJZ3xlgJNDwjM7bMp35TK1pxN8Jg8IuM+XJLR5QhT+PPQ76I1Md7DmLtUMPCiPh4TpKBYj3DQ7SILfAcwOC9HM6ST61ePgirC9W1DKmSZZZdRJm7V0tP1QzACzd9MDWUrxsFA4= Received: from SN4PR0701CA0005.namprd07.prod.outlook.com (2603:10b6:803:28::15) by SN1PR07MB2175.namprd07.prod.outlook.com (2a01:111:e400:c455::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1404.19; Mon, 10 Dec 2018 12:40:27 +0000 Received: from DM3NAM05FT005.eop-nam05.prod.protection.outlook.com (2a01:111:f400:7e51::203) by SN4PR0701CA0005.outlook.office365.com (2603:10b6:803:28::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1404.18 via Frontend Transport; Mon, 10 Dec 2018 12:40:27 +0000 Received-SPF: SoftFail (protection.outlook.com: domain of transitioning cadence.com discourages use of 199.43.4.28 as permitted sender) Received: from rmmaillnx1.cadence.com (199.43.4.28) by DM3NAM05FT005.mail.protection.outlook.com (10.152.98.110) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1425.9 via Frontend Transport; Mon, 10 Dec 2018 12:40:26 +0000 Received: from maileu3.global.cadence.com (maileu3.cadence.com [10.160.88.99]) by rmmaillnx1.cadence.com (8.14.4/8.14.4) with ESMTP id wBACeImC012942 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=OK); Mon, 10 Dec 2018 07:40:22 -0500 X-CrossPremisesHeadersFilteredBySendConnector: maileu3.global.cadence.com Received: from maileu3.global.cadence.com (10.160.88.99) by maileu3.global.cadence.com (10.160.88.99) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Mon, 10 Dec 2018 13:40:21 +0100 Received: from lvlogina.cadence.com (10.165.176.102) by maileu3.global.cadence.com (10.160.88.99) with Microsoft SMTP Server (TLS) id 15.0.1367.3 via Frontend Transport; Mon, 10 Dec 2018 13:40:20 +0100 Received: from lvlogina.cadence.com (localhost.localdomain [127.0.0.1]) by lvlogina.cadence.com (8.14.4/8.14.4) with ESMTP id wBACeHBQ007554; Mon, 10 Dec 2018 12:40:17 GMT Received: (from pawell@localhost) by lvlogina.cadence.com (8.14.4/8.14.4/Submit) id wBACeHjd007544; Mon, 10 Dec 2018 12:40:17 GMT From: Pawel Laszczak To: CC: , , , , , , , , , , , , , Pawel Laszczak Subject: [PATCH v1 2/2] usb:cdns3 Add Cadence USB3 DRD Driver Date: Mon, 10 Dec 2018 12:39:15 +0000 Message-ID: <1544445555-17325-3-git-send-email-pawell@cadence.com> X-Mailer: git-send-email 1.7.11.2 In-Reply-To: <1544445555-17325-1-git-send-email-pawell@cadence.com> References: <1544445555-17325-1-git-send-email-pawell@cadence.com> MIME-Version: 1.0 Content-Type: text/plain X-OrganizationHeadersPreserved: maileu3.global.cadence.com X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:199.43.4.28;IPV:CAL;SCL:-1;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(136003)(376002)(346002)(396003)(39860400002)(2980300002)(36092001)(189003)(199004)(51234002)(51416003)(7416002)(186003)(16586007)(305945005)(8676002)(53946003)(76176011)(48376002)(81156014)(4326008)(36756003)(5660300001)(478600001)(42186006)(50466002)(53936002)(316002)(81166006)(26826003)(54906003)(107886003)(87636003)(19627235002)(4720700003)(47776003)(14444005)(68736007)(426003)(11346002)(126002)(336012)(476003)(6916009)(105596002)(2351001)(106466001)(69596002)(486006)(97736004)(26005)(4744004)(551934003)(8936002)(356004)(2906002)(575784001)(86362001)(2616005)(446003)(50226002)(579004)(569006);DIR:OUT;SFP:1101;SCL:1;SRVR:SN1PR07MB2175;H:rmmaillnx1.cadence.com;FPR:;SPF:SoftFail;LANG:en;PTR:InfoDomainNonexistent;MX:1;A:1; X-Microsoft-Exchange-Diagnostics: 1;DM3NAM05FT005;1:Rk43rL/1zhbBJQRq+Fa3QNe0nAJLgu+d+qly7Wq1JY8QyhVSyzp9dKg6AqVPnytM7nhQRhtsBCq4FQV3icOlEeXNLu8mtQIytO8kjZF+KbXJgHaHs+zcdxFTE2hG9gMS X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 5b6c35b2-0e95-4d23-b940-08d65e9ca930 X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:(2390098)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(2017052603328)(7153060);SRVR:SN1PR07MB2175; X-Microsoft-Exchange-Diagnostics: 1;SN1PR07MB2175;3:4b6ySRrU69sEhomqWABA1yHxk3N1/2J1+R+CdatHWLoYAf8gPVdJo8u9i/umV/9YUuwsKG+p1Ap2BLHJTU0UXrPoiWMQbZpYpnlf8uVUP2rEVdvMzJYEiEQHFol4JkPlt0vn/f2DvbhwcM+++gx000RIl31vUTnoP18/YGVjYcNerCC5bT9da/n4mgYv1Tgly0ozDi/r1EzNxlcMei6h4g87v31oT1n+xa7wVH0dW4dcsV1gyCAz5uyh4oCjA1C2faoVF080+nyVajr2Zm/Nkg0j4XkX5Ebf8dXTjJv7APF+gkYrubwnB1s29CMPnDTPVZAw2LuBhU09daAhRAiDdQ==;25:roAN3c15C12FxkE5zUTyedhdP3xa/WELlOuzozvq6l5RdupihEhmpIEXeykQWZcGV+iNXsb2dYu03cdssikSXJJ2n7GB8lt0i1EAiVmodSjki8U7XbTS1qyKdlcO8Pp2FVjrr/MC6gG+nHBnVop4gclR223mBrabYm5YaLsybdgXQE/mx+QwDVZkFvA43g2qYEgLi4dsaZ6TlZWkBYxZnPcojNa4a/zzo6tG9xJonSX2V0zXDEhKGE/7Sg6Q/87V444JyGesuusgCHBbrFpLLeWDakHgUGIdC7zQmuubaFe128zjPys1ASpvkgFmwf/s7WbGwTM6N4orIBlq+iTZaTvJ8wjdQatAthbYWiEIo34= X-MS-TrafficTypeDiagnostic: SN1PR07MB2175: X-Microsoft-Exchange-Diagnostics: 1;SN1PR07MB2175;31:YQV2/3By+0/u0HO1pFy9I8cZw9i5Tw4qjFGSpVvrQePzJZ3nzpRFo9Qo6tuNUbmqvJfW69oZn7l1MS/D+w+ZIW2tk/dv9LDfwwXQ14XHh8JDN4fyjJfDjWNptihmaYmeA0f/nu9uHgxpBj8IMlFTqchh0XEvIti7sF7slDr/FiQEkRimaUpL4/No+Fr/5+PkCaRY1FkGqtPrdDvXCPOMj3i3QpsMaIDZoP3wWxJQ5XQ=;20:8QKkS/7EhFP3UyP9jLNIJMa52Hu0fRxK9nelf2Z83pML2cpszzc9MlKA9BwgK3wbQm8Avry6e3XhTiSqtNXcXS3E84JwBTswb4HTxvghDwnrKt/PHMvm6C7zHoBVA2DgH53Ox8/P928RN9yQ1u/oGUnVYh2faECQiGXflv/RCY/cc6EZFx/b96mklTsQfOkgsnXJonoRtJRGrElf7GKKdnN3bvB/elzjq/Dup0Zip1eeC5QKu3SXzfbfZiGxGk+tUv6Mx8psIPa3BXJRQqLt+qm91HMrg1W370RYu7+ziFQwsXAiTrdk1m4NSEtwMFke/sQsZbNJ94Y7KCWW3ndnd26C0EnXnHZnL9uJGdmYr9sMCJ7JHQO2Ar5Q+PWKLngITzFmAeFRi8u7IaZX9KLWw626IqgFhLYGIR96DsDWpsDv7LaASMocUOs5E1uEbTy8OXflU1AnBad4fCGaArBVTguowd1WjamS3tLPH3s5Iv6haboDIRnlEz6PUp1kUaDQ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(10201501046)(3002001)(93006095)(93003095)(3231455)(999002)(944501520)(52105112)(148016)(149066)(150057)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123558120)(20161123564045)(20161123560045)(201708071742011)(7699051)(76991095);SRVR:SN1PR07MB2175;BCL:0;PCL:0;RULEID:;SRVR:SN1PR07MB2175; X-Microsoft-Exchange-Diagnostics: 1;SN1PR07MB2175;4:OGhEYkAr2GSalPZdwaHTOfsUfRr7q2htnPEyFGZB/EvT9EWaIynMDc1845WCgbjhGbaJQx550Ci8bEr90nAvWJEDNz1hHac5hosOVWf3TgSqAivPOIDNsNTPw1Gv1bwD+ko+araiTHWW8jII1Dm8IYZph2bOkVFC/LwkG8Y3uiQB2yH0UFWXJI8WdJ7RYwiIr62eSd7fK5RD4+YH4/gNfwwisfEo4eKc2IcHv4ZxHU30QkDVe37bE8XUSgrOq012R7EcE9RaoeMOKBgSPyt8XA== X-Forefront-PRVS: 08828D20BC X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;SN1PR07MB2175;23:NdzlrHY/Lj3AwEXkrxwE69m/BfUJTnjYW7J3F8xlG?= =?us-ascii?Q?22FLG/0zxW4cXX9o+n2CdcNee5kLQQbUfyGAkMntHJzKPXVHt7lpqAjRMpEm?= =?us-ascii?Q?9Mluc/z5q6TDQWQSMJEmV2ULAh9kf5xvymQDfJFAi4TWVGdtDJ3GvPlH82NE?= =?us-ascii?Q?WmeeDuiMQeg1HVauKjMMEXwDL/qBXcA/JPaL/TbTSWsSOGd4/s4clp+e20K6?= =?us-ascii?Q?czq1AZpc/xdS8JSz0a1yeMHhSfDdb3yXOj/ZT9hhzJlDP3t8SlJLktXMPXDB?= =?us-ascii?Q?Q0vv5dngdyknyV+aRyWKPQSaysqBRl43zShYeYMn9UJPFFO9OYZJfKSLSD5z?= =?us-ascii?Q?jEgiSrZsDQeVTdTuKCfAv9HcNpBWA1/ccwQ+VOR/74MUi19atJ+gQAe4d0/0?= =?us-ascii?Q?jSoomSuK6PQ1zQymP/d2TO652n65pnOB1zsgCHXx5+fSJ6oddOO9pUDGqpzl?= =?us-ascii?Q?NXDjqZ1XJnI187jSTNuF4Je9dwgDdftBCNN0tStko8nByYfPHUYUt1PhGbaE?= =?us-ascii?Q?UQ2tPLKwFzdot233TH35l70RJsTFb6ZusfNZzINqWrMY5ScRCg4hnWhgA+lg?= =?us-ascii?Q?EiSu/nt5zDaJv3g7YZSZYAw2NPTXKcdgTpMrSj2u/wdiEH8SfzBtiXWIACnZ?= =?us-ascii?Q?g6zACw5GC6rlYBXqnWGF1z/UrMenBlI+5sGe6M4dxu0PrtLw8N/RQQlLvSBL?= =?us-ascii?Q?dUEhA6YAvJHTdHAU1tUROzd1WyvIdolqeyaEURF0HtK157g/oS0u61m51WEF?= =?us-ascii?Q?+oi4j5CVCnZD+DC2UQtDgvoba6EfM77zVn5mr7tjlfqv+FtH/fM0uQIOgeSj?= =?us-ascii?Q?qvziFDuC5q7BcTQiuSZgFoK5/KQ85FSK1AN8UsMmTPm8RsdY54uf+cCAmwYi?= =?us-ascii?Q?URK0qYh6KfhsSOGJJiCyAckrM+yHX2/erdklOpnQfD8k2EEvDPfaiV7MoCMy?= =?us-ascii?Q?5U19VUjgVug+4p+J3wBAIq4GCx2brOFyqNpXLSiLy2XPqXoolwy8zJZ0zdqn?= =?us-ascii?Q?WPNvlL4I+1ljBQ9c7UXsieat/YTYzTNDfBOtOIcN+abBicypKl0E5P9gf1kZ?= =?us-ascii?Q?2TojBG/VTl/8O4jMqJgecyLZyPuMdcpQOpU9Z9VxydmoG/ppBEyt5szT2xFT?= =?us-ascii?Q?FFWRVIUGzdJTMlGrEsvBqBzn8t3lO1R3vpxtlG9EwmFwC8qjcf9+3tEVRIjo?= =?us-ascii?Q?fdxdad2c9xcCgCRAF26RCSnZH2K6s9shOgCIYguZs9IzokGSDW/A+Zcf6S2M?= =?us-ascii?Q?Q6PoLvPpvIASGCYf5swW6YhXje4Gnibpj5OVekEWGDgaKJ3JkEv4NPkEUgIe?= =?us-ascii?Q?cb3U7jjzHmiPaQL7mmA0PHCyyz8sVAwNE3yR5dB7zmJDysByu3o3owoXmcjI?= =?us-ascii?Q?s37ONH9/U+uRl86ytIWz8WLOaPEyhDdfix5h4rQ7zzL/RIG?= X-Microsoft-Antispam-Message-Info: fYY74iKdc/QjTVhSraZe7OPzpepOXpcF9c+sHYVPPHhdvB8PMC5/JYax/zgmX+uYED0vwaW5c6D837Q7sKF0PZPQMTjy2XffUmo9HidfSy1O99c/dAd9OtlNLHjWTam9ITNIDsAdI3sKtmwCBihpWzoV68oErKnk/GQif2LPuYNIlSJAoSLsoYYyF2dbyoRucXu8igNvC5vOBeeFkb5T/Q2jl1g4bH53cfHoplen78trdpILquRtoPxcmrsBqK9Ig+piDpjzAQ+vFEtNauGiW7z5fGugBpF+fVvrQ+lZw2WlOc0ZlPeB3u+V9COQuNas X-Microsoft-Exchange-Diagnostics: 1;SN1PR07MB2175;6:oG7i5lI8DyLARDIf3K5T0zd09JKPVdpcUhAe7Mq8gARhfcpPT7ye4d831u3YriXfJVaUB60ISA3JubbHRDBGeG+9sGxNlbDcDKUaR7pAHlUtpm7MQgDZQ5EE0Y4z7NgyztV7kdbfWM5TPJI+Y874VREgdOPVTcNFld2oQmpQm0BOr5NALV8MT89EBegEuXqVK9upLxzV5XUtd4yoCqezrxr0awMmAZRkXBE9Q1b7kHDUV8SpohB+LnwsOP6fixPYTkITNqJLUKDnfWhWQXrAM6aIyqXciwzYxcNK6CpT/rj51ezkCAtzwTA+4QIyJaC2Mu1zNXCvBhnNj0tdeN5ljkR4WLgsea7q2YqobGguGX6+gkt1o5G38cvlf1PNtHpTPMcLiEe+qtIk3MwTjiyXpk6ZO/Ht+waupCPxlrYlGByqVektYLmk4Xu/Ql3ynYavQxD67cRcIid9IjwRL+YKrJ4uIfML5q0j5iOMCazIDto=;5:TgvUSCU6LiapBQzKexy7CLQHx1+esSpjPS5zNUkIiVB5qgi+HeFYRNLYnBSZ6Xp7bNgOGqdQDkhyAY6pnKW6qZvrrYAOlY3v7jx2xXjKlkNnXUu9l7Mh8PnuFwZvUNLzwM9AppfaLA2gBndJZ7RTOGpf89NA6lXHXku5uti9pwE=;7:WjDfTIoeRiPuSAAZM8o1CldjLyj+T68gmfjH6gCxwQdxduhQefG+l6+APfnABZxrTpEsL2fSV5aDoTt01Dbx2xnTsx/XdOxJ0zGVkSrRQbBa8PmUn/8LrNwbsjilhSBzpqf4mS7516RtbfXbdMEJoQ== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;SN1PR07MB2175;20:d6pOhmIgXVdn2tm8MguAkItku6XBTzmJDyAo05H8P3A9Tvq3qRplVX6yh4VhosAcqwNlE3dywMPy5EKUhCrNBBjt+QeH4EgWBdtq0pTmpRcs8soa0SxtQX3CNqFX3/U38aTIKon7n1H21TCSer/42mPi5ZVUtq41qHATeB0kzg71BafYsq30504/sdCBw2d96ztL/83P+DawIvv1Qbrp5iq5OK1A8LVN1X2FE4Xl4EPsoJLrS7C5jxvA6RM85EHx X-OriginatorOrg: cadence.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Dec 2018 12:40:26.0174 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 5b6c35b2-0e95-4d23-b940-08d65e9ca930 X-MS-Exchange-CrossTenant-Id: d36035c5-6ce6-4662-a3dc-e762e61ae4c9 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=d36035c5-6ce6-4662-a3dc-e762e61ae4c9;Ip=[199.43.4.28];Helo=[rmmaillnx1.cadence.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1PR07MB2175 X-Proofpoint-SPF-Result: pass X-Proofpoint-SPF-Record: v=spf1 include:_spf.salesforce.com include:mktomail.com include:spf-0014ca01.pphosted.com include:spf.protection.outlook.com include:auth.msgapp.com include:spf.mandrillapp.com ~all X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2018-12-10_04:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_check_notspam policy=outbound_check score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1812100116 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch introduce new Cadence USBSS DRD driver to linux kernel. The Cadence USBSS DRD Driver is a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. The current driver has been validated with FPGA burned. We have support for PCIe bus, which is used on FPGA prototyping. The host side of USBSS-DRD controller is compliance with XHCI specification, so it works with standard XHCI linux driver. Signed-off-by: Pawel Laszczak --- drivers/usb/Kconfig | 2 + drivers/usb/Makefile | 2 + drivers/usb/cdns3/Kconfig | 44 + drivers/usb/cdns3/Makefile | 16 + drivers/usb/cdns3/cdns3-pci-wrap.c | 157 +++ drivers/usb/cdns3/core.c | 451 +++++++ drivers/usb/cdns3/core.h | 108 ++ drivers/usb/cdns3/debug.h | 346 ++++++ drivers/usb/cdns3/debugfs.c | 168 +++ drivers/usb/cdns3/drd.c | 315 +++++ drivers/usb/cdns3/drd.h | 129 ++ drivers/usb/cdns3/ep0.c | 864 +++++++++++++ drivers/usb/cdns3/gadget-export.h | 28 + drivers/usb/cdns3/gadget.c | 1802 ++++++++++++++++++++++++++++ drivers/usb/cdns3/gadget.h | 1177 ++++++++++++++++++ drivers/usb/cdns3/host-export.h | 28 + drivers/usb/cdns3/host.c | 74 ++ drivers/usb/cdns3/trace.c | 11 + drivers/usb/cdns3/trace.h | 343 ++++++ 19 files changed, 6065 insertions(+) create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/debug.h create mode 100644 drivers/usb/cdns3/debugfs.c create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/gadget.h create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c create mode 100644 drivers/usb/cdns3/trace.c create mode 100644 drivers/usb/cdns3/trace.h diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 987fc5ba6321..5f9334019d04 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" endif +source "drivers/usb/cdns3/Kconfig" + source "drivers/usb/mtu3/Kconfig" source "drivers/usb/musb/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 7d1b8c82b208..ab125b966cac 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_ISP1760) += isp1760/ +obj-$(CONFIG_USB_CDNS3) += cdns3/ + obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MTU3) += mtu3/ diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig new file mode 100644 index 000000000000..4adfd87811e8 --- /dev/null +++ b/drivers/usb/cdns3/Kconfig @@ -0,0 +1,44 @@ +config USB_CDNS3 + tristate "Cadence USB3 Dual-Role Controller" + depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA + help + Say Y here if your system has a cadence USB3 dual-role controller. + It supports: dual-role switch, Host-only, and Peripheral-only. + + If you choose to build this driver is a dynamically linked + module, the module will be called cdns3.ko. + +if USB_CDNS3 + +config USB_CDNS3_GADGET + bool "Cadence USB3 device controller" + depends on USB_GADGET + help + Say Y here to enable device controller functionality of the + cadence USBSS-DEV driver. + + This controller supports FF, HS and SS mode. It doesn't support + LS and SSP mode + +config USB_CDNS3_HOST + bool "Cadence USB3 host controller" + depends on USB_XHCI_HCD + help + Say Y here to enable host controller functionality of the + cadence driver. + + Host controller is compliance with XHCI so it will use + standard XHCI driver. + +config USB_CDNS3_PCI_WRAP + tristate "Cadence USB3 support on PCIe-based platforms" + depends on USB_PCI && ACPI + default USB_CDNS3 + help + If you're using the USBSS Core IP with a PCIe, please say + 'Y' or 'M' here. + + If you choose to build this driver as module it will + be dynamically linked and module will be called cdns3-pci.ko + +endif diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile new file mode 100644 index 000000000000..3f63baa24294 --- /dev/null +++ b/drivers/usb/cdns3/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# define_trace.h needs to know how to find our header +CFLAGS_trace.o := -I$(src) + +obj-$(CONFIG_USB_CDNS3) += cdns3.o +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o + +cdns3-y := core.o drd.o trace.o + +ifneq ($(CONFIG_DEBUG_FS),) + cdns3-y += debugfs.o +endif + +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o +cdns3-pci-y := cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c new file mode 100644 index 000000000000..e93179c45ece --- /dev/null +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS PCI Glue driver + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +struct cdns3_wrap { + struct platform_device *plat_dev; + struct pci_dev *hg_dev; + struct resource dev_res[4]; +}; + +struct cdns3_wrap wrap; + +#define RES_IRQ_ID 0 +#define RES_HOST_ID 1 +#define RES_DEV_ID 2 +#define RES_DRD_ID 3 + +#define PCI_BAR_HOST 0 +#define PCI_BAR_DEV 2 +#define PCI_BAR_OTG 4 + +#define PCI_DEV_FN_HOST_DEVICE 0 +#define PCI_DEV_FN_OTG 1 + +#define PCI_DRIVER_NAME "cdns3-pci-usbss" +#define PLAT_DRIVER_NAME "cdns-usb3" + +#define CDNS_VENDOR_ID 0x17cd +#define CDNS_DEVICE_ID 0x0100 + +/** + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver + * @pdev: platform device object + * @id: pci device id + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct platform_device_info plat_info; + struct cdns3_wrap *wrap; + struct resource *res; + int err; + + /* + * for GADGET/HOST PCI (devfn) function number is 0, + * for OTG PCI (devfn) function number is 1 + */ + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) + return -EINVAL; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); + return err; + } + + pci_set_master(pdev); + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); + if (!wrap) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + /* function 0: host(BAR_0) + device(BAR_1) + otg(BAR_2)). */ + memset(wrap->dev_res, 0x00, + sizeof(struct resource) * ARRAY_SIZE(wrap->dev_res)); + dev_dbg(&pdev->dev, "Initialize Device resources\n"); + res = wrap->dev_res; + + res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV); + res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV); + res[RES_DEV_ID].name = "cdns3-dev-regs"; + res[RES_DEV_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n", + &res[RES_DEV_ID].start); + + res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST); + res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST); + res[RES_HOST_ID].name = "cdns3-xhci-regs"; + res[RES_HOST_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n", + &res[RES_HOST_ID].start); + + res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG); + res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG); + res[RES_DRD_ID].name = "cdns3-otg"; + res[RES_DRD_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n", + &res[RES_DRD_ID].start); + + /* Interrupt common for both device and XHCI */ + wrap->dev_res[RES_IRQ_ID].start = pdev->irq; + wrap->dev_res[RES_IRQ_ID].name = "cdns3-irq"; + wrap->dev_res[RES_IRQ_ID].flags = IORESOURCE_IRQ; + + /* set up platform device info */ + memset(&plat_info, 0, sizeof(plat_info)); + plat_info.parent = &pdev->dev; + plat_info.fwnode = pdev->dev.fwnode; + plat_info.name = PLAT_DRIVER_NAME; + plat_info.id = pdev->devfn; + plat_info.res = wrap->dev_res; + plat_info.num_res = ARRAY_SIZE(wrap->dev_res); + plat_info.dma_mask = pdev->dma_mask; + + /* register platform device */ + wrap->plat_dev = platform_device_register_full(&plat_info); + if (IS_ERR(wrap->plat_dev)) { + err = PTR_ERR(wrap->plat_dev); + return err; + } + + pci_set_drvdata(pdev, wrap); + + return err; +} + +void cdns3_pci_remove(struct pci_dev *pdev) +{ + struct cdns3_wrap *wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev); + + platform_device_unregister(wrap->plat_dev); +} + +static const struct pci_device_id cdns3_pci_ids[] = { + { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, + { 0, } +}; + +static struct pci_driver cdns3_pci_driver = { + .name = PCI_DRIVER_NAME, + .id_table = cdns3_pci_ids, + .probe = cdns3_pci_probe, + .remove = cdns3_pci_remove, +}; + +module_pci_driver(cdns3_pci_driver); +MODULE_DEVICE_TABLE(pci, cdns3_pci_ids); + +MODULE_AUTHOR("Pawel Laszczak "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr"); + diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c new file mode 100644 index 000000000000..b93e3788bd33 --- /dev/null +++ b/drivers/usb/cdns3/core.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2017-2018 NXP + * + * Author: Peter Chen + * Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +#include "gadget.h" +#include "core.h" +#include "host-export.h" +#include "gadget-export.h" +#include "drd.h" +#include "debug.h" + +static inline +struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) +{ + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); + return cdns->roles[cdns->role]; +} + +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) +{ + int ret; + + if (WARN_ON(role >= CDNS3_ROLE_END)) + return 0; + + if (!cdns->roles[role]) + return -ENXIO; + + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE) + return 0; + + mutex_lock(&cdns->mutex); + cdns->role = role; + ret = cdns->roles[role]->start(cdns); + if (!ret) + cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE; + mutex_unlock(&cdns->mutex); + return ret; +} + +void cdns3_role_stop(struct cdns3 *cdns) +{ + enum cdns3_roles role = cdns->role; + + if (role >= CDNS3_ROLE_END) { + WARN_ON(role > CDNS3_ROLE_END); + return; + } + + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE) + return; + + mutex_lock(&cdns->mutex); + cdns->roles[role]->stop(cdns); + cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE; + mutex_unlock(&cdns->mutex); +} + +/* + * cdns->role gets from cdns3_get_initial_role, and this API tells role at the + * runtime. + * If both roles are supported, the role is selected based on vbus/id. + * It could be read from OTG register or external connector. + * If only single role is supported, only one role structure + * is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET]. + */ +static enum cdns3_roles cdns3_get_initial_role(struct cdns3 *cdns) +{ + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { + if (cdns3_is_host(cdns)) + return CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + return CDNS3_ROLE_GADGET; + } + return cdns->roles[CDNS3_ROLE_HOST] + ? CDNS3_ROLE_HOST + : CDNS3_ROLE_GADGET; +} + +static void cdns3_exit_roles(struct cdns3 *cdns) +{ + cdns3_role_stop(cdns); + cdns3_drd_exit(cdns); +} + +/** + * cdns3_core_init_role - initialize role of operation + * @cdns: Pointer to cdns3 structure + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_core_init_role(struct cdns3 *cdns) +{ + struct device *dev = cdns->dev; + enum usb_dr_mode best_dr_mode; + enum usb_dr_mode dr_mode; + int ret = 0; + + dr_mode = usb_get_dr_mode(dev); + cdns->role = CDNS3_ROLE_END; + + /* + * If driver can't read mode by means of usb_get_dr_mdoe function then + * chooses mode according with Kernel configuration. This setting + * can be restricted later depending on strap pin configuration. + */ + if (dr_mode == USB_DR_MODE_UNKNOWN) { + if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && + IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_OTG; + else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + dr_mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_PERIPHERAL; + } + + best_dr_mode = USB_DR_MODE_OTG; + + if (dr_mode == USB_DR_MODE_OTG) { + best_dr_mode = cdns->dr_mode; + } else if (cdns->dr_mode == USB_DR_MODE_OTG) { + best_dr_mode = dr_mode; + } else if (cdns->dr_mode != dr_mode) { + dev_err(dev, "Incorrect DRD configuration\n"); + return -EINVAL; + } + + dr_mode = best_dr_mode; + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { + ret = cdns3_host_init(cdns); + if (ret) { + dev_err(dev, "Host initialization failed with %d\n", + ret); + goto err; + } + } + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { + ret = cdns3_gadget_init(cdns); + if (ret) { + dev_err(dev, "Device initialization failed with %d\n", + ret); + goto err; + } + } + + cdns->desired_dr_mode = dr_mode; + cdns->dr_mode = dr_mode; + /* + * dr_mode could be change so DRD must update controller + * configuration + */ + ret = cdns3_drd_update_mode(cdns); + + cdns->role = cdns3_get_initial_role(cdns); + + ret = cdns3_role_start(cdns, cdns->role); + if (ret) { + dev_err(dev, "can't start %s role\n", + cdns3_get_current_role_driver(cdns)->name); + goto err; + } + + return ret; +err: + cdns3_exit_roles(cdns); + return ret; +} + +/** + * cdsn3_get_real_role - get real role of controller based on hardware settings. + * @cdns: Pointer to cdns3 structure + * + * Returns role + */ +enum cdns3_roles cdsn3_get_real_role(struct cdns3 *cdns) +{ + enum cdns3_roles role = CDNS3_ROLE_END; + + if (cdns->current_dr_mode == USB_DR_MODE_OTG) { + if (cdns3_get_id(cdns)) + role = CDNS3_ROLE_GADGET; + else + role = CDNS3_ROLE_HOST; + } else { + if (cdns3_is_host(cdns)) + role = CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + role = CDNS3_ROLE_GADGET; + } + + return role; +} + +/** + * cdns3_role_switch - work queue handler for role switch + * + * @work: work queue item structure + * + * Handles below events: + * - Role switch for dual-role devices + * - CDNS3_ROLE_GADGET <--> CDNS3_ROLE_END for peripheral-only devices + */ +static void cdns3_role_switch(struct work_struct *work) +{ + enum cdns3_roles role = CDNS3_ROLE_END; + struct cdns3_role_driver *role_drv; + enum cdns3_roles current_role; + struct cdns3 *cdns; + int ret = 0; + + cdns = container_of(work, struct cdns3, role_switch_wq); + + /* During switching cdns->role can be different then role */ + role = cdsn3_get_real_role(cdns); + + role_drv = cdns3_get_current_role_driver(cdns); + + pm_runtime_get_sync(cdns->dev); + + /* Disable current role. This state can be forced from user space. */ + if (cdns->debug_disable && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) { + cdns3_role_stop(cdns); + goto exit; + } + + /* Do nothing if nothing changed */ + if (cdns->role == role && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) + goto exit; + + cdns3_role_stop(cdns); + + role = cdsn3_get_real_role(cdns); + + current_role = cdns->role; + dev_dbg(cdns->dev, "Switching role"); + + ret = cdns3_role_start(cdns, role); + + if (ret) { + /* Back to current role */ + dev_err(cdns->dev, "set %d has failed, back to %d\n", + role, current_role); + cdns3_role_start(cdns, current_role); + } +exit: + pm_runtime_put_sync(cdns->dev); +} + +/** + * cdns3_probe - probe for cdns3 core device + * @pdev: Pointer to cdns3 core platform device + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct cdns3 *cdns; + void __iomem *regs; + int ret; + + cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); + if (!cdns) + return -ENOMEM; + + cdns->dev = dev; + + platform_set_drvdata(pdev, cdns); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + cdns->irq = res->start; + + cdns->xhci_res[0] = *res; + + /* + * Request memory region + * region-0: xHCI + * region-1: Peripheral + * region-2: OTG registers + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cdns->xhci_res[1] = *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + cdns->dev_regs = regs; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + cdns->otg_regs = regs; + + mutex_init(&cdns->mutex); + + cdns->phy = devm_phy_get(dev, "cdns3,usbphy"); + if (IS_ERR(cdns->phy)) { + ret = PTR_ERR(cdns->phy); + if (ret == -ENOSYS || ret == -ENODEV) { + cdns->phy = NULL; + } else if (ret == -EPROBE_DEFER) { + return ret; + } else { + dev_err(dev, "no phy found\n"); + goto err0; + } + } + + phy_init(cdns->phy); + + INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch); + + ret = cdns3_drd_init(cdns); + if (ret) + goto err1; + + ret = cdns3_core_init_role(cdns); + if (ret) + goto err1; + + cdns3_debugfs_init(cdns); + device_set_wakeup_capable(dev, true); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + /* + * The controller needs less time between bus and controller suspend, + * and we also needs a small delay to avoid frequently entering low + * power mode. + */ + pm_runtime_set_autosuspend_delay(dev, 20); + pm_runtime_mark_last_busy(dev); + pm_runtime_use_autosuspend(dev); + dev_dbg(dev, "Cadence USB3 core: probe succeed\n"); + + return 0; + +err1: + phy_exit(cdns->phy); +err0: + return ret; +} + +/** + * cdns3_remove - unbind drd driver and clean up + * @pdev: Pointer to Linux platform device + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_remove(struct platform_device *pdev) +{ + struct cdns3 *cdns = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + cdns3_debugfs_exit(cdns); + cdns3_exit_roles(cdns); + phy_exit(cdns->phy); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id of_cdns3_match[] = { + { .compatible = "cdns,usb3" }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_cdns3_match); +#endif + +#ifdef CONFIG_PM + +#ifdef CONFIG_PM_SLEEP +static int cdns3_suspend(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} + +static int cdns3_resume(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ +static int cdns3_runtime_suspend(struct device *dev) +{ /* TODO: Implements this function. */ + return 0; +} + +static int cdns3_runtime_resume(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops cdns3_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cdns3_suspend, cdns3_resume) + SET_RUNTIME_PM_OPS(cdns3_runtime_suspend, cdns3_runtime_resume, NULL) +}; + +static struct platform_driver cdns3_driver = { + .probe = cdns3_probe, + .remove = cdns3_remove, + .driver = { + .name = "cdns-usb3", + .of_match_table = of_match_ptr(of_cdns3_match), + .pm = &cdns3_pm_ops, + }, +}; + +static int __init cdns3_driver_platform_register(void) +{ + return platform_driver_register(&cdns3_driver); +} +module_init(cdns3_driver_platform_register); + +static void __exit cdns3_driver_platform_unregister(void) +{ + platform_driver_unregister(&cdns3_driver); +} +module_exit(cdns3_driver_platform_unregister); + +MODULE_ALIAS("platform:cdns3"); +MODULE_AUTHOR("Pawel Laszczak "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h new file mode 100644 index 000000000000..ffd1971ff893 --- /dev/null +++ b/drivers/usb/cdns3/core.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Header File. + * + * Copyright (C) 2017-2018 NXP + * Copyright (C) 2018 Cadence. + * + * Authors: Peter Chen + * Pawel Laszczak + */ +#include + +#ifndef __LINUX_CDNS3_CORE_H +#define __LINUX_CDNS3_CORE_H + +struct cdns3; +enum cdns3_roles { + CDNS3_ROLE_HOST = 0, + CDNS3_ROLE_GADGET, + CDNS3_ROLE_END, +}; + +/** + * struct cdns3_role_driver - host/gadget role driver + * @start: start this role + * @stop: stop this role + * @suspend: suspend callback for this role + * @resume: resume callback for this role + * @irq: irq handler for this role + * @name: role name string (host/gadget) + * @state: current state + */ +struct cdns3_role_driver { + int (*start)(struct cdns3 *cdns); + void (*stop)(struct cdns3 *cdns); + int (*suspend)(struct cdns3 *cdns, bool do_wakeup); + int (*resume)(struct cdns3 *cdns, bool hibernated); + const char *name; +#define CDNS3_ROLE_STATE_INACTIVE 0 +#define CDNS3_ROLE_STATE_ACTIVE 1 + int state; +}; + +#define CDNS3_XHCI_RESOURCES_NUM 2 +/** + * struct cdns3 - Representation of Cadence USB3 DRD controller. + * @dev: pointer to Cadence device struct + * @xhci_regs: pointer to base of xhci registers + * @xhci_res: the resource for xhci + * @dev_regs: pointer to base of dev registers + * @otg_regs: pointer to base of otg registers + * @irq: irq number for controller + * @roles: array of supported roles for this controller + * @role: current role + * @host_dev: the child host device pointer for cdns3 core + * @gadget_dev: the child gadget device pointer for cdns3 core + * @usb: phy for this controller + * @role_switch_wq: work queue item for role switch + * @in_lpm: the controller in low power mode + * @wakeup_int: the wakeup interrupt + * @mutex: the mutex for concurrent code at driver + * @dr_mode: supported mode of operation it can be only Host, only Device + * or OTG mode that allow to switch between Device and Host mode. + * This field based on firmware setting, kernel configuration + * and hardware configuration. + * @current_dr_mode: current mode of operation when in dual-role mode + * @desired_dr_mode: desired mode of operation when in dual-role mode. + * This value can be changed during runtime. + * Available options depends on dr_mode: + * dr_mode | desired_dr_mode and current_dr_mode + * ---------------------------------------------------------------- + * USB_DR_MODE_HOST | only USB_DR_MODE_HOST + * USB_DR_MODE_PERIPHERAL | only USB_DR_MODE_PERIPHERAL + * USB_DR_MODE_OTG | only USB_DR_MODE_HOST + * USB_DR_MODE_OTG | only USB_DR_MODE_PERIPHERAL + * USB_DR_MODE_OTG | USB_DR_MODE_OTG + * + * Desired_dr_role can be changed by means of debugfs. + * @root: debugfs root folder pointer + * @debug_disable: + */ +struct cdns3 { + struct device *dev; + void __iomem *xhci_regs; + struct resource xhci_res[CDNS3_XHCI_RESOURCES_NUM]; + struct cdns3_usb_regs __iomem *dev_regs; + struct cdns3_otg_regs *otg_regs; + int irq; + struct cdns3_role_driver *roles[CDNS3_ROLE_END]; + enum cdns3_roles role; + struct platform_device *host_dev; + struct cdns3_device *gadget_dev; + struct phy *phy; + struct work_struct role_switch_wq; + int in_lpm:1; + int wakeup_int:1; + /* mutext used in workqueue*/ + struct mutex mutex; + enum usb_dr_mode dr_mode; + enum usb_dr_mode current_dr_mode; + enum usb_dr_mode desired_dr_mode; + struct dentry *root; + int debug_disable:1; +}; + +void cdns3_role_stop(struct cdns3 *cdns); + +#endif /* __LINUX_CDNS3_CORE_H */ diff --git a/drivers/usb/cdns3/debug.h b/drivers/usb/cdns3/debug.h new file mode 100644 index 000000000000..afb81d224718 --- /dev/null +++ b/drivers/usb/cdns3/debug.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver. + * Debug header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ +#ifndef __LINUX_CDNS3_DEBUG +#define __LINUX_CDNS3_DEBUG +#include "gadget.h" + +static inline void cdns3_decode_get_status(u8 bRequestType, u16 wIndex, + u16 wLength, char *str) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + sprintf(str, "Get Interface Status Intf = %d, L: = %d", + wIndex, wLength); + break; + case USB_RECIP_ENDPOINT: + sprintf(str, "Get Endpoint Status ep%d%s", + wIndex & ~USB_DIR_IN, + wIndex & USB_DIR_IN ? "in" : "out"); + break; + } +} + +static inline const char *cdns3_decode_device_feature(u16 wValue) +{ + switch (wValue) { + case USB_DEVICE_SELF_POWERED: + return "Self Powered"; + case USB_DEVICE_REMOTE_WAKEUP: + return "Remote Wakeup"; + case USB_DEVICE_TEST_MODE: + return "Test Mode"; + case USB_DEVICE_U1_ENABLE: + return "U1 Enable"; + case USB_DEVICE_U2_ENABLE: + return "U2 Enable"; + case USB_DEVICE_LTM_ENABLE: + return "LTM Enable"; + default: + return "UNKNOWN"; + } +} + +static inline const char *cdns3_decode_test_mode(u16 wIndex) +{ + switch (wIndex) { + case TEST_J: + return ": TEST_J"; + case TEST_K: + return ": TEST_K"; + case TEST_SE0_NAK: + return ": TEST_SE0_NAK"; + case TEST_PACKET: + return ": TEST_PACKET"; + case TEST_FORCE_EN: + return ": TEST_FORCE_EN"; + default: + return ": UNKNOWN"; + } +} + +static inline void cdns3_decode_set_clear_feature(u8 bRequestType, u8 bRequest, + u16 wValue, u16 wIndex, + char *str) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + sprintf(str, "%s Device Feature(%s%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + cdns3_decode_device_feature(wValue), + wValue == USB_DEVICE_TEST_MODE ? + cdns3_decode_test_mode(wIndex) : ""); + break; + case USB_RECIP_INTERFACE: + sprintf(str, "%s Interface Feature(%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + wIndex == USB_INTRF_FUNC_SUSPEND ? + "Function Suspend" : "UNKNOWN"); + break; + case USB_RECIP_ENDPOINT: + sprintf(str, "%s Endpoint Feature(%s ep%d%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + wIndex == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", + wIndex & ~USB_DIR_IN, + wIndex & USB_DIR_IN ? "in" : "out"); + break; + } +} + +static inline const char *cdns3_decode_descriptor(u16 wValue) +{ + switch (wValue >> 8) { + case USB_DT_DEVICE: + return "Device"; + case USB_DT_CONFIG: + return "Configuration"; + case USB_DT_STRING: + return "String"; + case USB_DT_INTERFACE: + return "Interface"; + case USB_DT_ENDPOINT: + return "Endpoint"; + case USB_DT_DEVICE_QUALIFIER: + return "Device Qualifier"; + case USB_DT_OTHER_SPEED_CONFIG: + return "Other Speed Config"; + case USB_DT_INTERFACE_POWER: + return "Interface Power"; + case USB_DT_OTG: + return "OTG"; + case USB_DT_DEBUG: + return "Debug"; + case USB_DT_INTERFACE_ASSOCIATION: + return "Interface Association"; + case USB_DT_BOS: + return "BOS"; + case USB_DT_DEVICE_CAPABILITY: + return "Device Capability"; + case USB_DT_SS_ENDPOINT_COMP: + return "SS Endpoint Companion"; + case USB_DT_SSP_ISOC_ENDPOINT_COMP: + return "SSP Isochronous Endpoint Companion"; + default: + return "UNKNOWN"; + } +} + +/** + * cdns3_decode_ctrl - returns a string represetion of ctrl request + */ +static inline const char *cdns3_decode_ctrl(char *str, u8 bRequestType, + u8 bRequest, u16 wValue, + u16 wIndex, u16 wLength) +{ + switch (bRequest) { + case USB_REQ_GET_STATUS: + cdns3_decode_get_status(bRequestType, wIndex, + wLength, str); + break; + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + cdns3_decode_set_clear_feature(bRequestType, bRequest, + wValue, wIndex, str); + break; + case USB_REQ_SET_ADDRESS: + sprintf(str, "Set Address Addr: %02x", wValue); + break; + case USB_REQ_GET_DESCRIPTOR: + sprintf(str, "GET %s Descriptor I: %d, L: %d", + cdns3_decode_descriptor(wValue), + wValue & 0xff, wLength); + break; + case USB_REQ_SET_DESCRIPTOR: + sprintf(str, "SET %s Descriptor I: %d, L: %d", + cdns3_decode_descriptor(wValue), + wValue & 0xff, wLength); + break; + case USB_REQ_GET_CONFIGURATION: + sprintf(str, "Get Configuration L: %d", wLength); + break; + case USB_REQ_SET_CONFIGURATION: + sprintf(str, "Set Configuration Config: %d ", wValue); + break; + case USB_REQ_GET_INTERFACE: + sprintf(str, "Get Interface Intf: %d, L: %d", wIndex, wLength); + break; + case USB_REQ_SET_INTERFACE: + sprintf(str, "Set Interface Intf: %d, Alt: %d", wIndex, wValue); + break; + case USB_REQ_SYNCH_FRAME: + sprintf(str, "Synch Frame Ep: %d, L: %d", wIndex, wLength); + break; + case USB_REQ_SET_SEL: + sprintf(str, "Set SEL L: %d", wLength); + break; + case USB_REQ_SET_ISOCH_DELAY: + sprintf(str, "Set Isochronous Delay Delay: %d ns", wValue); + break; + default: + sprintf(str, + "SETUP BRT: %02x BR: %02x V: %04x I: %04x L: %04x\n", + bRequestType, bRequest, + wValue, wIndex, wLength); + } + + return str; +} + +static inline char *cdns3_decode_usb_irq(struct cdns3_device *priv_dev, + u32 usb_ists) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ %08x = ", usb_ists); + + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { + u32 speed = cdns3_get_speed(priv_dev); + + ret += sprintf(str + ret, "Connection %s\n", + usb_speed_string(speed)); + } + if (usb_ists & USB_ISTS_CON2I || usb_ists & USB_ISTS_CONI) + ret += sprintf(str + ret, "Disconnection "); + if (usb_ists & USB_ISTS_L2ENTI) + ret += sprintf(str + ret, "suspended "); + + if (usb_ists & USB_ISTS_L2EXTI) + ret += sprintf(str + ret, "L2 exit "); + if (usb_ists & USB_ISTS_U3EXTI) + ret += sprintf(str + ret, "U3 exit "); + if (usb_ists & USB_ISTS_UWRESI) + ret += sprintf(str + ret, "Warm Reset "); + if (usb_ists & USB_ISTS_UHRESI) + ret += sprintf(str + ret, "Hot Reset "); + if (usb_ists & USB_ISTS_U2RESI) + ret += sprintf(str + ret, "Reset"); + + return str; +} + +static inline char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); + + if (ep_sts & EP_STS_SETUP) + ret += sprintf(str + ret, "SETUP "); + if (ep_sts & EP_STS_IOC) + ret += sprintf(str + ret, "IOC "); + if (ep_sts & EP_STS_ISP) + ret += sprintf(str + ret, "ISP "); + if (ep_sts & EP_STS_DESCMIS) + ret += sprintf(str + ret, "DESCMIS "); + if (ep_sts & EP_STS_STREAMR) + ret += sprintf(str + ret, "STREAMR "); + if (ep_sts & EP_STS_MD_EXIT) + ret += sprintf(str + ret, "MD_EXIT "); + if (ep_sts & EP_STS_TRBERR) + ret += sprintf(str + ret, "TRBERR "); + if (ep_sts & EP_STS_NRDY) + ret += sprintf(str + ret, "NRDY "); + if (ep_sts & EP_STS_PRIME) + ret += sprintf(str + ret, "PRIME "); + if (ep_sts & EP_STS_SIDERR) + ret += sprintf(str + ret, "SIDERRT "); + if (ep_sts & EP_STS_OUTSMM) + ret += sprintf(str + ret, "OUTSMM "); + if (ep_sts & EP_STS_ISOERR) + ret += sprintf(str + ret, "ISOERR "); + if (ep_sts & EP_STS_IOT) + ret += sprintf(str + ret, "IOT "); + + return str; +} + +static inline char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + priv_ep->name); +} + +static inline char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev) +{ + if (priv_dev->ep0_data_dir) + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0IN"); + else + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0OUT"); +} + +/** + * Debug a transfer ring. + * + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. + *. + */ +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, + int free_trbs, u8 pcs, u8 ccs, + int enqueue, int dequeue, + struct cdns3_trb *ring, char *str) +{ + u64 addr = priv_ep->trb_pool_dma; + struct cdns3_trb *trb; + int ret = 0; + int i; + + trb = &ring[priv_ep->dequeue]; + ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name); + + ret += sprintf(str + ret, + "\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n", + dequeue, trb, + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); + + trb = &ring[priv_ep->enqueue]; + ret += sprintf(str + ret, + "\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n", + enqueue, trb, + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); + + ret += sprintf(str + ret, + "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", free_trbs, ccs, + pcs); + + if (TRBS_PER_SEGMENT > 64) { + sprintf(str + ret, "\t\tTo big transfer ring %d\n", + TRBS_PER_SEGMENT); + return str; + } + + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &ring[i]; + ret += sprintf(str + ret, + "\t\t@%016llx %08x %08x %08x\n", addr, + le32_to_cpu(trb->buffer), + le32_to_cpu(trb->length), + le32_to_cpu(trb->control)); + addr += sizeof(*trb); + } + + return str; +} + +#ifdef CONFIG_DEBUG_FS +void cdns3_debugfs_init(struct cdns3 *cdns); +void cdns3_debugfs_exit(struct cdns3 *cdns); +#else +void cdns3_debugfs_init(struct cdns3 *cdns); +{ } +void cdns3_debugfs_exit(struct cdns3 *cdns); +{ } +#endif + +#endif /*__LINUX_CDNS3_DEBUG*/ diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c new file mode 100644 index 000000000000..d7919f5c1d90 --- /dev/null +++ b/drivers/usb/cdns3/debugfs.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Controller DebugFS filer. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include + +#include "core.h" +#include "gadget.h" +#include "drd.h" + +static int cdns3_mode_show(struct seq_file *s, void *unused) +{ + struct cdns3 *cdns = s->private; + + switch (cdns->current_dr_mode) { + case USB_DR_MODE_HOST: + seq_puts(s, "host\n"); + break; + case USB_DR_MODE_PERIPHERAL: + seq_puts(s, "device\n"); + break; + case USB_DR_MODE_OTG: + seq_puts(s, "otg\n"); + break; + default: + seq_puts(s, "UNKNOWN mode\n"); + } + + return 0; +} + +static int cdns3_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_mode_show, inode->i_private); +} + +static ssize_t cdns3_mode_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3 *cdns = s->private; + u32 mode = USB_DR_MODE_UNKNOWN; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "host", 4)) { + if (cdns->dr_mode == USB_DR_MODE_HOST || + cdns->dr_mode == USB_DR_MODE_OTG) { + mode = USB_DR_MODE_HOST; + } + } + + if (!strncmp(buf, "device", 6)) + if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL || + cdns->dr_mode == USB_DR_MODE_OTG) + mode = USB_DR_MODE_PERIPHERAL; + + if (!strncmp(buf, "otg", 3) && cdns->dr_mode == USB_DR_MODE_OTG) + mode = USB_DR_MODE_OTG; + + if (mode == USB_DR_MODE_UNKNOWN) { + dev_err(cdns->dev, "Failed: incorrect mode setting\n"); + return -EFAULT; + } + + if (cdns->current_dr_mode != mode) { + cdns->desired_dr_mode = mode; + cdns->debug_disable = 0; + cdns3_role_stop(cdns); + cdns3_drd_update_mode(cdns); + queue_work(system_freezable_wq, &cdns->role_switch_wq); + } + + return count; +} + +static const struct file_operations cdns3_mode_fops = { + .open = cdns3_mode_open, + .write = cdns3_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int cdns3_disable_show(struct seq_file *s, void *unused) +{ + struct cdns3 *cdns = s->private; + + if (!cdns->debug_disable) + seq_puts(s, "0\n"); + else + seq_puts(s, "1\n"); + + return 0; +} + +static ssize_t cdns3_disable_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3 *cdns = s->private; + int disable; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1) || !strncmp(buf, "yes", 3)) { + disable = 1; + } else if (!strncmp(buf, "0", 1) || !strncmp(buf, "no", 2)) { + disable = 0; + } else { + dev_err(cdns->dev, "Failed: incorrect disable setting\n"); + return -EFAULT; + } + + if (disable != cdns->debug_disable) { + cdns->debug_disable = disable; + queue_work(system_freezable_wq, &cdns->role_switch_wq); + } + + return count; +} + +static int cdns3_disable_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_disable_show, inode->i_private); +} + +static const struct file_operations cdns3_disable_fops = { + .open = cdns3_disable_open, + .write = cdns3_disable_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void cdns3_debugfs_init(struct cdns3 *cdns) +{ + struct dentry *root; + + root = debugfs_create_dir(dev_name(cdns->dev), NULL); + cdns->root = root; + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + debugfs_create_file("mode", 0644, root, cdns, + &cdns3_mode_fops); + + debugfs_create_file("disable", 0644, root, cdns, + &cdns3_disable_fops); +} + +void cdns3_debugfs_exit(struct cdns3 *cdns) +{ + debugfs_remove_recursive(cdns->root); +} diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c new file mode 100644 index 000000000000..45573427ba83 --- /dev/null +++ b/drivers/usb/cdns3/drd.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak +#include +#include +#include + +#include "gadget.h" +#include "drd.h" +#include "core.h" + +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on); + +/** + * cdns3_set_mode - change mode of OTG Core + * @cdns: pointer to context structure + * @mode: selected mode from cdns_role + */ +void cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) +{ + u32 reg; + + cdns->current_dr_mode = mode; + + switch (mode) { + case USB_DR_MODE_PERIPHERAL: + dev_info(cdns->dev, "Set controller to Gadget mode\n"); + cdns3_drd_switch_gadget(cdns, 1); + break; + case USB_DR_MODE_HOST: + dev_info(cdns->dev, "Set controller to Host mode\n"); + cdns3_drd_switch_host(cdns, 1); + break; + case USB_DR_MODE_OTG: + dev_info(cdns->dev, "Set controller to OTG mode\n"); + reg = readl(&cdns->otg_regs->override); + reg |= OVERRIDE_IDPULLUP; + writel(reg, &cdns->otg_regs->override); + + /* + * Hardware specification says: "ID_VALUE must be valid within + * 50ms after idpullup is set to '1" so driver must wait + * 50ms before reading this pin. + */ + usleep_range(50000, 60000); + break; + default: + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; + dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode); + return; + } +} + +int cdns3_get_id(struct cdns3 *cdns) +{ + int id; + + id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE; + dev_dbg(cdns->dev, "OTG ID: %d", id); + return id; +} + +int cdns3_is_host(struct cdns3 *cdns) +{ + if (cdns->current_dr_mode == USB_DR_MODE_HOST) + return 1; + else if (!cdns3_get_id(cdns)) + return 1; + + return 0; +} + +int cdns3_is_device(struct cdns3 *cdns) +{ + if (cdns->current_dr_mode == USB_DR_MODE_PERIPHERAL) + return 1; + else if (cdns->current_dr_mode == USB_DR_MODE_OTG) + if (cdns3_get_id(cdns)) + return 1; + + return 0; +} + +/** + * cdns3_otg_disable_irq - Disable all OTG interrupts + * @cdns: Pointer to controller context structure + */ +static void cdns3_otg_disable_irq(struct cdns3 *cdns) +{ + writel(0, &cdns->otg_regs->ien); +} + +/** + * cdns3_otg_enable_irq - enable id and sess_valid interrupts + * @cdns: Pointer to controller context structure + */ +static void cdns3_otg_enable_irq(struct cdns3 *cdns) +{ + writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT | + OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien); +} + +/** + * cdns3_drd_switch_host - start/stop host + * @cdns: Pointer to controller context structure + * @on: 1 for start, 0 for stop + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on) +{ + int ret; + u32 reg = OTGCMD_OTG_DIS; + + /* switch OTG core */ + if (on) { + writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); + + dev_dbg(cdns->dev, "Waiting for Host mode is turned on\n"); + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_XHCI_READY, + OTGSTS_XHCI_READY, 100000); + + if (ret) + return ret; + } else { + usleep_range(30, 40); + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + } + + return 0; +} + +/** + * cdns3_drd_switch_gadget - start/stop gadget + * @cdns: Pointer to controller context structure + * @on: 1 for start, 0 for stop + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) +{ + int ret; + u32 reg = OTGCMD_OTG_DIS; + + /* switch OTG core */ + if (on) { + writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); + + dev_dbg(cdns->dev, "Waiting for Device mode is turned on\n"); + + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_DEV_READY, + OTGSTS_DEV_READY, 100000); + + if (ret) + return ret; + } else { + /* + * driver should wait at least 10us after disabling Device + * before turning-off Device (DEV_BUS_DROP) + */ + usleep_range(20, 30); + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + } + + return 0; +} + +/** + * cdns3_init_otg_mode - initialize drd controller + * @cdns: Pointer to controller context structure + * + * Returns 0 on success otherwise negative errno + */ +static void cdns3_init_otg_mode(struct cdns3 *cdns) +{ + cdns3_otg_disable_irq(cdns); + /* clear all interrupts */ + writel(~0, &cdns->otg_regs->ivect); + + cdns3_set_mode(cdns, USB_DR_MODE_OTG); + + if (cdns3_is_host(cdns)) + cdns3_drd_switch_host(cdns, 1); + else + cdns3_drd_switch_gadget(cdns, 1); + + cdns3_otg_enable_irq(cdns); +} + +/** + * cdns3_drd_update_mode - initialize mode of operation + * @cdns: Pointer to controller context structure + * + * Returns 0 on success otherwise negative errno + */ +int cdns3_drd_update_mode(struct cdns3 *cdns) +{ + int ret = 0; + + if (cdns->desired_dr_mode == cdns->current_dr_mode) + return ret; + + cdns3_drd_switch_gadget(cdns, 0); + cdns3_drd_switch_host(cdns, 0); + + switch (cdns->desired_dr_mode) { + case USB_DR_MODE_PERIPHERAL: + cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL); + break; + case USB_DR_MODE_HOST: + cdns3_set_mode(cdns, USB_DR_MODE_HOST); + break; + case USB_DR_MODE_OTG: + cdns3_init_otg_mode(cdns); + break; + default: + dev_err(cdns->dev, "Unsupported mode of operation %d\n", + cdns->dr_mode); + return -EINVAL; + } + + return ret; +} + +/** + * cdns3_drd_irq - interrupt handler for OTG events + * + * @irq: irq number for cdns3 core device + * @data: structure of cdns3 + * + * Returns IRQ_HANDLED or IRQ_NONE + */ +static irqreturn_t cdns3_drd_irq(int irq, void *data) +{ + irqreturn_t ret = IRQ_NONE; + struct cdns3 *cdns = data; + u32 reg; + + if (cdns->dr_mode != USB_DR_MODE_OTG) + return ret; + + reg = readl(&cdns->otg_regs->ivect); + if (!reg) + return ret; + + if (reg & OTGIEN_ID_CHANGE_INT) { + dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", + cdns3_get_id(cdns)); + + queue_work(system_freezable_wq, &cdns->role_switch_wq); + + ret = IRQ_HANDLED; + } + + writel(~0, &cdns->otg_regs->ivect); + return ret; +} + +int cdns3_drd_init(struct cdns3 *cdns) +{ + int ret = 0; + u32 state; + + state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts)); + + /* Update dr_mode according to STRAP configuration. */ + cdns->dr_mode = USB_DR_MODE_OTG; + if (state == OTGSTS_STRAP_HOST) { + dev_info(cdns->dev, "Controller strapped to HOST\n"); + cdns->dr_mode = USB_DR_MODE_HOST; + } else if (state == OTGSTS_STRAP_GADGET) { + dev_info(cdns->dev, "Controller strapped to PERIPHERAL\n"); + cdns->dr_mode = USB_DR_MODE_PERIPHERAL; + } + + cdns->desired_dr_mode = cdns->dr_mode; + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; + + ret = devm_request_irq(cdns->dev, cdns->irq, cdns3_drd_irq, IRQF_SHARED, + dev_name(cdns->dev), cdns); + + if (ret) + return ret; + + state = readl(&cdns->otg_regs->sts); + if (OTGSTS_OTG_NRDY(state) != 0) { + dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); + return -ENODEV; + } + + ret = cdns3_drd_update_mode(cdns); + + dev_info(cdns->dev, "Controller Device ID: %08lx, Revision ID: %08lx\n", + CDNS_RID(readl(&cdns->otg_regs->rid)), + CDNS_DID(readl(&cdns->otg_regs->did))); + + return ret; +} + +int cdns3_drd_exit(struct cdns3 *cdns) +{ + return cdns3_drd_switch_host(cdns, 0); +} diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h new file mode 100644 index 000000000000..4159e6e612ac --- /dev/null +++ b/drivers/usb/cdns3/drd.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USB3 DRD header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ +#ifndef __LINUX_CDNS3_DRD +#define __LINUX_CDNS3_DRD + +#include +#include +#include "core.h" + +/* DRD register interface. */ +struct cdns3_otg_regs { + __le32 did; + __le32 rid; + __le32 capabilities; + __le32 reserved1; + __le32 cmd; + __le32 sts; + __le32 state; + __le32 reserved2; + __le32 ien; + __le32 ivect; + __le32 refclk; + __le32 tmr; + __le32 reserved3[4]; + __le32 simulate; + __le32 override; + __le32 susp_ctrl; + __le32 reserved4; + __le32 anasts; + __le32 adp_ramp_time; + __le32 ctrl1; + __le32 ctrl2; +}; + +/* CDNS_RID - bitmasks */ +#define CDNS_RID(p) ((p) & GENMASK(15, 0)) + +/* CDNS_VID - bitmasks */ +#define CDNS_DID(p) ((p) & GENMASK(31, 0)) + +/* OTGCMD - bitmasks */ +/* "Request the bus for Device mode. */ +#define OTGCMD_DEV_BUS_REQ BIT(0) +/* Request the bus for Host mode */ +#define OTGCMD_HOST_BUS_REQ BIT(1) +/* Enable OTG mode. */ +#define OTGCMD_OTG_EN BIT(2) +/* Disable OTG mode */ +#define OTGCMD_OTG_DIS BIT(3) +/*"Configure OTG as A-Device. */ +#define OTGCMD_A_DEV_EN BIT(4) +/*"Configure OTG as A-Device. */ +#define OTGCMD_A_DEV_DIS BIT(5) +/* Drop the bus for Device mod e. */ +#define OTGCMD_DEV_BUS_DROP BIT(8) +/* Drop the bus for Host mode*/ +#define OTGCMD_HOST_BUS_DROP BIT(9) +/* Power Down USBSS-DEV. */ +#define OTGCMD_DEV_POWER_OFF BIT(11) +/* Power Down CDNSXHCI. */ +#define OTGCMD_HOST_POWER_OFF BIT(12) + +/* OTGIEN - bitmasks */ +/* ID change interrupt enable */ +#define OTGIEN_ID_CHANGE_INT BIT(0) +/* Vbusvalid fall detected interrupt enable.*/ +#define OTGIEN_VBUSVALID_RISE_INT BIT(4) +/* Vbusvalid fall detected interrupt enable */ +#define OTGIEN_VBUSVALID_FALL_INT BIT(5) + +/* OTGSTS - bitmasks */ +/* + * Current value of the ID pin. It is only valid when idpullup in + * OTGCTRL1_TYPE register is set to '1'. + */ +#define OTGSTS_ID_VALUE BIT(0) +/* Current value of the vbus_valid */ +#define OTGSTS_VBUS_VALID BIT(1) +/* Current value of the b_sess_vld */ +#define OTGSTS_SESSION_VALID BIT(2) +/*Device mode is active*/ +#define OTGSTS_DEV_ACTIVE BIT(3) +/* Host mode is active. */ +#define OTGSTS_HOST_ACTIVE BIT(4) +/* OTG Controller not ready. */ +#define OTGSTS_OTG_NRDY_MASK BIT(11) +#define OTGSTS_OTG_NRDY(p) ((p) & OTGSTS_OTG_NRDY_MASK) +/* + * Value of the strap pins. + * 000 - no default configuration + * 010 - Controller initiall configured as Host + * 100 - Controller initially configured as Device + */ +#define OTGSTS_STRAP(p) (((p) & GENMASK(14, 12)) >> 12) +#define OTGSTS_STRAP_NO_DEFAULT_CFG 0x00 +#define OTGSTS_STRAP_HOST_OTG 0x01 +#define OTGSTS_STRAP_HOST 0x02 +#define OTGSTS_STRAP_GADGET 0x04 +/* Host mode is turned on. */ +#define OTGSTS_XHCI_READY BIT(26) +/* "Device mode is turned on .*/ +#define OTGSTS_DEV_READY BIT(27) + +/* OTGSTATE- bitmasks */ +#define OTGSTATE_HOST_STATE_MASK GENMASK(5, 3) +#define OTGSTATE_HOST_STATE_IDLE 0x0 +#define OTGSTATE_HOST_STATE_VBUS_FALL 0x7 +#define OTGSTATE_HOST_STATE(p) (((p) & OTGSTATE_HOST_STATE_MASK) >> 3) + +/* OTGREFCLK - bitmasks */ +#define OTGREFCLK_STB_CLK_SWITCH_EN BIT(31) + +/* OVERRIDE - bitmasks */ +#define OVERRIDE_IDPULLUP BIT(0) + +int cdns3_is_host(struct cdns3 *cdns); +int cdns3_is_device(struct cdns3 *cdns); +int cdns3_get_id(struct cdns3 *cdns); +int cdns3_drd_init(struct cdns3 *cdns); +int cdns3_drd_exit(struct cdns3 *cdns); +int cdns3_drd_update_mode(struct cdns3 *cdns); + +#endif /* __LINUX_CDNS3_DRD */ diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c new file mode 100644 index 000000000000..1ef0e9f73e3e --- /dev/null +++ b/drivers/usb/cdns3/ep0.c @@ -0,0 +1,864 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include + +#include "gadget.h" +#include "trace.h" + +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +/** + * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware + * @priv_dev: extended gadget object + * @dma_addr: physical address where data is/will be stored + * @length: data length + * @erdy: set it to 1 when ERDY packet should be sent - + * exit from flow control state + */ +static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, + dma_addr_t dma_addr, + unsigned int length, int erdy) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + priv_dev->ep0_trb->buffer = TRB_BUFFER(dma_addr); + priv_dev->ep0_trb->length = TRB_LEN(length); + priv_dev->ep0_trb->control = TRB_CYCLE | TRB_IOC | TRB_TYPE(TRB_NORMAL); + + trace_cdns3_prepare_trb(priv_ep, priv_dev->ep0_trb); + + cdns3_select_ep(priv_dev, priv_dev->ep0_data_dir); + + writel(EP_STS_TRBERR, ®s->ep_sts); + writel(EP_TRADDR_TRADDR(priv_dev->ep0_trb_dma), ®s->ep_traddr); + trace_cdns3_doorbell_ep0(priv_dev->ep0_data_dir ? "ep0in" : "ep0out"); + + /* TRB should be prepared before starting transfer */ + writel(EP_CMD_DRDY, ®s->ep_cmd); + + if (erdy) + writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); +} + +/** + * cdns3_ep0_delegate_req - Returns status of handling setup packet + * Setup is handled by gadget driver + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns zero on success or negative value on failure + */ +static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + spin_unlock(&priv_dev->lock); + priv_dev->setup_pending = 1; + ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); + priv_dev->setup_pending = 0; + spin_lock(&priv_dev->lock); + return ret; +} + +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) +{ + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + sizeof(struct usb_ctrlrequest), 0); +} + +/** + * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, USB_GADGET_DELAYED_STATUS on deferred status stage, + * error code on error + */ +static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + struct cdns3_endpoint *priv_ep; + u32 config = le16_to_cpu(ctrl_req->wValue); + int result = 0; + int i; + + switch (device_state) { + case USB_STATE_ADDRESS: + /* Configure non-control EPs */ + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { + priv_ep = priv_dev->eps[i]; + if (!priv_ep) + continue; + + if (priv_ep->flags & EP_CLAIMED) + cdns3_ep_config(priv_ep); + } + + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (result) + return result; + + if (config) { + cdns3_set_hw_configuration(priv_dev); + } else { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, + USB_STATE_ADDRESS); + } + break; + case USB_STATE_CONFIGURED: + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (!config && !result) { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, + USB_STATE_ADDRESS); + } + break; + default: + result = -EINVAL; + } + + return result; +} + +/** + * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + u32 reg; + u32 addr; + + addr = le16_to_cpu(ctrl_req->wValue); + + if (addr > USB_DEVICE_MAX_ADDRESS) { + dev_err(priv_dev->dev, + "Device address (%d) cannot be greater than %d\n", + addr, USB_DEVICE_MAX_ADDRESS); + return -EINVAL; + } + + if (device_state == USB_STATE_CONFIGURED) { + dev_err(priv_dev->dev, + "can't set_address from configured state\n"); + return -EINVAL; + } + + reg = readl(&priv_dev->regs->usb_cmd); + + writel(reg | USB_CMD_FADDR(addr) | USB_CMD_SET_ADDR, + &priv_dev->regs->usb_cmd); + + usb_gadget_set_state(&priv_dev->gadget, + (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT)); + + cdns3_prepare_setup_packet(priv_dev); + + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + return 0; +} + +/** + * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl) +{ + __le16 *response_pkt; + u16 usb_status = 0; + u32 recip; + u32 reg; + + recip = ctrl->bRequestType & USB_RECIP_MASK; + + switch (recip) { + case USB_RECIP_DEVICE: + /* self powered */ + if (priv_dev->is_selfpowered) + usb_status = BIT(USB_DEVICE_SELF_POWERED); + + if (priv_dev->wake_up_flag) + usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP); + + if (priv_dev->gadget.speed != USB_SPEED_SUPER) + break; + + reg = readl(&priv_dev->regs->usb_sts); + + if (priv_dev->u1_allowed) + usb_status |= BIT(USB_DEV_STAT_U1_ENABLED); + + if (priv_dev->u2_allowed) + usb_status |= BIT(USB_DEV_STAT_U2_ENABLED); + + break; + case USB_RECIP_INTERFACE: + return cdns3_ep0_delegate_req(priv_dev, ctrl); + case USB_RECIP_ENDPOINT: + /* check if endpoint is stalled */ + cdns3_select_ep(priv_dev, ctrl->wIndex); + if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts))) + usb_status = BIT(USB_ENDPOINT_HALT); + break; + default: + return -EINVAL; + } + + response_pkt = (__le16 *)priv_dev->setup_buf; + *response_pkt = cpu_to_le16(usb_status); + + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + sizeof(*response_pkt), 1); + return 0; +} + +static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + enum usb_device_state state; + enum usb_device_speed speed; + int ret = 0; + u32 wValue; + u32 wIndex; + u16 tmode; + + wValue = le16_to_cpu(ctrl->wValue); + wIndex = le16_to_cpu(ctrl->wIndex); + state = priv_dev->gadget.state; + speed = priv_dev->gadget.speed; + + switch (ctrl->wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + priv_dev->wake_up_flag = !!set; + break; + case USB_DEVICE_U1_ENABLE: + if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) + return -EINVAL; + + priv_dev->u1_allowed = !!set; + break; + case USB_DEVICE_U2_ENABLE: + if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) + return -EINVAL; + + priv_dev->u2_allowed = !!set; + break; + case USB_DEVICE_LTM_ENABLE: + ret = -EINVAL; + break; + case USB_DEVICE_TEST_MODE: + if (state != USB_STATE_CONFIGURED || speed > USB_SPEED_HIGH) + return -EINVAL; + + tmode = le16_to_cpu(ctrl->wIndex); + + if (!set || (tmode & 0xff) != 0) + return -EINVAL; + + switch (tmode >> 8) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + cdns3_set_register_bit(&priv_dev->regs->usb_cmd, + USB_CMD_STMODE | + USB_STS_TMODE_SEL(tmode - 1)); + break; + default: + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cdns3_ep0_feature_handle_intf(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + u32 wValue; + int ret = 0; + + wValue = le16_to_cpu(ctrl->wValue); + + switch (wValue) { + case USB_INTRF_FUNC_SUSPEND: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + struct cdns3_endpoint *priv_ep; + int ret = 0; + u8 index; + + if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT) + return -EINVAL; + + if (!(ctrl->wIndex & ~USB_DIR_IN)) + return 0; + + index = cdns3_ep_addr_to_index(ctrl->wIndex); + priv_ep = priv_dev->eps[index]; + + cdns3_select_ep(priv_dev, ctrl->wIndex); + + if (set) { + writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd); + priv_ep->flags |= EP_STALL; + } else { + struct usb_request *request; + + if (priv_dev->eps[index]->flags & EP_WEDGE) { + cdns3_select_ep(priv_dev, 0x00); + return 0; + } + + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + /* wait for EPRST cleared */ + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + if (ret) + return -EINVAL; + + priv_ep->flags &= ~EP_STALL; + + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + return ret; +} + +/** + * cdns3_req_ep0_handle_feature - + * Handling of GET/SET_FEATURE standard USB request + * + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * @set: must be set to 1 for SET_FEATURE request + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + int ret = 0; + u32 recip; + + recip = ctrl->bRequestType & USB_RECIP_MASK; + + switch (recip) { + case USB_RECIP_DEVICE: + ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set); + break; + case USB_RECIP_INTERFACE: + ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set); + break; + case USB_RECIP_ENDPOINT: + ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set); + break; + default: + return -EINVAL; + } + + if (!ret) + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + return ret; +} + +/** + * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + if (priv_dev->gadget.state < USB_STATE_ADDRESS) + return -EINVAL; + + if (ctrl_req->wLength != 6) { + dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n", + ctrl_req->wLength); + return -EINVAL; + } + + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 6, 1); + return 0; +} + +/** + * cdns3_req_ep0_set_isoch_delay - + * Handling of GET_ISOCH_DELAY standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_isoch_delay(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + if (ctrl_req->wIndex || ctrl_req->wLength) + return -EINVAL; + + priv_dev->isoch_delay = ctrl_req->wValue; + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + return 0; +} + +/** + * cdns3_ep0_standard_request - Handling standard USB requests + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_ep0_standard_request(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + switch (ctrl_req->bRequest) { + case USB_REQ_SET_ADDRESS: + ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req); + break; + case USB_REQ_SET_CONFIGURATION: + ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req); + break; + case USB_REQ_GET_STATUS: + ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req); + break; + case USB_REQ_CLEAR_FEATURE: + ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0); + break; + case USB_REQ_SET_FEATURE: + ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1); + break; + case USB_REQ_SET_SEL: + ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req); + break; + case USB_REQ_SET_ISOCH_DELAY: + ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req); + break; + default: + ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + break; + } + + return ret; +} + +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) +{ + struct usb_request *request = priv_dev->pending_status_request; + + if (priv_dev->status_completion_no_call && request && + request->complete) { + request->complete(priv_dev->gadget.ep0, request); + priv_dev->status_completion_no_call = 0; + } +} + +void cdns3_pending_setup_status_handler(struct work_struct *work) +{ + struct cdns3_device *priv_dev = container_of(work, struct cdns3_device, + pending_status_wq); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + __pending_setup_status_handler(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); +} + +/** + * cdns3_gadget_ep_giveback - call struct usb_request's ->complete callback + * @priv_ep: The endpoint to whom the request belongs to + * @priv_req: The request we're giving back + * @status: completion code for the request + * + * Must be called with controller's lock held and interrupts disabled. This + * function will unmap @req and call its ->complete() callback to notify upper + * layers that it has completed. + */ + +void cdns3_gadget_ep0_giveback(struct cdns3_device *priv_dev, + int status) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + + priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + request = cdns3_next_request(&priv_ep->request_list); + + priv_ep->dir = priv_dev->ep0_data_dir; + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), status); + priv_dev->ep0_request = NULL; +} + +/** + * cdns3_ep0_setup_phase - Handling setup USB requests + * @priv_dev: extended gadget object + */ +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) +{ + struct usb_ctrlrequest *ctrl = priv_dev->setup_buf; + struct cdns3_endpoint *priv_ep; + int result; + + priv_dev->ep0_data_dir = ctrl->bRequestType & USB_DIR_IN; + priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + trace_cdns3_ctrl_req(ctrl); + + if (!list_empty(&priv_ep->request_list)) + cdns3_gadget_ep0_giveback(priv_dev, -ECONNRESET); + + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) + result = cdns3_ep0_standard_request(priv_dev, ctrl); + else + result = cdns3_ep0_delegate_req(priv_dev, ctrl); + + if (result != 0 && result != USB_GADGET_DELAYED_STATUS) { + dev_dbg(priv_dev->dev, "STALL for ep0\n"); + /* set_stall on ep0 */ + cdns3_select_ep(priv_dev, 0x00); + writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + } +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + if (priv_dev->ep0_request) { + trace_cdns3_complete_trb(priv_ep, priv_dev->ep0_trb); + + priv_dev->ep0_request->actual = + TRB_LEN(le32_to_cpu(priv_dev->ep0_trb->length)); + + cdns3_gadget_ep0_giveback(priv_dev, 0); + } + + cdns3_prepare_setup_packet(priv_dev); + writel(EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); +} + +/** + * cdns3_check_new_setup - Check if controller receive new SETUP packet. + * @priv_dev: extended gadget object + * + * The SETUP packet can be kept in on-chip memory or in system memory. + */ +static bool cdns3_check_new_setup(struct cdns3_device *priv_dev) +{ + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT); + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + + return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT)); +} + +/** + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 + * @priv_dev: extended gadget object + * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction + */ +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) +{ + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, dir); + + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + writel(ep_sts_reg, &priv_dev->regs->ep_sts); + + trace_cdns3_ep0_irq(priv_dev); + + __pending_setup_status_handler(priv_dev); + + if ((ep_sts_reg & EP_STS_SETUP)) { + cdns3_ep0_setup_phase(priv_dev); + } else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { + priv_dev->ep0_data_dir = dir; + cdns3_transfer_completed(priv_dev); + } + + if (ep_sts_reg & EP_STS_DESCMIS) { + if (dir == 0 && !priv_dev->setup_pending) + cdns3_prepare_setup_packet(priv_dev); + } +} + +/** + * cdns3_gadget_ep0_enable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_disable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_disable(struct usb_ep *ep) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_set_halt + * @ep: pointer to endpoint zero object + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 + */ +static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + /* TODO */ + return 0; +} + +/** + * cdns3_gadget_ep0_queue Transfer data on endpoint zero + * @ep: pointer to endpoint zero object + * @request: pointer to request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep0_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int erdy_sent = 0; + int ret = 0; + + dev_dbg(priv_dev->dev, "Queue to Ep0%s L: %d\n", + priv_dev->ep0_data_dir ? "IN" : "OUT", + request->length); + + /* cancel the request if controller receive new SETUP packet. */ + if (cdns3_check_new_setup(priv_dev)) + return -ECONNRESET; + + /* send STATUS stage. Should be called only for SET_CONFIGURATION */ + if (request->length == 0 && request->zero == 0) { + spin_lock_irqsave(&priv_dev->lock, flags); + cdns3_select_ep(priv_dev, 0x00); + + erdy_sent = !priv_dev->hw_configured_flag; + cdns3_set_hw_configuration(priv_dev); + + if (!erdy_sent) + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, + &priv_dev->regs->ep_cmd); + + cdns3_prepare_setup_packet(priv_dev); + request->actual = 0; + priv_dev->status_completion_no_call = true; + priv_dev->pending_status_request = request; + spin_unlock_irqrestore(&priv_dev->lock, flags); + + /* + * Since there is no completion interrupt for status stage, + * it needs to call ->completion in software after + * ep0_queue is back. + */ + queue_work(system_freezable_wq, &priv_dev->pending_status_wq); + return 0; + } + + spin_lock_irqsave(&priv_dev->lock, flags); + if (!list_empty(&priv_ep->request_list)) { + dev_err(priv_dev->dev, + "can't handle multiple requests for ep0\n"); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return -EBUSY; + } + + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, + priv_dev->ep0_data_dir); + if (ret) { + spin_unlock_irqrestore(&priv_dev->lock, flags); + dev_err(priv_dev->dev, "failed to map request\n"); + return -EINVAL; + } + + request->status = -EINPROGRESS; + priv_dev->ep0_request = request; + list_add_tail(&request->list, &priv_ep->request_list); + cdns3_ep0_run_transfer(priv_dev, request->dma, request->length, 1); + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +/** + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint + * @ep: endpoint object + * + * Returns 0 + */ +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name); + cdns3_gadget_ep_set_halt(ep, 1); + priv_ep->flags |= EP_WEDGE; + + return 0; +} + +const struct usb_ep_ops cdns3_gadget_ep0_ops = { + .enable = cdns3_gadget_ep0_enable, + .disable = cdns3_gadget_ep0_disable, + .alloc_request = cdns3_gadget_ep_alloc_request, + .free_request = cdns3_gadget_ep_free_request, + .queue = cdns3_gadget_ep0_queue, + .dequeue = cdns3_gadget_ep_dequeue, + .set_halt = cdns3_gadget_ep0_set_halt, + .set_wedge = cdns3_gadget_ep_set_wedge, +}; + +/** + * cdns3_ep0_config - Configures default endpoint + * @priv_dev: extended gadget object + * + * Functions sets parameters: maximal packet size and enables interrupts + */ +void cdns3_ep0_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs; + u32 max_packet_size = 64; + + regs = priv_dev->regs; + + if (priv_dev->gadget.speed == USB_SPEED_SUPER) + max_packet_size = 512; + + if (priv_dev->ep0_request) { + list_del_init(&priv_dev->ep0_request->list); + priv_dev->ep0_request = NULL; + } + + priv_dev->u1_allowed = 0; + priv_dev->u2_allowed = 0; + + priv_dev->gadget.ep0->maxpacket = max_packet_size; + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + /* init ep out */ + cdns3_select_ep(priv_dev, USB_DIR_OUT); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, + ®s->ep_sts_en); + + /* init ep in */ + cdns3_select_ep(priv_dev, USB_DIR_IN); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); + + cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); + cdns3_prepare_setup_packet(priv_dev); +} + +/** + * cdns3_init_ep0 Initializes software endpoint 0 of gadget + * @cdns3: extended gadget object + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_init_ep0(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *ep0; + + ep0 = devm_kzalloc(priv_dev->dev, sizeof(struct cdns3_endpoint), + GFP_KERNEL); + + if (!ep0) + return -ENOMEM; + + ep0->cdns3_dev = priv_dev; + sprintf(ep0->name, "ep0"); + + /* fill linux fields */ + ep0->endpoint.ops = &cdns3_gadget_ep0_ops; + ep0->endpoint.maxburst = 1; + usb_ep_set_maxpacket_limit(&ep0->endpoint, CDNS3_EP0_MAX_PACKET_LIMIT); + ep0->endpoint.address = 0; + ep0->endpoint.caps.type_control = 1; + ep0->endpoint.caps.dir_in = 1; + ep0->endpoint.caps.dir_out = 1; + ep0->endpoint.name = ep0->name; + ep0->endpoint.desc = &cdns3_gadget_ep0_desc; + priv_dev->gadget.ep0 = &ep0->endpoint; + INIT_LIST_HEAD(&ep0->request_list); + + return 0; +} diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h new file mode 100644 index 000000000000..577469eee961 --- /dev/null +++ b/drivers/usb/cdns3/gadget-export.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver - Gadget Export APIs. + * + * Copyright (C) 2017 NXP + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET_EXPORT +#define __LINUX_CDNS3_GADGET_EXPORT + +#ifdef CONFIG_USB_CDNS3_GADGET + +int cdns3_gadget_init(struct cdns3 *cdns); +void cdns3_gadget_exit(struct cdns3 *cdns); +#else + +static inline int cdns3_gadget_init(struct cdns3 *cdns) +{ + return -ENXIO; +} + +static inline void cdns3_gadget_exit(struct cdns3 *cdns) { } + +#endif + +#endif /* __LINUX_CDNS3_GADGET_EXPORT */ diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c new file mode 100644 index 000000000000..a021eaf07aee --- /dev/null +++ b/drivers/usb/cdns3/gadget.c @@ -0,0 +1,1802 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include +#include + +#include "core.h" +#include "gadget-export.h" +#include "gadget.h" + +#include "trace.h" + +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags); + +/** + * cdns3_handshake - spin reading until handshake completes or fails + * @ptr: address of device controller register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + */ +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl(ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/** + * cdns3_set_register_bit - set bit in given register. + * @ptr: address of device controller register to be read and changed + * @mask: bits requested to set + */ +void cdns3_set_register_bit(void __iomem *ptr, u32 mask) +{ + mask = readl(ptr) | mask; + writel(mask, ptr); +} + +/** + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register + * to index of endpoint object in cdns3_device.eps[] container + * @i: bit position of endpoint for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u8 cdns3_ep_reg_pos_to_index(int i) +{ + return ((i / 16) + (((i % 16) - 2) * 2)); +} + +/** + * cdns3_ep_addr_to_index - Macro converts endpoint address to + * index of endpoint object in cdns3_device.eps[] container + * @ep_addr: endpoint address for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +u8 cdns3_ep_addr_to_index(u8 ep_addr) +{ + return (((ep_addr & 0x7F) - 1) + ((ep_addr & USB_DIR_IN) ? 1 : 0)); +} + +/** + * cdns3_ep_addr_to_bit_pos - Macro converts endpoint address to + * bit position in ep_ists register + * @ep_addr: endpoint address for which bit position is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u32 cdns3_ep_addr_to_bit_pos(u8 ep_addr) +{ + return (1 << (ep_addr & 0x7F)) << ((ep_addr & 0x80) ? 16 : 0); +} + +/** + * cdns3_next_request - returns next request from list + * @list: list containing requests + * + * Returns request or NULL if no requests in list + */ +struct usb_request *cdns3_next_request(struct list_head *list) +{ + if (list_empty(list)) + return NULL; + return list_first_entry(list, struct usb_request, list); +} + +/** + * select_ep - selects endpoint + * @priv_dev: extended gadget object + * @ep: endpoint address + */ +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) +{ + if (priv_dev->selected_ep == ep) + return; + + priv_dev->selected_ep = ep; + writel(ep, &priv_dev->regs->ep_sel); +} + +dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, + struct cdns3_trb *trb) +{ + u32 offset = (char *)trb - (char *)priv_ep->trb_pool; + + return priv_ep->trb_pool_dma + offset; +} + +/** + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint + * @priv_ep: endpoint object + * + * Function will return 0 on success or -ENOMEM on allocation error + */ +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *link_trb; + + if (!priv_ep->trb_pool) { + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + &priv_ep->trb_pool_dma, + GFP_DMA); + if (!priv_ep->trb_pool) + return -ENOMEM; + } else { + memset(priv_ep->trb_pool, 0, TRB_RING_SIZE); + } + + if (!priv_ep->aligned_buff) { + void *buff = dma_alloc_coherent(priv_dev->sysdev, + CDNS3_ALIGNED_BUF_SIZE, + &priv_ep->aligned_dma_addr, + GFP_DMA); + + priv_ep->aligned_buff = buff; + if (!priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + priv_ep->trb_pool, + priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + + return -ENOMEM; + } + } + + /* Initialize the last TRB as Link TRB */ + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | + TRB_CHAIN | TRB_TOGGLE; + + return 0; +} + +static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + if (priv_ep->trb_pool) { + dma_free_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + priv_ep->trb_pool, priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + } + + if (priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, CDNS3_ALIGNED_BUF_SIZE, + priv_ep->aligned_buff, + priv_ep->aligned_dma_addr); + priv_ep->aligned_buff = NULL; + } +} + +/** + * cdns3_data_flush - flush data at onchip buffer + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + * + * Returns zero on success or negative value on failure + */ +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); +} + +/** + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + */ +static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL, + &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); + priv_ep->flags |= EP_STALL; +} + +/** + * cdns3_gadget_unconfig - reset device configuration + * @priv_dev: extended gadget object + */ +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) +{ + /* RESET CONFIGURATION */ + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf); + + cdns3_allow_enable_l1(priv_dev, 0); + priv_dev->hw_configured_flag = 0; + priv_dev->onchip_mem_allocated_size = 0; +} + +/** + * cdns3_ep_inc_trb - increment a trb index. + * @index: Pointer to the TRB index to increment. + * @cs: Cycle state + * + * The index should never point to the link TRB. After incrementing, + * if it is point to the link TRB, wrap around to the beginning and revert + * cycle state bit The + * link TRB is always at the last TRB entry. + */ +static void cdns3_ep_inc_trb(int *index, u8 *cs) +{ + (*index)++; + if (*index == (TRBS_PER_SEGMENT - 1)) { + *index = 0; + *cs ^= 1; + } +} + +/** + * cdns3_ep_inc_enq - increment endpoint's enqueue pointer + * @priv_ep: The endpoint whose enqueue pointer we're incrementing + */ +static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs--; + cdns3_ep_inc_trb(&priv_ep->enqueue, &priv_ep->pcs); +} + +/** + * cdns3_ep_inc_deq - increment endpoint's dequeue pointer + * @priv_ep: The endpoint whose dequeue pointer we're incrementing + */ +static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs++; + cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs); +} + +/** + * cdns3_allow_enable_l1 - enable/disable permits to transition to L1. + * @priv_dev: Extended gadget object + * @enable: Enable/disable permit to transition to L1. + * + * If bit USB_CONF_L1EN is set and device receive Extended Token packet, + * then controller answer with ACK handshake. + * If bit USB_CONF_L1DS is set and device receive Extended Token packet, + * then controller answer with NYET handshake. + */ +void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable) +{ + if (enable) + writel(USB_CONF_L1EN, &priv_dev->regs->usb_conf); + else + writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf); +} + +enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev) +{ + u32 reg; + + reg = readl(&priv_dev->regs->usb_sts); + + if (DEV_SUPERSPEED(reg)) + return USB_SPEED_SUPER; + else if (DEV_HIGHSPEED(reg)) + return USB_SPEED_HIGH; + else if (DEV_FULLSPEED(reg)) + return USB_SPEED_FULL; + else if (DEV_LOWSPEED(reg)) + return USB_SPEED_LOW; + return USB_SPEED_UNKNOWN; +} + +/** + * cdns3_start_all_request - add to ring all request not started + * @priv_dev: Extended gadget object + * @priv_ep: The endpoint for whom request will be started. + * + * Returns return ENOMEM if transfer ring i not enough TRBs to start + * all requests. + */ +static int cdns3_start_all_request(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + struct usb_request *req, *req_temp; + int ret = 0; + + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { + struct cdns3_request *priv_req = to_cdns3_request(req); + + if (!(priv_req->flags & REQUEST_PENDING)) { + ret = cdns3_ep_run_transfer(priv_ep, req); + if (ret) + return ret; + } + } + + priv_ep->flags &= ~EP_RING_FULL; + return ret; +} + +/** + * cdns3_gadget_giveback - call struct usb_request's ->complete callback + * @priv_ep: The endpoint to whom the request belongs to + * @priv_req: The request we're giving back + * @status: completion code for the request + * + * Must be called with controller's lock held and interrupts disabled. This + * function will unmap @req and call its ->complete() callback to notify upper + * layers that it has completed. + */ +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req, + int status) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *request = &priv_req->request; + + list_del_init(&request->list); + + if (request->status == -EINPROGRESS) + request->status = status; + + usb_gadget_unmap_request_by_dev(priv_dev->sysdev, request, + priv_ep->dir); + + priv_req->flags &= ~REQUEST_PENDING; + trace_cdns3_gadget_giveback(priv_req); + + if (priv_req->flags & REQUEST_INTERNAL) { + struct usb_request *req; + + req = cdns3_next_request(&priv_ep->request_list); + + priv_ep->descmis_pending = false; + priv_ep->descmis_finished = true; + + /* + * If no request is queued then driver can't do nothing + * with just completed request. Request with flag set to + * REQUEST_INTERNAL is only internal used request and driver + * can't call complete callback. Before calling completion, data + * must be copied to normal usb_request object + */ + if (!req) + return; + + req->actual = request->actual; + req->status = request->status; + memcpy(req->buf, request->buf, request->actual); + + request = req; + list_del_init(&request->list); + cdns3_start_all_request(priv_dev, priv_ep); + priv_ep->descmis_finished = false; + } + + /* Start all not pending request */ + if (priv_ep->flags & EP_RING_FULL) + cdns3_start_all_request(priv_dev, priv_ep); + + if (request->complete) { + spin_unlock(&priv_dev->lock); + usb_gadget_giveback_request(&priv_ep->endpoint, + request); + spin_lock(&priv_dev->lock); + } + + if (request->buf == priv_dev->zlp_buf) + cdns3_gadget_ep_free_request(&priv_ep->endpoint, request); +} + +/** + * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware + * @priv_ep: endpoint object + * + * Returns zero on success or negative value on failure + */ +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + struct usb_request *request) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + dma_addr_t trb_dma; + int sg_iter = 0; + u32 first_pcs; + int num_trb; + int address; + int pcs; + + num_trb = request->num_sgs ? request->num_sgs : 1; + + if (num_trb > priv_ep->free_trbs) { + priv_ep->flags |= EP_RING_FULL; + return -ENOMEM; + } + + priv_req = to_cdns3_request(request); + address = priv_ep->endpoint.desc->bEndpointAddress; + + if (priv_ep->descmis_pending) + return 0; + + if (priv_req->flags & REQUEST_PENDING) + goto arm; + + priv_ep->flags |= EP_PENDING_REQUEST; + trb_dma = request->dma; + + /* must allocate buffer aligned to 8 */ + if ((request->dma % 8)) { + if (request->length <= CDNS3_ALIGNED_BUF_SIZE) { + memcpy(priv_ep->aligned_buff, request->buf, + request->length); + trb_dma = priv_ep->aligned_dma_addr; + } else { + return -ENOMEM; + } + } + + trb = priv_ep->trb_pool + priv_ep->enqueue; + priv_req->trb = trb; + priv_req->start_trb = priv_ep->enqueue; + + /* prepare ring */ + if ((priv_ep->enqueue + num_trb) >= (TRBS_PER_SEGMENT - 1)) { + /*updating C bt in Link TRB before starting DMA*/ + struct cdns3_trb *link_trb = priv_ep->trb_pool + + (TRBS_PER_SEGMENT - 1); + link_trb->control = ((priv_ep->pcs) ? TRB_CYCLE : 0) | + TRB_TYPE(TRB_LINK) | TRB_CHAIN | + TRB_TOGGLE; + } + + first_pcs = priv_ep->pcs ? TRB_CYCLE : 0; + + do { + /* fill TRB */ + trb->buffer = TRB_BUFFER(request->num_sgs == 0 + ? trb_dma : request->sg[sg_iter].dma_address); + + trb->length = TRB_BURST_LEN(16) | + TRB_LEN(request->num_sgs == 0 ? + request->length : request->sg[sg_iter].length); + + trb->control = TRB_TYPE(TRB_NORMAL); + pcs = priv_ep->pcs ? TRB_CYCLE : 0; + + /* + * first trb should be prepared as last to avoid processing + * transfer to early + */ + if (sg_iter == request->num_sgs && sg_iter != 0) + trb->control |= pcs | TRB_IOC | TRB_ISP; + else if (sg_iter != 0) + trb->control |= pcs; + + ++sg_iter; + ++trb; + cdns3_ep_inc_enq(priv_ep); + } while (sg_iter < request->num_sgs); + + trb = priv_req->trb; + /* + * Memory barrier = Cycle Bit must be set before trb->length and + * trb->buffer fields. + */ + wmb(); + + /* give the TD to the consumer*/ + if (sg_iter == 1) + trb->control |= first_pcs | TRB_IOC | TRB_ISP; + else + trb->control |= first_pcs; + + priv_req->flags |= REQUEST_PENDING; + + if (priv_req->flags & REQUEST_INTERNAL) + priv_ep->descmis_pending = true; + + trace_cdns3_prepare_trb(priv_ep, priv_req->trb); + trace_cdns3_ring(priv_ep); + +arm: + /* arm transfer on selected endpoint */ + cdns3_select_ep(priv_ep->cdns3_dev, address); + + /* + * For DMULT mode we can set address to transfer ring only once after + * enabling endpoint. + */ + if (priv_ep->flags & EP_UPDATE_EP_TRBADDR) { + writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma), + &priv_dev->regs->ep_traddr); + priv_ep->flags &= ~EP_UPDATE_EP_TRBADDR; + } + + if (priv_dev->hw_configured_flag) { + /*clearing TRBERR and EP_STS_DESCMIS before seting DRDY*/ + writel(EP_STS_TRBERR | EP_STS_DESCMIS, &priv_dev->regs->ep_sts); + trace_cdns3_doorbell_epx(priv_ep->name); + writel(EP_CMD_DRDY, &priv_dev->regs->ep_cmd); + } + + return 0; +} + +void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + struct usb_ep *ep; + int result = 0; + + if (priv_dev->hw_configured_flag) + return; + + writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + cdns3_set_register_bit(&priv_dev->regs->usb_conf, + USB_CONF_U1EN | USB_CONF_U2EN); + + /* wait until configuration set */ + result = cdns3_handshake(&priv_dev->regs->usb_sts, + USB_STS_CFGSTS_MASK, 1, 100); + + priv_dev->hw_configured_flag = 1; + cdns3_allow_enable_l1(priv_dev, 1); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + if (ep->enabled) { + priv_ep = ep_to_cdns3_ep(ep); + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + } +} + +static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req) +{ + int current_index; + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *trb = priv_req->trb; + + if (!(priv_req->flags & REQUEST_PENDING)) + return false; + + cdns3_select_ep(priv_dev, priv_ep->endpoint.desc->bEndpointAddress); + current_index = (readl(&priv_dev->regs->ep_traddr) - + priv_ep->trb_pool_dma) / TRB_SIZE; + + trb = &priv_ep->trb_pool[priv_req->start_trb]; + + if ((trb->control & TRB_CYCLE) != priv_ep->ccs) + return false; + + /** + * case where ep_traddr point to last trb in ring (link trb) + * and dequeue pointer already has been changed to first trb + */ + if ((current_index == (TRBS_PER_SEGMENT - 1)) && !priv_ep->dequeue) + return false; + + if (priv_req->start_trb != current_index) + return true; + + return false; +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + struct usb_request *request; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + + while (!list_empty(&priv_ep->request_list)) { + request = cdns3_next_request(&priv_ep->request_list); + priv_req = to_cdns3_request(request); + + if (!cdns3_request_handled(priv_ep, priv_req)) + return; + + if (request->dma % 8 && priv_ep->dir == USB_DIR_OUT) + memcpy(request->buf, priv_ep->aligned_buff, + request->length); + + trb = priv_ep->trb_pool + priv_ep->dequeue; + trace_cdns3_complete_trb(priv_ep, trb); + if (trb != priv_req->trb) + dev_warn(priv_dev->dev, + "request_trb=0x%p, queue_trb=0x%p\n", + priv_req->trb, trb); + + request->actual = TRB_LEN(le32_to_cpu(trb->length)); + + cdns3_ep_inc_deq(priv_ep); + + cdns3_gadget_giveback(priv_ep, priv_req, 0); + } + + priv_ep->flags &= ~EP_PENDING_REQUEST; +} + +/** + * cdns3_descmissing_packet - handles descriptor missing event. + * @priv_dev: extended gadget object + * + * Function protects gadget functions from getting stuck. + * Controller for OUT endpoints has shared on-chip buffers for all incoming + * packets, including ep0out. It's FIFO buffer, so packets must be handle by DMA + * in correct order. If the first packet in the buffer will not be handled, + * then the following packets directed for other endpoints and functions + * will be blocked. + * Additionally the packets directed to one endpoint can clog entire on-chip + * buffers. In this case transfer to other endpoints also will blocked. + * + * To resolve this issue after raising the descriptor missing interrupt + * driver prepares internal usb_request object and use it to arm DMA transfer + * for the right endpoint. Driver use only single usb_request with + * allocated 64KB buffer, so if host send more not expected transfers, then only + * the last will be saved and returned to gadget function. + * Such blocking situation was observed on ACM gadget, because host send OUT + * data packet but ACM function doesn't want their. + */ +static void cdns3_descmissing_packet(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_request *priv_req = priv_ep->descmis_req; + struct usb_request *request; + + if (!priv_req) { + request = cdns3_gadget_ep_alloc_request(&priv_ep->endpoint, + GFP_ATOMIC); + priv_req = to_cdns3_request(request); + priv_req->flags |= REQUEST_INTERNAL; + priv_req->request.buf = kzalloc(CDNS3_DESCMIS_BUF_SIZE, + GFP_ATOMIC); + priv_req->request.length = CDNS3_DESCMIS_BUF_SIZE; + priv_ep->descmis_req = priv_req; + } + + priv_ep->descmis_finished = false; + __cdns3_gadget_ep_queue(&priv_ep->endpoint, + &priv_ep->descmis_req->request, + GFP_ATOMIC); +} + +/** + * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint + * @priv_ep: endpoint object + * + * Returns 0 + */ +static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, priv_ep->endpoint.address); + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + writel(ep_sts_reg, &priv_dev->regs->ep_sts); + + trace_cdns3_epx_irq(priv_ep); + + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) + cdns3_transfer_completed(priv_dev, priv_ep); + + if (ep_sts_reg & EP_STS_DESCMIS) + cdns3_descmissing_packet(priv_ep); + + return 0; +} + +/** + * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device + * @priv_dev: extended gadget object + * @usb_ists: bitmap representation of device's reported interrupts + * (usb_ists register value) + */ +static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev, + u32 usb_ists) +{ + int speed = 0; + + trace_cdns3_usb_irq(priv_dev, usb_ists); + /* Connection detected */ + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { + speed = cdns3_get_speed(priv_dev); + priv_dev->gadget.speed = speed; + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED); + cdns3_ep0_config(priv_dev); + } + + /* Disconnection detected */ + if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) { + if (priv_dev->gadget_driver && + priv_dev->gadget_driver->disconnect) { + spin_unlock(&priv_dev->lock); + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); + spin_lock(&priv_dev->lock); + } + + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED); + cdns3_gadget_unconfig(priv_dev); + } + + /* reset*/ + if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) { + /*read again to check the actuall speed*/ + speed = cdns3_get_speed(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_DEFAULT); + priv_dev->gadget.speed = speed; + cdns3_gadget_unconfig(priv_dev); + cdns3_ep0_config(priv_dev); + } +} + +/** + * cdns3_device_irq_handler- interrupt handler for device part of controller + * + * @irq: irq number for cdns3 core device + * @data: structure of cdns3 + * + * Returns IRQ_HANDLED or IRQ_NONE + */ +static irqreturn_t cdns3_device_irq_handler(int irq, void *data) +{ + struct cdns3_device *priv_dev; + struct cdns3 *cdns = data; + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + u32 reg; + + priv_dev = cdns->gadget_dev; + spin_lock_irqsave(&priv_dev->lock, flags); + + /* check USB device interrupt */ + reg = readl(&priv_dev->regs->usb_ists); + writel(reg, &priv_dev->regs->usb_ists); + + if (reg) { + dev_dbg(priv_dev->dev, "IRQ: usb_ists: %08X\n", reg); + cdns3_check_usb_interrupt_proceed(priv_dev, reg); + ret = IRQ_HANDLED; + } + + /* check endpoint interrupt */ + reg = readl(&priv_dev->regs->ep_ists); + + /* handle default endpoint OUT */ + if (reg & EP_ISTS_EP_OUT0) { + cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_OUT); + ret = IRQ_HANDLED; + } + + /* handle default endpoint IN */ + if (reg & EP_ISTS_EP_IN0) { + cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_IN); + ret = IRQ_HANDLED; + } + + /* check if interrupt from non default endpoint, if no exit */ + reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0); + if (!reg) + goto irqend; + + do { + unsigned int bit_pos = ffs(reg); + u32 bit_mask = 1 << (bit_pos - 1); + int index; + + index = cdns3_ep_reg_pos_to_index(bit_pos); + cdns3_check_ep_interrupt_proceed(priv_dev->eps[index]); + reg &= ~bit_mask; + ret = IRQ_HANDLED; + } while (reg); + +irqend: + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_ep_onchip_buffer_reserve - Try to reserve onchip buf for EP + * + * The real reservation will occur during write to EP_CFG register, + * this function is used to check if the 'size' reservation is allowed. + * + * @priv_dev: extended gadget object + * @size: the size (KB) for EP would like to allocate + * + * Return 0 if the required size can met or negative value on failure + */ +static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev, + int size) +{ + u32 onchip_mem; + + priv_dev->onchip_mem_allocated_size += size; + + onchip_mem = USB_CAP2_ACTUAL_MEM_SIZE(readl(&priv_dev->regs->usb_cap2)); + if (!onchip_mem) + onchip_mem = 256; + + /* 2KB is reserved for EP0*/ + onchip_mem -= 2; + if (priv_dev->onchip_mem_allocated_size > onchip_mem) { + priv_dev->onchip_mem_allocated_size -= size; + return -EPERM; + } + + return 0; +} + +/** + * cdns3_ep_config Configure hardware endpoint + * @priv_ep: extended endpoint object + */ +void cdns3_ep_config(struct cdns3_endpoint *priv_ep) +{ + bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + u32 bEndpointAddress = priv_ep->num | priv_ep->dir; + u32 interrupt_mask = EP_STS_EN_TRBERREN; + u32 max_packet_size = 0; + u32 ep_cfg = 0; + int ret; + + if (!priv_ep->dir) + interrupt_mask |= EP_STS_EN_DESCMISEN; + + if (priv_ep->type == USB_ENDPOINT_XFER_INT) { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_INT); + } else if (priv_ep->type == USB_ENDPOINT_XFER_BULK) { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_BULK); + } else { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC); + interrupt_mask = 0xFFFFFFFF; + } + + switch (priv_dev->gadget.speed) { + case USB_SPEED_FULL: + max_packet_size = is_iso_ep ? 1023 : 64; + break; + case USB_SPEED_HIGH: + max_packet_size = is_iso_ep ? 1024 : 512; + break; + case USB_SPEED_SUPER: + max_packet_size = 1024; + break; + default: + /* all other speed are not supported */ + return; + } + + ret = cdns3_ep_onchip_buffer_reserve(priv_dev, CDNS3_EP_BUF_SIZE); + if (ret) { + dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n"); + return; + } + + ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | + EP_CFG_BUFFERING(CDNS3_EP_BUF_SIZE - 1) | + EP_CFG_MAXBURST(priv_ep->endpoint.maxburst); + + cdns3_select_ep(priv_dev, bEndpointAddress); + + writel(ep_cfg, &priv_dev->regs->ep_cfg); + writel(interrupt_mask, &priv_dev->regs->ep_sts_en); + + dev_dbg(priv_dev->dev, "Configure %s: with val %08x\n", + priv_ep->name, ep_cfg); + + /* enable interrupt for selected endpoint */ + cdns3_set_register_bit(&priv_dev->regs->ep_ien, + cdns3_ep_addr_to_bit_pos(bEndpointAddress)); +} + +/* Find correct direction for HW endpoint according to description */ +static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, + struct cdns3_endpoint *priv_ep) +{ + return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) || + (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc)); +} + +static struct +cdns3_endpoint *cdns3_find_available_ep(struct cdns3_device *priv_dev, + struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep; + struct cdns3_endpoint *priv_ep; + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + unsigned long num; + int ret; + /* ep name pattern likes epXin or epXout */ + char c[2] = {ep->name[2], '\0'}; + + ret = kstrtoul(c, 10, &num); + if (ret) + return ERR_PTR(ret); + + priv_ep = ep_to_cdns3_ep(ep); + if (cdns3_ep_dir_is_correct(desc, priv_ep)) { + if (!(priv_ep->flags & EP_CLAIMED)) { + priv_ep->num = num; + return priv_ep; + } + } + } + return ERR_PTR(-ENOENT); +} + +static struct +usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + unsigned long flags; + + priv_ep = cdns3_find_available_ep(priv_dev, desc); + if (IS_ERR(priv_ep)) { + dev_err(priv_dev->dev, "no available ep\n"); + return NULL; + } + + dev_dbg(priv_dev->dev, "match endpoint: %s\n", priv_ep->name); + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + priv_ep->flags |= EP_CLAIMED; + spin_unlock_irqrestore(&priv_dev->lock, flags); + return &priv_ep->endpoint; +} + +/** + * cdns3_gadget_ep_alloc_request Allocates request + * @ep: endpoint object associated with request + * @gfp_flags: gfp flags + * + * Returns allocated request address, NULL on allocation error + */ +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_request *priv_req; + + priv_req = kzalloc(sizeof(*priv_req), gfp_flags); + if (!priv_req) + return NULL; + + priv_req->priv_ep = priv_ep; + + trace_cdns3_alloc_request(priv_req); + return &priv_req->request; +} + +/** + * cdns3_gadget_ep_free_request Free memory occupied by request + * @ep: endpoint object associated with request + * @request: request to free memory + */ +void cdns3_gadget_ep_free_request(struct usb_ep *ep, + struct usb_request *request) +{ + struct cdns3_request *priv_req = to_cdns3_request(request); + + trace_cdns3_free_request(priv_req); + kfree(priv_req); +} + +/** + * cdns3_gadget_ep_enable Enable endpoint + * @ep: endpoint object + * @desc: endpoint descriptor + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct cdns3_endpoint *priv_ep; + struct cdns3_device *priv_dev; + unsigned long flags; + int ret; + u32 reg; + + priv_ep = ep_to_cdns3_ep(ep); + priv_dev = priv_ep->cdns3_dev; + + if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { + dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + return -EINVAL; + } + + if (!desc->wMaxPacketSize) { + dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n"); + return -EINVAL; + } + + if (dev_WARN_ONCE(priv_dev->dev, priv_ep->flags & EP_ENABLED, + "%s is already enabled\n", priv_ep->name)) + return 0; + + ret = cdns3_allocate_trb_pool(priv_ep); + if (ret) + return ret; + + trace_cdns3_gadget_ep_enable(priv_ep); + spin_lock_irqsave(&priv_dev->lock, flags); + + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + + cdns3_select_ep(priv_dev, desc->bEndpointAddress); + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_CSTALL | EP_CMD_EPRST, 0, 100); + + cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE); + + ep->desc = desc; + priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALL); + priv_ep->flags |= EP_ENABLED | EP_UPDATE_EP_TRBADDR; + priv_ep->enqueue = 0; + priv_ep->dequeue = 0; + reg = readl(&priv_dev->regs->ep_sts); + priv_ep->pcs = !!EP_STS_CCS(reg); + priv_ep->ccs = !!EP_STS_CCS(reg); + /* one TRB is reserved for link TRB used in DMULT mode*/ + priv_ep->free_trbs = TRBS_PER_SEGMENT - 1; + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_ep_disable Disable endpoint + * @ep: endpoint object + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep_disable(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep; + struct cdns3_device *priv_dev; + unsigned long flags; + int ret = 0; + struct usb_request *request; + u32 ep_cfg; + + if (!ep) { + dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + return -EINVAL; + } + + priv_ep = ep_to_cdns3_ep(ep); + priv_dev = priv_ep->cdns3_dev; + + if (dev_WARN_ONCE(priv_dev->dev, !(priv_ep->flags & EP_ENABLED), + "%s is already disabled\n", priv_ep->name)) + return 0; + + spin_lock_irqsave(&priv_dev->lock, flags); + + trace_cdns3_gadget_ep_disable(priv_ep); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + ret = cdns3_data_flush(priv_ep); + + ep_cfg = readl(&priv_dev->regs->ep_cfg); + ep_cfg &= ~EP_CFG_ENABLE; + writel(ep_cfg, &priv_dev->regs->ep_cfg); + + while (!list_empty(&priv_ep->request_list)) { + request = cdns3_next_request(&priv_ep->request_list); + + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), + -ESHUTDOWN); + } + + if (priv_ep->descmis_req) { + kfree(priv_ep->descmis_req->request.buf); + cdns3_gadget_ep_free_request(&priv_ep->endpoint, + &priv_ep->descmis_req->request); + priv_ep->descmis_req = NULL; + priv_ep->descmis_pending = false; + priv_ep->descmis_finished = false; + } + + ep->desc = NULL; + priv_ep->flags &= ~EP_ENABLED; + + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +/** + * cdns3_gadget_ep_queue Transfer data on endpoint + * @ep: endpoint object + * @request: request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + int ret = 0; + + request->actual = 0; + request->status = -EINPROGRESS; + priv_req = to_cdns3_request(request); + + trace_cdns3_ep_queue(priv_req); + + /* Data will be copied from internal usb_request object. */ + if (priv_ep->descmis_finished) { + priv_ep->descmis_finished = false; + request->actual = priv_ep->descmis_req->request.actual; + + memcpy(request->buf, priv_ep->descmis_req->request.buf, + priv_ep->descmis_req->request.actual); + list_add_tail(&request->list, &priv_ep->request_list); + + cdns3_gadget_giveback(priv_ep, + priv_req, + priv_ep->descmis_req->request.status); + + return ret; + } + + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, + usb_endpoint_dir_in(ep->desc)); + if (ret) + return ret; + + list_add_tail(&request->list, &priv_ep->request_list); + + cdns3_ep_run_transfer(priv_ep, request); + + return ret; +} + +static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *zlp_request; + unsigned long flags; + int ret; + + if (!request || !ep) + return -EINVAL; + + spin_lock_irqsave(&priv_dev->lock, flags); + ret = __cdns3_gadget_ep_queue(ep, request, gfp_flags); + + if (ret == 0 && request->zero && request->length && + (request->length % ep->maxpacket == 0)) { + struct cdns3_request *priv_req; + + zlp_request = cdns3_gadget_ep_alloc_request(ep, GFP_ATOMIC); + zlp_request->buf = priv_dev->zlp_buf; + zlp_request->length = 0; + + priv_req = to_cdns3_request(zlp_request); + priv_req->flags |= REQUEST_ZLP; + + dev_dbg(priv_dev->dev, "Queuing ZLP for endpoint: %s\n", + priv_ep->name); + ret = __cdns3_gadget_ep_queue(ep, zlp_request, gfp_flags); + } + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_gadget_ep_dequeue Remove request from transfer queue + * @ep: endpoint object associated with request + * @request: request object + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, + struct usb_request *request) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *req, *req_temp; + struct cdns3_request *priv_req; + unsigned long flags; + int ret = 0; + + if (!ep || !request || !ep->desc) + return -EINVAL; + + spin_lock_irqsave(&priv_dev->lock, flags); + + priv_req = to_cdns3_request(request); + + trace_cdns3_ep_dequeue(priv_req); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { + if (request == req) { + cdns3_gadget_giveback(priv_ep, + priv_req, + -ECONNRESET); + break; + } + } + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint + * @ep: endpoint object to set/clear stall on + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int ret = 0; + + if (!(priv_ep->flags & EP_ENABLED)) + return -EPERM; + + spin_lock_irqsave(&priv_dev->lock, flags); + + /* if actual transfer is pending defer setting stall on this endpoint */ + if ((priv_ep->flags & EP_PENDING_REQUEST) && value) { + priv_ep->flags |= EP_STALL; + goto finish; + } + + dev_dbg(priv_dev->dev, "Halt endpoint %s\n", priv_ep->name); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + if (value) { + cdns3_ep_stall_flush(priv_ep); + } else { + priv_ep->flags &= ~EP_WEDGE; + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + /* wait for EPRST cleared */ + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + if (unlikely(ret)) { + dev_err(priv_dev->dev, + "Clearing halt condition failed for %s\n", + priv_ep->name); + goto finish; + + } else { + priv_ep->flags &= ~EP_STALL; + } + } + + priv_ep->flags &= ~EP_PENDING_REQUEST; +finish: + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +extern const struct usb_ep_ops cdns3_gadget_ep0_ops; + +static const struct usb_ep_ops cdns3_gadget_ep_ops = { + .enable = cdns3_gadget_ep_enable, + .disable = cdns3_gadget_ep_disable, + .alloc_request = cdns3_gadget_ep_alloc_request, + .free_request = cdns3_gadget_ep_free_request, + .queue = cdns3_gadget_ep_queue, + .dequeue = cdns3_gadget_ep_dequeue, + .set_halt = cdns3_gadget_ep_set_halt, + .set_wedge = cdns3_gadget_ep_set_wedge, +}; + +/** + * cdns3_gadget_get_frame Returns number of actual ITP frame + * @gadget: gadget object + * + * Returns number of actual ITP frame + */ +static int cdns3_gadget_get_frame(struct usb_gadget *gadget) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + + return readl(&priv_dev->regs->usb_iptn); +} + +static int cdns3_gadget_wakeup(struct usb_gadget *gadget) +{ + return 0; +} + +static int cdns3_gadget_set_selfpowered(struct usb_gadget *gadget, + int is_selfpowered) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_dev->is_selfpowered = !!is_selfpowered; + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +static int cdns3_gadget_pullup(struct usb_gadget *gadget, int is_on) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + + if (is_on) + writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf); + else + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); + + return 0; +} + +static void cdns3_gadget_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + + cdns3_ep0_config(priv_dev); + + /* enable interrupts for endpoint 0 (in and out) */ + writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); + + /* enable generic interrupt*/ + writel(USB_IEN_INIT, ®s->usb_ien); + writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); + writel(USB_CONF_DMULT, ®s->usb_conf); + writel(USB_CONF_DEVEN, ®s->usb_conf); +} + +/** + * cdns3_gadget_udc_start Gadget start + * @gadget: gadget object + * @driver: driver which operates on this gadget + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_dev->gadget_driver = driver; + cdns3_gadget_config(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_udc_stop Stops gadget + * @gadget: gadget object + * + * Returns 0 + */ +static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + u32 bEndpointAddress; + struct usb_ep *ep; + int ret = 0; + int i; + + priv_dev->gadget_driver = NULL; + + priv_dev->onchip_mem_allocated_size = 0; + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + + for (i = 0; i < priv_dev->ep_nums ; i++) + cdns3_free_trb_pool(priv_dev->eps[i]); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + priv_ep = ep_to_cdns3_ep(ep); + bEndpointAddress = priv_ep->num | priv_ep->dir; + cdns3_select_ep(priv_dev, bEndpointAddress); + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + } + + /* disable interrupt for device */ + writel(0, &priv_dev->regs->usb_ien); + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); + + return ret; +} + +static const struct usb_gadget_ops cdns3_gadget_ops = { + .get_frame = cdns3_gadget_get_frame, + .wakeup = cdns3_gadget_wakeup, + .set_selfpowered = cdns3_gadget_set_selfpowered, + .pullup = cdns3_gadget_pullup, + .udc_start = cdns3_gadget_udc_start, + .udc_stop = cdns3_gadget_udc_stop, + .match_ep = cdns3_gadget_match_ep, +}; + +static void cdns3_free_all_ep(struct cdns3_device *priv_dev) +{ + int i; + + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) + if (priv_dev->eps[i]) + devm_kfree(priv_dev->dev, priv_dev->eps[i]); + + if (priv_dev->gadget.ep0) + devm_kfree(priv_dev->dev, priv_dev->gadget.ep0); +} + +/** + * cdns3_init_ep Initializes software endpoints of gadget + * @cdns3: extended gadget object + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_init_ep(struct cdns3_device *priv_dev) +{ + u32 ep_enabled_reg, iso_ep_reg; + struct cdns3_endpoint *priv_ep; + int found_endpoints = 0; + int ep_dir, ep_number; + u32 ep_mask; + int i; + + /* Read it from USB_CAP3 to USB_CAP5 */ + ep_enabled_reg = readl(&priv_dev->regs->usb_cap3); + iso_ep_reg = readl(&priv_dev->regs->usb_cap4); + + dev_dbg(priv_dev->dev, "Initializing non-zero endpoints\n"); + + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { + ep_number = (i / 2) + 1; + ep_dir = i % 2; + ep_mask = BIT((16 * ep_dir) + ep_number); + + if (!(ep_enabled_reg & ep_mask)) + continue; + + priv_ep = devm_kzalloc(priv_dev->dev, sizeof(*priv_ep), + GFP_KERNEL); + if (!priv_ep) + return -ENOMEM; + + /* set parent of endpoint object */ + priv_ep->cdns3_dev = priv_dev; + priv_dev->eps[found_endpoints++] = priv_ep; + + snprintf(priv_ep->name, sizeof(priv_ep->name), "ep%d%s", + ep_number, !!ep_dir ? "in" : "out"); + priv_ep->endpoint.name = priv_ep->name; + + usb_ep_set_maxpacket_limit(&priv_ep->endpoint, + CDNS3_EP_MAX_PACKET_LIMIT); + priv_ep->endpoint.max_streams = CDNS3_EP_MAX_STREAMS; + priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; + if (ep_dir) + priv_ep->endpoint.caps.dir_in = 1; + else + priv_ep->endpoint.caps.dir_out = 1; + + if (iso_ep_reg & ep_mask) + priv_ep->endpoint.caps.type_iso = 1; + + priv_ep->endpoint.caps.type_bulk = 1; + priv_ep->endpoint.caps.type_int = 1; + priv_ep->endpoint.maxburst = CDNS3_EP_BUF_SIZE - 1; + + priv_ep->flags = 0; + + dev_info(priv_dev->dev, "Initialized %s support: %s %s\n", + priv_ep->name, + priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "", + priv_ep->endpoint.caps.type_iso ? "ISO" : ""); + + list_add_tail(&priv_ep->endpoint.ep_list, + &priv_dev->gadget.ep_list); + INIT_LIST_HEAD(&priv_ep->request_list); + } + + priv_dev->ep_nums = found_endpoints; + return 0; +} + +static void cdns3_gadget_disable(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + + priv_dev = cdns->gadget_dev; + + if (priv_dev->gadget_driver) + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); + + usb_gadget_disconnect(&priv_dev->gadget); + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; +} + +void cdns3_gadget_exit(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + + priv_dev = cdns->gadget_dev; + + cdns3_gadget_disable(cdns); + + devm_free_irq(cdns->dev, cdns->irq, cdns); + + pm_runtime_mark_last_busy(cdns->dev); + pm_runtime_put_autosuspend(cdns->dev); + + usb_del_gadget_udc(&priv_dev->gadget); + + cdns3_free_all_ep(priv_dev); + + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, + priv_dev->setup_dma); + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->ep0_trb, + priv_dev->ep0_trb_dma); + + kfree(priv_dev->zlp_buf); + kfree(priv_dev); + cdns->gadget_dev = NULL; +} + +static int cdns3_gadget_start(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + u32 max_speed; + int ret; + + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); + if (!priv_dev) + return -ENOMEM; + + cdns->gadget_dev = priv_dev; + priv_dev->sysdev = cdns->dev; + priv_dev->dev = cdns->dev; + priv_dev->regs = cdns->dev_regs; + + max_speed = usb_get_maximum_speed(cdns->dev); + + /* Check the maximum_speed parameter */ + switch (max_speed) { + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", + max_speed); + /* fall through */ + case USB_SPEED_UNKNOWN: + /* default to superspeed */ + max_speed = USB_SPEED_SUPER; + break; + } + + /* fill gadget fields */ + priv_dev->gadget.max_speed = max_speed; + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + priv_dev->gadget.ops = &cdns3_gadget_ops; + priv_dev->gadget.name = "usb-ss-gadget"; + priv_dev->gadget.sg_supported = 1; + + spin_lock_init(&priv_dev->lock); + INIT_WORK(&priv_dev->pending_status_wq, + cdns3_pending_setup_status_handler); + + /* initialize endpoint container */ + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); + + ret = cdns3_init_ep0(priv_dev); + if (ret) { + dev_err(priv_dev->dev, "Failed to create endpoint 0\n"); + goto err1; + } + + ret = cdns3_init_ep(priv_dev); + if (ret) { + dev_err(priv_dev->dev, "Failed to create non zero endpoints\n"); + goto err1; + } + + /* allocate memory for default endpoint TRB */ + priv_dev->ep0_trb = dma_alloc_coherent(priv_dev->sysdev, TRB_SIZE * 2, + &priv_dev->ep0_trb_dma, GFP_DMA); + if (!priv_dev->ep0_trb) { + dev_err(priv_dev->dev, "Failed to allocate memory for ep0 TRB\n"); + ret = -ENOMEM; + goto err1; + } + + /* allocate memory for setup packet buffer */ + priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, + &priv_dev->setup_dma, GFP_DMA); + if (!priv_dev->setup_buf) { + dev_err(priv_dev->dev, "Failed to allocate memory for SETUP buffer\n"); + ret = -ENOMEM; + goto err2; + } + + dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", + readl(&priv_dev->regs->usb_cap6)); + dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n", + readl(&priv_dev->regs->usb_cap1)); + dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n", + readl(&priv_dev->regs->usb_cap2)); + + priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL); + if (!priv_dev->zlp_buf) { + ret = -ENOMEM; + goto err3; + } + + /* add USB gadget device */ + ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); + if (ret < 0) { + dev_err(priv_dev->dev, + "Failed to register USB device controller\n"); + goto err4; + } + + return 0; +err4: + kfree(priv_dev->zlp_buf); +err3: + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, + priv_dev->setup_dma); +err2: + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->ep0_trb, + priv_dev->ep0_trb_dma); +err1: + cdns->gadget_dev = NULL; + return ret; +} + +static int __cdns3_gadget_init(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + unsigned long flags; + int ret = 0; + + ret = cdns3_gadget_start(cdns); + if (ret) + return ret; + + priv_dev = cdns->gadget_dev; + ret = devm_request_irq(cdns->dev, cdns->irq, cdns3_device_irq_handler, + IRQF_SHARED, dev_name(cdns->dev), cdns); + + if (ret) + goto err0; + + pm_runtime_get_sync(cdns->dev); + spin_lock_irqsave(&priv_dev->lock, flags); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +err0: + cdns3_gadget_exit(cdns); + return ret; +} + +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) +{ + cdns3_gadget_disable(cdns); + return 0; +} + +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) +{ + struct cdns3_device *priv_dev; + unsigned long flags; + + priv_dev = cdns->gadget_dev; + spin_lock_irqsave(&priv_dev->lock, flags); + + if (!priv_dev->gadget_driver) { + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; + } + + cdns3_gadget_config(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_init - initialize device structure + * + * cdns: cdns3 instance + * + * This function initializes the gadget. + */ +int cdns3_gadget_init(struct cdns3 *cdns) +{ + struct cdns3_role_driver *rdrv; + + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = __cdns3_gadget_init; + rdrv->stop = cdns3_gadget_exit; + rdrv->suspend = cdns3_gadget_suspend; + rdrv->resume = cdns3_gadget_resume; + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; + rdrv->name = "gadget"; + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; + + return 0; +} diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h new file mode 100644 index 000000000000..db398dff65fc --- /dev/null +++ b/drivers/usb/cdns3/gadget.h @@ -0,0 +1,1177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver header file + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2017-2018 NXP + * + * Author: Pawel Laszczak + * Pawel Jez + * Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET +#define __LINUX_CDNS3_GADGET +#include + +/* + * USBSS-DEV register interface. + * This corresponds to the USBSS Device Controller Interface + */ + +/** + * struct cdns3_usb_regs - device controller registers. + * @usb_conf: Global Configuration Register. + * @usb_sts: Global Status Register. + * @usb_cmd: Global Command Register. + * @usb_iptn: ITP/SOF number Register. + * @usb_lpm: Global Command Register. + * @usb_ien: USB Interrupt Enable Register. + * @usb_ists: USB Interrupt Status Register. + * @ep_sel: Endpoint Select Register. + * @ep_traddr: Endpoint Transfer Ring Address Register. + * @ep_cfg: Endpoint Configuration Register. + * @ep_cmd: Endpoint Command Register. + * @ep_sts: Endpoint Status Register. + * @ep_sts_sid: Endpoint Status Register. + * @ep_sts_en: Endpoint Status Register Enable. + * @drbl: Doorbell Register. + * @ep_ien: EP Interrupt Enable Register. + * @ep_ists: EP Interrupt Status Register. + * @usb_pwr: Global Power Configuration Register. + * @usb_conf2: Global Configuration Register 2. + * @usb_cap1: Capability Register 1. + * @usb_cap2: Capability Register 2. + * @usb_cap3: Capability Register 3. + * @usb_cap4: Capability Register 4. + * @usb_cap5: Capability Register 5. + * @usb_cap6: Capability Register 6. + * @usb_cpkt1: Custom Packet Register 1. + * @usb_cpkt2: Custom Packet Register 2. + * @usb_cpkt3: Custom Packet Register 3. + * @reserved1: Reserved. + * @cfg_regs: Configuration registers. + * @reserved2: Reserved. + * @dma_axi_ctrl: AXI Control register. + * @dma_axi_id: AXI ID register. + * @dma_axi_cap: AXI Capability register. + * @dma_axi_ctrl0: AXI Control 0 register. + * @dma_axi_ctrl1: AXI Control 1 register. + */ +struct cdns3_usb_regs { + __le32 usb_conf; + __le32 usb_sts; + __le32 usb_cmd; + __le32 usb_iptn; + __le32 usb_lpm; + __le32 usb_ien; + __le32 usb_ists; + __le32 ep_sel; + __le32 ep_traddr; + __le32 ep_cfg; + __le32 ep_cmd; + __le32 ep_sts; + __le32 ep_sts_sid; + __le32 ep_sts_en; + __le32 drbl; + __le32 ep_ien; + __le32 ep_ists; + __le32 usb_pwr; + __le32 usb_conf2; + __le32 usb_cap1; + __le32 usb_cap2; + __le32 usb_cap3; + __le32 usb_cap4; + __le32 usb_cap5; + __le32 usb_cap6; + __le32 usb_cpkt1; + __le32 usb_cpkt2; + __le32 usb_cpkt3; + __le32 reserved1[36]; + __le32 cfg_reg1; + __le32 dbg_link1; + __le32 dbg_link2; + __le32 cfg_regs[74]; + __le32 reserved2[34]; + __le32 dma_axi_ctrl; + __le32 dma_axi_id; + __le32 dma_axi_cap; + __le32 dma_axi_ctrl0; + __le32 dma_axi_ctrl1; +}; + +/* USB_CONF - bitmasks */ +/* Reset USB device configuration. */ +#define USB_CONF_CFGRST BIT(0) +/* Set Configuration. */ +#define USB_CONF_CFGSET BIT(1) +/* Disconnect USB device in SuperSpeed. */ +#define USB_CONF_USB3DIS BIT(3) +/* Disconnect USB device in HS/FS */ +#define USB_CONF_USB2DIS BIT(4) +/* Little Endian access - default */ +#define USB_CONF_LENDIAN BIT(5) +/* + * Big Endian access. Driver assume that byte order for + * SFRs access always is as Little Endian so this bit + * is not used. + */ +#define USB_CONF_BENDIAN BIT(6) +/* Device software reset. */ +#define USB_CONF_SWRST BIT(7) +/* Singular DMA transfer mode. */ +#define USB_CONF_DSING BIT(8) +/* Multiple DMA transfers mode. */ +#define USB_CONF_DMULT BIT(9) +/* DMA clock turn-off enable. */ +#define USB_CONF_DMAOFFEN BIT(10) +/* DMA clock turn-off disable. */ +#define USB_CONF_DMAOFFDS BIT(11) +/* Clear Force Full Speed. */ +#define USB_CONF_CFORCE_FS BIT(12) +/* Set Force Full Speed. */ +#define USB_CONF_SFORCE_FS BIT(13) +/* Device enable. */ +#define USB_CONF_DEVEN BIT(14) +/* Device disable. */ +#define USB_CONF_DEVDS BIT(15) +/* L1 LPM state entry enable (used in HS/FS mode). */ +#define USB_CONF_L1EN BIT(16) +/* L1 LPM state entry disable (used in HS/FS mode). */ +#define USB_CONF_L1DS BIT(17) +/* USB 2.0 clock gate disable. */ +#define USB_CONF_CLK2OFFEN BIT(18) +/* USB 2.0 clock gate enable. */ +#define USB_CONF_CLK2OFFDS BIT(19) +/* L0 LPM state entry request (used in HS/FS mode). */ +#define USB_CONF_LGO_L0 BIT(20) +/* USB 3.0 clock gate disable. */ +#define USB_CONF_CLK3OFFEN BIT(21) +/* USB 3.0 clock gate enable. */ +#define USB_CONF_CLK3OFFDS BIT(22) +/* Bit 23 is reserved*/ +/* U1 state entry enable (used in SS mode). */ +#define USB_CONF_U1EN BIT(24) +/* U1 state entry disable (used in SS mode). */ +#define USB_CONF_U1DS BIT(25) +/* U2 state entry enable (used in SS mode). */ +#define USB_CONF_U2EN BIT(26) +/* U2 state entry disable (used in SS mode). */ +#define USB_CONF_U2DS BIT(27) +/* U0 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U0 BIT(28) +/* U1 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U1 BIT(29) +/* U2 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U2 BIT(30) +/* SS.Inactive state entry request (used in SS mode) */ +#define USB_CONF_LGO_SSINACT BIT(31) + +/* USB_STS - bitmasks */ +/* + * Configuration status. + * 1 - device is in the configured state. + * 0 - device is not configured. + */ +#define USB_STS_CFGSTS_MASK BIT(0) +#define USB_STS_CFGSTS(p) ((p) & USB_STS_CFGSTS_MASK) +/* + * On-chip memory overflow. + * 0 - On-chip memory status OK. + * 1 - On-chip memory overflow. + */ +#define USB_STS_OV_MASK BIT(1) +#define USB_STS_OV(p) ((p) & USB_STS_OV_MASK) +/* + * SuperSpeed connection status. + * 0 - USB in SuperSpeed mode disconnected. + * 1 - USB in SuperSpeed mode connected. + */ +#define USB_STS_USB3CONS_MASK BIT(2) +#define USB_STS_USB3CONS(p) ((p) & USB_STS_USB3CONS_MASK) +/* + * DMA transfer configuration status. + * 0 - single request. + * 1 - multiple TRB chain + */ +#define USB_STS_DTRANS_MASK BIT(3) +#define USB_STS_DTRANS(p) ((p) & USB_STS_DTRANS_MASK) +/* + * Device speed. + * 0 - Undefined (value after reset). + * 1 - Low speed + * 2 - Full speed + * 3 - High speed + * 4 - Super speed + */ +#define USB_STS_USBSPEED_MASK GENMASK(6, 4) +#define USB_STS_USBSPEED(p) (((p) & USB_STS_USBSPEED_MASK) >> 4) +#define USB_STS_LS (0x1 << 4) +#define USB_STS_FS (0x2 << 4) +#define USB_STS_HS (0x3 << 4) +#define USB_STS_SS (0x4 << 4) +#define DEV_UNDEFSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == (0x0 << 4)) +#define DEV_LOWSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_LS) +#define DEV_FULLSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_FS) +#define DEV_HIGHSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_HS) +#define DEV_SUPERSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_SS) +/* + * Endianness for SFR access. + * 0 - Little Endian order (default after hardware reset). + * 1 - Big Endian order + */ +#define USB_STS_ENDIAN_MASK BIT(7) +#define USB_STS_ENDIAN(p) ((p) & USB_STS_ENDIAN_MASK) +/* + * HS/FS clock turn-off status. + * 0 - hsfs clock is always on. + * 1 - hsfs clock turn-off in L2 (HS/FS mode) is enabled + * (default after hardware reset). + */ +#define USB_STS_CLK2OFF_MASK BIT(8) +#define USB_STS_CLK2OFF(p) ((p) & USB_STS_CLK2OFF_MASK) +/* + * PCLK clock turn-off status. + * 0 - pclk clock is always on. + * 1 - pclk clock turn-off in U3 (SS mode) is enabled + * (default after hardware reset). + */ +#define USB_STS_CLK3OFF_MASK BIT(9) +#define USB_STS_CLK3OFF(p) ((p) & USB_STS_CLK3OFF_MASK) +/* + * Controller in reset state. + * 0 - Internal reset is active. + * 1 - Internal reset is not active and controller is fully operational. + */ +#define USB_STS_IN_RST_MASK BIT(10) +#define USB_STS_IN_RST(p) ((p) & USB_STS_IN_RST_MASK) +/* + * Device enable Status. + * 0 - USB device is disabled (VBUS input is disconnected from internal logic). + * 1 - USB device is enabled (VBUS input is connected to the internal logic). + */ +#define USB_STS_DEVS_MASK BIT(14) +#define USB_STS_DEVS(p) ((p) & USB_STS_DEVS_MASK) +/* + * DAddress statuss. + * 0 - USB device is default state. + * 1 - USB device is at least in address state. + */ +#define USB_STS_ADDRESSED_MASK BIT(15) +#define USB_STS_ADDRESSED(p) ((p) & USB_STS_ADDRESSED_MASK) +/* + * L1 LPM state enable status (used in HS/FS mode). + * 0 - Entering to L1 LPM state disabled. + * 1 - Entering to L1 LPM state enabled. + */ +#define USB_STS_L1ENS_MASK BIT(16) +#define USB_STS_L1ENS(p) ((p) & USB_STS_L1ENS_MASK) +/* + * Internal VBUS connection status (used both in HS/FS and SS mode). + * 0 - internal VBUS is not detected. + * 1 - internal VBUS is detected. + */ +#define USB_STS_VBUSS_MASK BIT(17) +#define USB_STS_VBUSS(p) ((p) & USB_STS_VBUSS_MASK) +/* + * HS/FS LPM state (used in FS/HS mode). + * 0 - L0 State + * 1 - L1 State + * 2 - L2 State + * 3 - L3 State + */ +#define USB_STS_LPMST_MASK GENMASK(19, 18) +#define DEV_L0_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x0 << 18)) +#define DEV_L1_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x1 << 18)) +#define DEV_L2_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x2 << 18)) +#define DEV_L3_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x3 << 18)) +/* + * Disable HS status (used in FS/HS mode). + * 0 - the disconnect bit for HS/FS mode is set . + * 1 - the disconnect bit for HS/FS mode is not set. + */ +#define USB_STS_USB2CONS_MASK BIT(20) +#define USB_STS_USB2CONS(p) ((p) & USB_STS_USB2CONS_MASK) +/* + * HS/FS mode connection status (used in FS/HS mode). + * 0 - High Speed operations in USB2.0 (FS/HS) mode not disabled. + * 1 - High Speed operations in USB2.0 (FS/HS). + */ +#define USB_STS_DISABLE_HS_MASK BIT(21) +#define USB_STS_DISABLE_HS(p) ((p) & USB_STS_DISABLE_HS_MASK) +/* + * U1 state enable status (used in SS mode). + * 0 - Entering to U1 state disabled. + * 1 - Entering to U1 state enabled. + */ +#define USB_STS_U1ENS_MASK BIT(24) +#define USB_STS_U1ENS(p) ((p) & USB_STS_U1ENS_MASK) +/* + * U2 state enable status (used in SS mode). + * 0 - Entering to U2 state disabled. + * 1 - Entering to U2 state enabled. + */ +#define USB_STS_U2ENS_MASK BIT(25) +#define USB_STS_U2ENS(p) ((p) & USB_STS_U2ENS_MASK) +/* + * SuperSpeed Link LTSSM state. This field reflects USBSS-DEV current + * SuperSpeed link state + */ +#define USB_STS_LST_MASK GENMASK(29, 26) +#define DEV_LST_U0 (((p) & USB_STS_LST_MASK) == (0x0 << 26)) +#define DEV_LST_U1 (((p) & USB_STS_LST_MASK) == (0x1 << 26)) +#define DEV_LST_U2 (((p) & USB_STS_LST_MASK) == (0x2 << 26)) +#define DEV_LST_U3 (((p) & USB_STS_LST_MASK) == (0x3 << 26)) +#define DEV_LST_DISABLED (((p) & USB_STS_LST_MASK) == (0x4 << 26)) +#define DEV_LST_RXDETECT (((p) & USB_STS_LST_MASK) == (0x5 << 26)) +#define DEV_LST_INACTIVE (((p) & USB_STS_LST_MASK) == (0x6 << 26)) +#define DEV_LST_POLLING (((p) & USB_STS_LST_MASK) == (0x7 << 26)) +#define DEV_LST_RECOVERY (((p) & USB_STS_LST_MASK) == (0x8 << 26)) +#define DEV_LST_HOT_RESET (((p) & USB_STS_LST_MASK) == (0x9 << 26)) +#define DEV_LST_COMP_MODE (((p) & USB_STS_LST_MASK) == (0xa << 26)) +#define DEV_LST_LB_STATE (((p) & USB_STS_LST_MASK) == (0xb << 26)) +/* + * DMA clock turn-off status. + * 0 - DMA clock is always on (default after hardware reset). + * 1 - DMA clock turn-off in U1, U2 and U3 (SS mode) is enabled. + */ +#define USB_STS_DMAOFF_MASK BIT(30) +#define USB_STS_DMAOFF(p) ((p) & USB_STS_DMAOFF_MASK) +/* + * SFR Endian statuss. + * 0 - Little Endian order (default after hardware reset). + * 1 - Big Endian order. + */ +#define USB_STS_ENDIAN2_MASK BIT(31) +#define USB_STS_ENDIAN2(p) ((p) & USB_STS_ENDIAN2_MASK) + +/* USB_CMD - bitmasks */ +/* Set Function Address */ +#define USB_CMD_SET_ADDR BIT(0) +/* + * Function Address This field is saved to the device only when the field + * SET_ADDR is set '1 ' during write to USB_CMD register. + * Software is responsible for entering the address of the device during + * SET_ADDRESS request service. This field should be set immediately after + * the SETUP packet is decoded, and prior to confirmation of the status phase + */ +#define USB_CMD_FADDR_MASK GENMASK(7, 1) +#define USB_CMD_FADDR(p) (((p) << 1) & USB_CMD_FADDR_MASK) +/* Send Function Wake Device Notification TP (used only in SS mode). */ +#define USB_CMD_SDNFW BIT(8) +/* Set Test Mode (used only in HS/FS mode). */ +#define USB_CMD_STMODE BIT(9) +/* Test mode selector (used only in HS/FS mode) */ +#define USB_STS_TMODE_SEL_MASK GENMASK(11, 10) +#define USB_STS_TMODE_SEL(p) (((p) << 10) & USB_STS_TMODE_SEL_MASK) +/* + * Send Latency Tolerance Message Device Notification TP (used only + * in SS mode). + */ +#define USB_CMD_SDNLTM BIT(12) +/* Send Custom Transaction Packet (used only in SS mode) */ +#define USB_CMD_SPKT BIT(13) +/*Device Notification 'Function Wake' - Interface value (only in SS mode. */ +#define USB_CMD_DNFW_INT_MASK GENMASK(23, 16) +#define USB_STS_DNFW_INT(p) (((p) << 16) & USB_CMD_DNFW_INT_MASK) +/* + * Device Notification 'Latency Tolerance Message' -373 BELT value [7:0] + * (used only in SS mode). + */ +#define USB_CMD_DNLTM_BELT_MASK GENMASK(27, 16) +#define USB_STS_DNLTM_BELT(p) (((p) << 16) & USB_CMD_DNLTM_BELT_MASK) + +/* USB_ITPN - bitmasks */ +/* + * ITP(SS) / SOF (HS/FS) number + * In SS mode this field represent number of last ITP received from host. + * In HS/FS mode this field represent number of last SOF received from host. + */ +#define USB_ITPN_MASK GENMASK(13, 0) +#define USB_ITPN(p) ((p) & USB_ITPN_MASK) + +/* USB_LPM - bitmasks */ +/* Host Initiated Resume Duration. */ +#define USB_LPM_HIRD_MASK GENMASK(3, 0) +#define USB_LPM_HIRD(p) ((p) & USB_LPM_HIRD_MASK) +/* Remote Wakeup Enable (bRemoteWake). */ +#define USB_LPM_BRW BIT(4) + +/* USB_IEN - bitmasks */ +/* SS connection interrupt enable */ +#define USB_IEN_CONIEN BIT(0) +/* SS disconnection interrupt enable. */ +#define USB_IEN_DISIEN BIT(1) +/* USB SS warm reset interrupt enable. */ +#define USB_IEN_UWRESIEN BIT(2) +/* USB SS hot reset interrupt enable */ +#define USB_IEN_UHRESIEN BIT(3) +/* SS link U3 state enter interrupt enable (suspend).*/ +#define USB_IEN_U3ENTIEN BIT(4) +/* SS link U3 state exit interrupt enable (wakeup). */ +#define USB_IEN_U3EXTIEN BIT(5) +/* SS link U2 state enter interrupt enable.*/ +#define USB_IEN_U2ENTIEN BIT(6) +/* SS link U2 state exit interrupt enable.*/ +#define USB_IEN_U2EXTIEN BIT(7) +/* SS link U1 state enter interrupt enable.*/ +#define USB_IEN_U1ENTIEN BIT(8) +/* SS link U1 state exit interrupt enable.*/ +#define USB_IEN_U1EXTIEN BIT(9) +/* ITP/SOF packet detected interrupt enable.*/ +#define USB_IEN_ITPIEN BIT(10) +/* Wakeup interrupt enable.*/ +#define USB_IEN_WAKEIEN BIT(11) +/* Send Custom Packet interrupt enable.*/ +#define USB_IEN_SPKTIEN BIT(12) +/* HS/FS mode connection interrupt enable.*/ +#define USB_IEN_CON2IEN BIT(16) +/* HS/FS mode disconnection interrupt enable.*/ +#define USB_IEN_DIS2IEN BIT(17) +/* USB reset (HS/FS mode) interrupt enable.*/ +#define USB_IEN_U2RESIEN BIT(18) +/* LPM L2 state enter interrupt enable.*/ +#define USB_IEN_L2ENTIEN BIT(20) +/* LPM L2 state exit interrupt enable.*/ +#define USB_IEN_L2EXTIEN BIT(21) +/* LPM L1 state enter interrupt enable.*/ +#define USB_IEN_L1ENTIEN BIT(24) +/* LPM L1 state exit interrupt enable.*/ +#define USB_IEN_L1EXTIEN BIT(25) +/* Configuration reset interrupt enable.*/ +#define USB_IEN_CFGRESIEN BIT(26) +/* Start of the USB SS warm reset interrupt enable.*/ +#define USB_IEN_UWRESSIEN BIT(28) +/* End of the USB SS warm reset interrupt enable.*/ +#define USB_IEN_UWRESEIEN BIT(29) + +#define USB_IEN_INIT (USB_IEN_U2RESIEN | USB_ISTS_DIS2I | USB_IEN_CON2IEN \ + | USB_IEN_UHRESIEN | USB_IEN_UWRESIEN | USB_IEN_DISIEN \ + | USB_IEN_CONIEN | USB_IEN_U3EXTIEN | USB_IEN_L2ENTIEN \ + | USB_IEN_L2EXTIEN) + +/* USB_ISTS - bitmasks */ +/* SS Connection detected. */ +#define USB_ISTS_CONI BIT(0) +/* SS Disconnection detected. */ +#define USB_ISTS_DISI BIT(1) +/* UUSB warm reset detectede. */ +#define USB_ISTS_UWRESI BIT(2) +/* USB hot reset detected. */ +#define USB_ISTS_UHRESI BIT(3) +/* U3 link state enter detected (suspend).*/ +#define USB_ISTS_U3ENTI BIT(4) +/* U3 link state exit detected (wakeup). */ +#define USB_ISTS_U3EXTI BIT(5) +/* U2 link state enter detected.*/ +#define USB_ISTS_U2ENTI BIT(6) +/* U2 link state exit detected.*/ +#define USB_ISTS_U2EXTI BIT(7) +/* U1 link state enter detected.*/ +#define USB_ISTS_U1ENTI BIT(8) +/* U1 link state exit detected.*/ +#define USB_ISTS_U1EXTI BIT(9) +/* ITP/SOF packet detected.*/ +#define USB_ISTS_ITPI BIT(10) +/* Wakeup detected.*/ +#define USB_ISTS_WAKEI BIT(11) +/* Send Custom Packet detected.*/ +#define USB_ISTS_SPKTI BIT(12) +/* HS/FS mode connection detected.*/ +#define USB_ISTS_CON2I BIT(16) +/* HS/FS mode disconnection detected.*/ +#define USB_ISTS_DIS2I BIT(17) +/* USB reset (HS/FS mode) detected.*/ +#define USB_ISTS_U2RESI BIT(18) +/* LPM L2 state enter detected.*/ +#define USB_ISTS_L2ENTI BIT(20) +/* LPM L2 state exit detected.*/ +#define USB_ISTS_L2EXTI BIT(21) +/* LPM L1 state enter detected.*/ +#define USB_ISTS_L1ENTI BIT(24) +/* LPM L1 state exit detected.*/ +#define USB_ISTS_L1EXTI BIT(25) +/* USB configuration reset detected.*/ +#define USB_ISTS_CFGRESI BIT(26) +/* Start of the USB warm reset detected.*/ +#define USB_ISTS_UWRESSI BIT(28) +/* End of the USB warm reset detected.*/ +#define USB_ISTS_UWRESEI BIT(29) + +/* USB_SEL - bitmasks */ +#define EP_SEL_EPNO_MASK GENMASK(3, 0) +/* Endpoint number. */ +#define EP_SEL_EPNO(p) ((p) & EP_SEL_EPNO_MASK) +/* Endpoint direction bit - 0 - OUT, 1 - IN. */ +#define EP_SEL_DIR BIT(7) + +#define select_ep_in(nr) (EP_SEL_EPNO(p) | EP_SEL_DIR) +#define select_ep_out (EP_SEL_EPNO(p)) + +/* EP_TRADDR - bitmasks */ +/* Transfer Ring address. */ +#define EP_TRADDR_TRADDR(p) ((p)) + +/* EP_CFG - bitmasks */ +/* Endpoint enable */ +#define EP_CFG_ENABLE BIT(0) +/* + * Endpoint type. + * 1 - isochronous + * 2 - bulk + * 3 - interrupt + */ +#define EP_CFG_EPTYPE_MASK GENMASK(2, 1) +#define EP_CFG_EPTYPE(p) (((p) << 1) & EP_CFG_EPTYPE_MASK) +/* Stream support enable (only in SS mode). */ +#define EP_CFG_STREAM_EN BIT(3) +/* TDL check (only in SS mode for BULK EP). */ +#define EP_CFG_TDL_CHK BIT(4) +/* SID check (only in SS mode for BULK OUT EP). */ +#define EP_CFG_SID_CHK BIT(5) +/* DMA transfer endianness. */ +#define EP_CFG_EPENDIAN BIT(7) +/* Max burst size (used only in SS mode). */ +#define EP_CFG_MAXBURST_MASK GENMASK(11, 8) +#define EP_CFG_MAXBURST(p) (((p) << 8) & EP_CFG_MAXBURST_MASK) +/* ISO max burst. */ +#define EP_CFG_MULT_MASK GENMASK(15, 14) +#define EP_CFG_MULT(p) (((p) << 14) & EP_CFG_MULT) +/* ISO max burst. */ +#define EP_CFG_MAXPKTSIZE_MASK GENMASK(26, 16) +#define EP_CFG_MAXPKTSIZE(p) (((p) << 16) & EP_CFG_MAXPKTSIZE_MASK) +/* Max number of buffered packets. */ +#define EP_CFG_BUFFERING_MASK GENMASK(31, 27) +#define EP_CFG_BUFFERING(p) (((p) << 27) & EP_CFG_BUFFERING_MASK) + +/* EP_CMD - bitmasks */ +/* Endpoint reset. */ +#define EP_CMD_EPRST BIT(0) +/* Endpoint STALL set. */ +#define EP_CMD_SSTALL BIT(1) +/* Endpoint STALL clear. */ +#define EP_CMD_CSTALL BIT(2) +/* Send ERDY TP. */ +#define EP_CMD_ERDY BIT(3) +/* Request complete. */ +#define EP_CMD_REQ_CMPL BIT(5) +/* Transfer descriptor ready. */ +#define EP_CMD_DRDY BIT(6) +/* Data flush. */ +#define EP_CMD_DFLUSH BIT(7) +/* + * Transfer Descriptor Length write (used only for Bulk Stream capable + * endpoints in SS mode). + */ +#define EP_CMD_STDL BIT(8) +/* Transfer Descriptor Length (used only in SS mode for bulk endpoints). */ +#define EP_CMD_TDL_MASK GENMASK(15, 9) +#define EP_CMD_TDL(p) (((p) << 9) & EP_CMD_TDL_MASK) +/* ERDY Stream ID value (used in SS mode). */ +#define EP_CMD_ERDY_SID_MASK GENMASK(31, 16) +#define EP_CMD_ERDY_SID(p) (((p) << 16) & EP_CMD_SID_MASK) + +/* EP_STS - bitmasks */ +/* Setup transfer complete. */ +#define EP_STS_SETUP BIT(0) +/* Endpoint STALL status. */ +#define EP_STS_STALL(p) ((p) & BIT(1)) +/* Interrupt On Complete. */ +#define EP_STS_IOC BIT(2) +/* Interrupt on Short Packet. */ +#define EP_STS_ISP BIT(3) +/* Transfer descriptor missing. */ +#define EP_STS_DESCMIS BIT(4) +/* Stream Rejected (used only in SS mode) */ +#define EP_STS_STREAMR BIT(5) +/* EXIT from MOVE DATA State (used only for stream transfers in SS mode). */ +#define EP_STS_MD_EXIT BIT(6) +/* TRB error. */ +#define EP_STS_TRBERR BIT(7) +/* Not ready (used only in SS mode). */ +#define EP_STS_NRDY BIT(8) +/* DMA busy. */ +#define EP_STS_DBUSY(p) ((p) & BIT(9)) +/* Endpoint Buffer Empty */ +#define EP_STS_BUFFEMPTY(p) ((p) & BIT(10)) +/* Current Cycle Status */ +#define EP_STS_CCS(p) ((p) & BIT(11)) +/* Prime (used only in SS mode. */ +#define EP_STS_PRIME BIT(12) +/* Stream error (used only in SS mode). */ +#define EP_STS_SIDERR BIT(13) +/* OUT size mismatch. */ +#define EP_STS_OUTSMM BIT(14) +/* ISO transmission error. */ +#define EP_STS_ISOERR BIT(15) +/* Host Packet Pending (only for SS mode). */ +#define EP_STS_HOSTPP(p) ((p) & BIT(16)) +/* Stream Protocol State Machine State (only for Bulk stream endpoints). */ +#define EP_STS_SPSMST_MASK GENMASK(18, 17) +#define EP_STS_SPSMST_DISABLED(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_IDLE(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_START_STREAM(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_MOVE_DATA(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +/* Interrupt On Transfer complete. */ +#define EP_STS_IOT BIT(19) +/* OUT queue endpoint number. */ +#define EP_STS_OUTQ_NO_MASK GENMASK(27, 24) +#define EP_STS_OUTQ_NO(p) (((p) & EP_STS_OUTQ_NO_MASK) >> 24) +/* OUT queue valid flag. */ +#define EP_STS_OUTQ_VAL_MASK BIT(28) +#define EP_STS_OUTQ_VAL(p) ((p) & EP_STS_OUTQ_VAL_MASK) +/* SETUP WAIT. */ +#define EP_STS_STPWAIT BIT(31) + +/* EP_STS_SID - bitmasks */ +/* Stream ID (used only in SS mode). */ +#define EP_STS_SID_MASK GENMASK(15, 0) +#define EP_STS_SID(p) ((p) & EP_STS_SID_MASK) + +/* EP_STS_EN - bitmasks */ +/* SETUP interrupt enable. */ +#define EP_STS_EN_SETUPEN BIT(0) +/* OUT transfer missing descriptor enable. */ +#define EP_STS_EN_DESCMISEN BIT(4) +/* Stream Rejected enable. */ +#define EP_STS_EN_STREAMREN BIT(5) +/* Move Data Exit enable.*/ +#define EP_STS_EN_MD_EXITEN BIT(6) +/* TRB enable. */ +#define EP_STS_EN_TRBERREN BIT(7) +/* NRDY enable. */ +#define EP_STS_EN_NRDYEN BIT(8) +/* Prime enable. */ +#define EP_STS_EN_PRIMEEEN BIT(12) +/* Stream error enable. */ +#define EP_STS_EN_SIDERREN BIT(13) +/* OUT size mismatch enable. */ +#define EP_STS_EN_OUTSMMEN BIT(14) +/* ISO transmission error enable. */ +#define EP_STS_EN_ISOERREN BIT(15) +/* Interrupt on Transmission complete enable. */ +#define EP_STS_EN_IOTEN BIT(19) +/* Setup Wait interrupt enable. */ +#define EP_STS_EN_STPWAITEN BIT(31) + +/* DRBL- bitmasks */ +#define DB_VALUE_BY_INDEX(index) (1 << (index)) +#define DB_VALUE_EP0_OUT BIT(0) +#define DB_VALUE_EP0_IN BIT(16) + +/* EP_IEN - bitmasks */ +#define EP_IEN(index) (1 << (index)) +#define EP_IEN_EP_OUT0 BIT(0) +#define EP_IEN_EP_IN0 BIT(16) + +/* EP_ISTS - bitmasks */ +#define EP_ISTS(index) (1 << (index)) +#define EP_ISTS_EP_OUT0 BIT(0) +#define EP_ISTS_EP_IN0 BIT(16) + +/* EP_PWR- bitmasks */ +/*Power Shut Off capability enable*/ +#define PUSB_PWR_PSO_EN BIT(0) +/*Power Shut Off capability disable*/ +#define PUSB_PWR_PSO_DS BIT(1) +/* + * Enables turning-off Reference Clock. + * This bit is optional and implemented only when support for OTG is + * implemented (indicated by OTG_READY bit set to '1'). + */ +#define PUSB_PWR_STB_CLK_SWITCH_EN BIT(8) +/* + * Status bit indicating that operation required by STB_CLK_SWITCH_EN write + * is completed + */ +#define PUSB_PWR_STB_CLK_SWITCH_DONE BIT(9) +/* This bit informs if Fast Registers Access is enabled. */ +#define PUSB_PWR_FST_REG_ACCESS_STAT BIT(30) +/* Fast Registers Access Enable. */ +#define PUSB_PWR_FST_REG_ACCESS BIT(31) + +/* USB_CAP1- bitmasks */ +/* + * SFR Interface type + * These field reflects type of SFR interface implemented: + * 0x0 - OCP + * 0x1 - AHB, + * 0x2 - PLB + * 0x3 - AXI + * 0x4-0xF - reserved + */ +#define USB_CAP1_SFR_TYPE_MASK GENMASK(3, 0) +#define DEV_SFR_TYPE_OCP(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x0) +#define DEV_SFR_TYPE_AHB(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x1) +#define DEV_SFR_TYPE_PLB(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x2) +#define DEV_SFR_TYPE_AXI(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x3) +/* + * SFR Interface width + * These field reflects width of SFR interface implemented: + * 0x0 - 8 bit interface, + * 0x1 - 16 bit interface, + * 0x2 - 32 bit interface + * 0x3 - 64 bit interface + * 0x4-0xF - reserved + */ +#define USB_CAP1_SFR_WIDTH_MASK GENMASK(7, 4) +#define DEV_SFR_WIDTH_8(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x0 << 4)) +#define DEV_SFR_WIDTH_16(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x1 << 4)) +#define DEV_SFR_WIDTH_32(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x2 << 4)) +#define DEV_SFR_WIDTH_64(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x3 << 4)) +/* + * DMA Interface type + * These field reflects type of DMA interface implemented: + * 0x0 - OCP + * 0x1 - AHB, + * 0x2 - PLB + * 0x3 - AXI + * 0x4-0xF - reserved + */ +#define USB_CAP1_DMA_TYPE_MASK GENMASK(11, 8) +#define DEV_DMA_TYPE_OCP(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x0 << 8)) +#define DEV_DMA_TYPE_AHB(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x1 << 8)) +#define DEV_DMA_TYPE_PLB(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x2 << 8)) +#define DEV_DMA_TYPE_AXI(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x3 << 8)) +/* + * DMA Interface width + * These field reflects width of DMA interface implemented: + * 0x0 - reserved, + * 0x1 - reserved, + * 0x2 - 32 bit interface + * 0x3 - 64 bit interface + * 0x4-0xF - reserved + */ +#define USB_CAP1_DMA_WIDTH_MASK GENMASK(15, 12) +#define DEV_DMA_WIDTH_32(p) (((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x2 << 12)) +#define DEV_DMA_WIDTH_64(p) (((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x3 << 12)) +/* + * USB3 PHY Interface type + * These field reflects type of USB3 PHY interface implemented: + * 0x0 - USB PIPE, + * 0x1 - RMMI, + * 0x2-0xF - reserved + */ +#define USB_CAP1_U3PHY_TYPE_MASK GENMASK(19, 16) +#define DEV_U3PHY_PIPE(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x0 << 16)) +#define DEV_U3PHY_RMMI(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x1 << 16)) +/* + * USB3 PHY Interface width + * These field reflects width of USB3 PHY interface implemented: + * 0x0 - 8 bit PIPE interface, + * 0x1 - 16 bit PIPE interface, + * 0x2 - 32 bit PIPE interface, + * 0x3 - 64 bit PIPE interface + * 0x4-0xF - reserved + * Note: When SSIC interface is implemented this field shows the width of + * internal PIPE interface. The RMMI interface is always 20bit wide. + */ +#define USB_CAP1_U3PHY_WIDTH_MASK GENMASK(23, 20) +#define DEV_U3PHY_WIDTH_8(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x0 << 20)) +#define DEV_U3PHY_WIDTH_16(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x1 << 16)) +#define DEV_U3PHY_WIDTH_32(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x2 << 20)) +#define DEV_U3PHY_WIDTH_64(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x3 << 16)) + +/* + * USB2 PHY Interface enable + * These field informs if USB2 PHY interface is implemented: + * 0x0 - interface NOT implemented, + * 0x1 - interface implemented + */ +#define USB_CAP1_U2PHY_EN(p) ((p) & BIT(24)) +/* + * USB2 PHY Interface type + * These field reflects type of USB2 PHY interface implemented: + * 0x0 - UTMI, + * 0x1 - ULPI + */ +#define DEV_U2PHY_ULPI(p) ((p) & BIT(25)) +/* + * USB2 PHY Interface width + * These field reflects width of USB2 PHY interface implemented: + * 0x0 - 8 bit interface, + * 0x1 - 16 bit interface, + * Note: The ULPI interface is always 8bit wide. + */ +#define DEV_U2PHY_WIDTH_16(p) ((p) & BIT(26)) +/* + * OTG Ready + * 0x0 - pure device mode + * 0x1 - some features and ports for CDNS USB OTG controller are implemented. + */ +#define USB_CAP1_OTG_READY(p) ((p) & BIT(27)) + +/* USB_CAP2- bitmasks */ +/* + * The actual size of the connected On-chip RAM memory in kB: + * - 0 means 256 kB (max supported mem size) + * - value other than 0 reflects the mem size in kB + */ +#define USB_CAP2_ACTUAL_MEM_SIZE(p) ((p) & GENMASK(7, 0)) +/* + * Max supported mem size + * These field reflects width of on-chip RAM address bus width, + * which determines max supported mem size: + * 0x0-0x7 - reserved, + * 0x8 - support for 4kB mem, + * 0x9 - support for 8kB mem, + * 0xA - support for 16kB mem, + * 0xB - support for 32kB mem, + * 0xC - support for 64kB mem, + * 0xD - support for 128kB mem, + * 0xE - support for 256kB mem, + * 0xF - reserved + */ +#define USB_CAP2_MAX_MEM_SIZE(p) ((p) & GENMASK(11, 8)) + +/* USB_CAP3- bitmasks */ +#define EP_IS_IMPLEMENTED(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP4- bitmasks */ +#define EP_SUPPORT_ISO(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP5- bitmasks */ +#define EP_SUPPORT_STREAM(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP6- bitmasks */ +/* The USBSS-DEV Controller Internal build number. */ +#define GET_DEV_VERSION__INTERNAL_NUMBER(p) ((p) & GENMASK(7, 0)) +/* The USBSS-DEV Controller version number. */ +#define GET_DEV_VERSION(p) ((p) & GENMASK(31, 8)) + +/* DBG_LINK1- bitmasks */ +/* + * LFPS_MIN_DET_U1_EXIT value This parameter configures the minimum + * time required for decoding the received LFPS as an LFPS.U1_Exit. + */ +#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT(p) ((p) & GENMASK(7, 0)) +/* + * LFPS_MIN_GEN_U1_EXIT value This parameter configures the minimum time for + * phytxelecidle deassertion when LFPS.U1_Exit + */ +#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT(p) (((p) << 8) & GENMASK(15, 8)) +/* + * RXDET_BREAK_DIS value This parameter configures terminating the Far-end + * Receiver termination detection sequence: + * 0: it is possible that USBSS_DEV will terminate Farend receiver + * termination detection sequence + * 1: USBSS_DEV will not terminate Far-end receiver termination + * detection sequence + */ +#define DBG_LINK1_RXDET_BREAK_DIS BIT(16) +/* LFPS_GEN_PING value This parameter configures the LFPS.Ping generation */ +#define DBG_LINK1_LFPS_GEN_PING(p) (((p) << 17) & GENMASK(21, 17)) +/* + * Set the LFPS_MIN_DET_U1_EXIT value Writing '1' to this bit writes the + * LFPS_MIN_DET_U1_EXIT field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT_SET BIT(24) +/* + * Set the LFPS_MIN_GEN_U1_EXIT value. Writing '1' to this bit writes the + * LFPS_MIN_GEN_U1_EXIT field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_SET BIT(25) +/* + * Set the RXDET_BREAK_DIS value Writing '1' to this bit writes + * the RXDET_BREAK_DIS field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_RXDET_BREAK_DIS_SET BIT(26) +/* + * Set the LFPS_GEN_PING_SET value Writing '1' to this bit writes + * the LFPS_GEN_PING field value to the device. This bit is automatically + * cleared. Writing '0' has no effect." + */ +#define DBG_LINK1_LFPS_GEN_PING_SET BIT(27) + +#define gadget_to_cdns3_device(g) (container_of(g, struct cdns3_device, gadget)) + +#define ep_to_cdns3_ep(ep) (container_of(ep, struct cdns3_endpoint, endpoint)) + +/*-------------------------------------------------------------------------*/ +/* + * USBSS-DEV DMA interface . + */ +#define TRBS_PER_SEGMENT 16 + +/** + * struct cdns3_trb - represent Transfer Descriptor block. + * @buffer: pointer to buffer data + * @length: length of data + * @control: control flags. + * + * This structure describes transfer block serviced by DMA module. + */ +struct cdns3_trb { + __le32 buffer; + __le32 length; + __le32 control; +}; + +#define TRB_SIZE (sizeof(struct cdns3_trb)) +#define TRB_RING_SIZE (TRB_SIZE * TRBS_PER_SEGMENT) + +/* TRB bit mask */ +#define TRB_TYPE_BITMASK GENMASK(15, 10) +#define TRB_TYPE(p) ((p) << 10) +#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) + +/* TRB type IDs */ +/* bulk, interrupt, isoc , and control data stage */ +#define TRB_NORMAL 1 +/* TRB for linking ring segments */ +#define TRB_LINK 6 + +/* Cycle bit - indicates TRB ownership by driver or hw*/ +#define TRB_CYCLE BIT(0) +/* + * When set to '1', the device will toggle its interpretation of the Cycle bit + */ +#define TRB_TOGGLE BIT(1) + +/* Interrupt on short packet*/ +#define TRB_ISP BIT(2) +/*Setting this bit enables FIFO DMA operation mode*/ +#define TRB_FIFO_MODE BIT(3) +/* Set PCIe no snoop attribute */ +#define TRB_CHAIN BIT(4) +/* Interrupt on completion */ +#define TRB_IOC BIT(5) + +/* stream ID bitmasks. */ +#define TRB_STREAM_ID(p) ((p) & GENMASK(31, 16)) + +/* transfer_len bitmasks. */ +#define TRB_LEN(p) ((p) & GENMASK(16, 0)) + +/* transfer_len bitmasks - bits 31:24 */ +#define TRB_BURST_LEN(p) ((p) & GENMASK(31, 24)) + +/* Data buffer pointer bitmasks*/ +#define TRB_BUFFER(p) ((p) & GENMASK(31, 0)) + +/*-------------------------------------------------------------------------*/ +/* Driver numeric constants */ + +/* Such declaration should be added to ch9.h */ +#define USB_DEVICE_MAX_ADDRESS 127 + +/* Endpoint init values */ +#define CDNS3_EP_MAX_PACKET_LIMIT 1024 +#define CDNS3_EP_MAX_STREAMS 15 + +#define CDNS3_EP0_MAX_PACKET_LIMIT 512 + +/* All endpoints except EP0 */ +#define CDNS3_ENDPOINTS_MAX_COUNT 30 + +#define CDNS3_EP_ZLP_BUF_SIZE 1024 + +/*-------------------------------------------------------------------------*/ +#define CDNS3_EP_BUF_SIZE 2 /* KB */ +#define CDNS3_ALIGNED_BUF_SIZE 16384 /* Bytes */ +#define CDNS3_DESCMIS_BUF_SIZE 65536 /* Bytes */ +/*-------------------------------------------------------------------------*/ +/* Used structs */ + +struct cdns3_device; + +/** + * struct cdns3_endpoint - extended device side representation of USB endpoint. + * @endpoint: usb endpoint + * @request_list: list of request for this endpoint + * @trb_pool: transfer ring - array of transaction buffers + * @trb_pool_dma: dma address of transfer ring + * @cdns3_dev: device associated with this endpoint + * @name: a human readable name e.g. ep1out + * @flags: specify the current state of endpoint + * @descmis_req: internal transfer object used for getting data from on-chip + * buffer. It can happen only if function driver doesn't send usb_request + * object on time. + * @descmis_pending: flag specify that internal buffer was used for DMA to + * take data from shared on-chip buffers to avoid blocking transfer to other + * endpoints. It indicate that is still in progress. + * @descmis_finished: flag specify that transfer has armed on descriptor + * missing event has been completed. If function driver requests + * the transfer then controller driver can just return this data. + * @aligned_buff: aligned to 8 bytes data buffer. Buffer address used in + * TRB shall be aligned to 8. + * @aligned_dma_addr: dma address of aligned_buff + * @dir: endpoint direction + * @num: endpoint number (1 - 15) + * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK + * @free_trbs: number of free TRBs in transfer ring + * @pcs: producer cycle state + * @ccs: consumer cycle state + * @enqueue: enqueue index in transfer ring + * @dequeue: dequeue index in transfer ring + */ +struct cdns3_endpoint { + struct usb_ep endpoint; + struct list_head request_list; + + struct cdns3_trb *trb_pool; + dma_addr_t trb_pool_dma; + + struct cdns3_device *cdns3_dev; + char name[20]; + +#define EP_ENABLED BIT(0) +#define EP_STALL BIT(1) +#define EP_WEDGE BIT(2) +#define EP_TRANSFER_STARTED BIT(3) +#define EP_UPDATE_EP_TRBADDR BIT(4) +#define EP_PENDING_REQUEST BIT(5) +#define EP_RING_FULL BIT(6) +#define EP_CLAIMED BIT(5) + u32 flags; + + struct cdns3_request *descmis_req; + u32 descmis_pending:1; + u32 descmis_finished:1; + + void *aligned_buff; + dma_addr_t aligned_dma_addr; + u8 dir; + u8 num; + u8 type; + + int free_trbs; + u8 pcs; + u8 ccs; + int enqueue; + int dequeue; +}; + +/** + * struct cdns3_request - extended device side representation of usb_request + * object . + * @request: generic usb_request object describing single I/O request. + * @priv_ep: extended representation of usb_ep object + * @trb: the first TRB association with this request + * @start_trb: number of the first TRB in transfer ring + * @end_trb: number of the last TRB in transfer ring + * @flags: flag specifying special usage of request + */ +struct cdns3_request { + struct usb_request request; + struct cdns3_endpoint *priv_ep; + struct cdns3_trb *trb; + int start_trb; + int end_trb; +#define REQUEST_PENDING BIT(0) +#define REQUEST_INTERNAL BIT(1) +#define REQUEST_ZLP BIT(2) + u32 flags; +}; + +#define to_cdns3_request(r) (container_of(r, struct cdns3_request, request)) + +/** + * struct cdns3_device - represent USB device. + * @dev: pointer to device structure associated whit this controller + * @sysdev: pointer to the DMA capable device + * @gadget: device side representation of the peripheral controller + * @gadget_driver: pointer to the gadget driver + * @lock: for synchronizing + * @regs: base address for device side registers + * @setup_buf: used while processing usb control requests + * @setup_dma: dma address for setup_buf + * @ep0_trb: TRB used for control transfer + * @ep0_trb_dma: dma address of ep0_trb + * @zlp_buf - zlp buffer + * @ep0_request: dummy request used while handling USB control request + * @ep0_data_dir: direction for control transfer + * @eps: array of pointers to all endpoints with exclusion ep0 + * @ep_nums: number of endpoints in eps + * @isoch_delay: value from Set Isoch Delay request. Only valid on SS/SSP. + * @u1_allowed: allow device transition to u1 state + * @u2_allowed: allow device transition to u2 state + * @is_selfpowered: device is self powered + * @setup_pending: setup packet is processing by gadget driver + * @hw_configured_flag: hardware endpoint configuration was set. + * @wake_up_flag: allow device to remote up the host + * @status_completion_no_call: indicate that driver is waiting for status s + * stage completion. It's used in deferred SET_CONFIGURATION request. + * @onchip_mem_allocated_size: actual size of on-chip memory assigned + * to endpoints + * @pending_status_wq: workqueue handling status stage for deferred requests. + * @pending_status_request: request for which status stage was deferred + */ +struct cdns3_device { + struct device *dev; + struct device *sysdev; + + struct usb_gadget gadget; + struct usb_gadget_driver *gadget_driver; + + /* generic spin-lock for drivers */ + spinlock_t lock; + + struct cdns3_usb_regs __iomem *regs; + + struct usb_ctrlrequest *setup_buf; + dma_addr_t setup_dma; + struct cdns3_trb *ep0_trb; + dma_addr_t ep0_trb_dma; + void *zlp_buf; + struct usb_request *ep0_request; + int ep0_data_dir; + + struct cdns3_endpoint *eps[CDNS3_ENDPOINTS_MAX_COUNT]; + int ep_nums; + + u32 selected_ep; + u16 isoch_delay; + + unsigned u1_allowed:1; + unsigned u2_allowed:1; + unsigned is_selfpowered:1; + unsigned setup_pending:1; + int hw_configured_flag:1; + int wake_up_flag:1; + unsigned status_completion_no_call:1; + + struct work_struct pending_status_wq; + struct usb_request *pending_status_request; + + /*in KB */ + int onchip_mem_allocated_size; +}; + +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec); +void cdns3_set_register_bit(void __iomem *ptr, u32 mask); +dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, + struct cdns3_trb *trb); +enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev); +void cdns3_pending_setup_status_handler(struct work_struct *work); +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev); +void cdns3_set_hw_configuration(struct cdns3_device *priv_dev); +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); +void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable); +struct usb_request *cdns3_next_request(struct list_head *list); +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + struct usb_request *request); +u8 cdns3_ep_addr_to_index(u8 ep_addr); +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep); +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value); +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags); +void cdns3_gadget_ep_free_request(struct usb_ep *ep, + struct usb_request *request); +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request); +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req, + int status); + +int cdns3_init_ep0(struct cdns3_device *priv_dev); +void cdns3_ep0_config(struct cdns3_device *priv_dev); +void cdns3_ep_config(struct cdns3_endpoint *priv_ep); +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir); + +#endif /* __LINUX_CDNS3_GADGET */ diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h new file mode 100644 index 000000000000..b498a170b7e8 --- /dev/null +++ b/drivers/usb/cdns3/host-export.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver - Host Export APIs + * + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + */ +#ifndef __LINUX_CDNS3_HOST_EXPORT +#define __LINUX_CDNS3_HOST_EXPORT + +#ifdef CONFIG_USB_CDNS3_HOST + +int cdns3_host_init(struct cdns3 *cdns); +void cdns3_host_exit(struct cdns3 *cdns); + +#else + +static inline int cdns3_host_init(struct cdns3 *cdns) +{ + return -ENXIO; +} + +static inline void cdns3_host_exit(struct cdns3 *cdns) { } + +#endif /* CONFIG_USB_CDNS3_HOST */ + +#endif /* __LINUX_CDNS3_HOST_EXPORT */ diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c new file mode 100644 index 000000000000..e16175e0328a --- /dev/null +++ b/drivers/usb/cdns3/host.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - host side + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + * Pawel Laszczak + */ + +#include +#include "core.h" + +static int __cdns3_host_init(struct cdns3 *cdns) +{ + struct platform_device *xhci; + int ret; + + xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); + if (!xhci) { + dev_err(cdns->dev, "couldn't allocate xHCI device\n"); + return -ENOMEM; + } + + xhci->dev.parent = cdns->dev; + cdns->host_dev = xhci; + + ret = platform_device_add_resources(xhci, cdns->xhci_res, + CDNS3_XHCI_RESOURCES_NUM); + if (ret) { + dev_err(cdns->dev, "couldn't add resources to xHCI device\n"); + goto err1; + } + + ret = platform_device_add(xhci); + if (ret) { + dev_err(cdns->dev, "failed to register xHCI device\n"); + goto err1; + } + + return 0; +err1: + platform_device_put(xhci); + return ret; +} + +static void cdns3_host_exit(struct cdns3 *cdns) +{ + platform_device_unregister(cdns->host_dev); + cdns->host_dev = NULL; +} + +int cdns3_host_init(struct cdns3 *cdns) +{ + struct cdns3_role_driver *rdrv; + + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = __cdns3_host_init; + rdrv->stop = cdns3_host_exit; + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; +#if CONFIG_PM + rdrv->suspend = NULL; + rdrv->resume = NULL; +#endif /* CONFIG_PM */ + rdrv->name = "host"; + + cdns->roles[CDNS3_ROLE_HOST] = rdrv; + + return 0; +} diff --git a/drivers/usb/cdns3/trace.c b/drivers/usb/cdns3/trace.c new file mode 100644 index 000000000000..587ae08e019d --- /dev/null +++ b/drivers/usb/cdns3/trace.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USBSS device controller driver Trace Support + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/cdns3/trace.h b/drivers/usb/cdns3/trace.h new file mode 100644 index 000000000000..a5c8b2a756b4 --- /dev/null +++ b/drivers/usb/cdns3/trace.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver. + * Trace support header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cdns3 + +#if !defined(__LINUX_CDNS3_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __LINUX_CDNS3_TRACE + +#include +#include +#include +#include "core.h" +#include "gadget.h" +#include "debug.h" + +#define CDNS3_MSG_MAX 500 + +DECLARE_EVENT_CLASS(cdns3_log_doorbell, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name), + TP_STRUCT__entry( + __field(const char *, ep_name) + ), + TP_fast_assign( + __entry->ep_name = ep_name; + ), + TP_printk("//Ding Dong %s", __entry->ep_name) +); + +DEFINE_EVENT(cdns3_log_doorbell, cdns3_doorbell_ep0, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name) +); + +DEFINE_EVENT(cdns3_log_doorbell, cdns3_doorbell_epx, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name) +); + +DECLARE_EVENT_CLASS(cdns3_log_usb_irq, + TP_PROTO(struct cdns3_device *priv_dev, u32 usb_ists), + TP_ARGS(priv_dev, usb_ists), + TP_STRUCT__entry( + __field(struct cdns3_device *, priv_dev) + __field(u32, usb_ists) + ), + TP_fast_assign( + __entry->priv_dev = priv_dev; + __entry->usb_ists = usb_ists; + ), + TP_printk("%s", cdns3_decode_usb_irq(__entry->priv_dev, + __entry->usb_ists)) +); + +DEFINE_EVENT(cdns3_log_usb_irq, cdns3_usb_irq, + TP_PROTO(struct cdns3_device *priv_dev, u32 usb_ists), + TP_ARGS(priv_dev, usb_ists) +); + +DECLARE_EVENT_CLASS(cdns3_log_epx_irq, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __field(struct cdns3_endpoint *, priv_ep) + ), + TP_fast_assign( + __entry->priv_ep = priv_ep; + ), + TP_printk("%s", cdns3_decode_epx_irq(__entry->priv_ep)) +); + +DEFINE_EVENT(cdns3_log_epx_irq, cdns3_epx_irq, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DECLARE_EVENT_CLASS(cdns3_log_ep0_irq, + TP_PROTO(struct cdns3_device *priv_dev), + TP_ARGS(priv_dev), + TP_STRUCT__entry( + __field(struct cdns3_device *, priv_dev) + ), + TP_fast_assign( + __entry->priv_dev = priv_dev; + ), + TP_printk("%s", cdns3_decode_ep0_irq(__entry->priv_dev)) +); + +DEFINE_EVENT(cdns3_log_ep0_irq, cdns3_ep0_irq, + TP_PROTO(struct cdns3_device *priv_dev), + TP_ARGS(priv_dev) +); + +DECLARE_EVENT_CLASS(cdns3_log_ctrl, + TP_PROTO(struct usb_ctrlrequest *ctrl), + TP_ARGS(ctrl), + TP_STRUCT__entry( + __field(u8, bRequestType) + __field(u8, bRequest) + __field(u16, wValue) + __field(u16, wIndex) + __field(u16, wLength) + __dynamic_array(char, str, CDNS3_MSG_MAX) + ), + TP_fast_assign( + __entry->bRequestType = ctrl->bRequestType; + __entry->bRequest = ctrl->bRequest; + __entry->wValue = le16_to_cpu(ctrl->wValue); + __entry->wIndex = le16_to_cpu(ctrl->wIndex); + __entry->wLength = le16_to_cpu(ctrl->wLength); + ), + TP_printk("%s", cdns3_decode_ctrl(__get_str(str), __entry->bRequestType, + __entry->bRequest, __entry->wValue, + __entry->wIndex, __entry->wLength) + ) +); + +DEFINE_EVENT(cdns3_log_ctrl, cdns3_ctrl_req, + TP_PROTO(struct usb_ctrlrequest *ctrl), + TP_ARGS(ctrl) +); + +DECLARE_EVENT_CLASS(cdns3_log_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req), + TP_STRUCT__entry( + __string(name, req->priv_ep->name) + __field(struct cdns3_request *, req) + __field(unsigned int, actual) + __field(unsigned int, length) + __field(int, status) + __field(int, zero) + __field(int, short_not_ok) + __field(int, no_interrupt) + __field(int, start_trb) + __field(int, end_trb) + __field(struct cdns3_trb *, start_trb_addr) + __field(int, flags) + ), + TP_fast_assign( + __assign_str(name, req->priv_ep->name); + __entry->req = req; + __entry->actual = req->request.actual; + __entry->length = req->request.length; + __entry->status = req->request.status; + __entry->zero = req->request.zero; + __entry->short_not_ok = req->request.short_not_ok; + __entry->no_interrupt = req->request.no_interrupt; + __entry->start_trb = req->start_trb; + __entry->end_trb = req->end_trb; + __entry->start_trb_addr = req->trb; + __entry->flags = req->flags; + ), + TP_printk("%s: req: %p, length: %u/%u %s%s%s, status: %d," + " trb: [start:%d, end:%d: virt addr %pa], flags:%x ", + __get_str(name), __entry->req, __entry->actual, __entry->length, + __entry->zero ? "zero | " : "", + __entry->short_not_ok ? "short | " : "", + __entry->no_interrupt ? "no int" : "", + __entry->status, + __entry->start_trb, + __entry->end_trb, + __entry->start_trb_addr, + __entry->flags + ) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_alloc_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_free_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_ep_queue, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_ep_dequeue, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_gadget_giveback, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DECLARE_EVENT_CLASS(cdns3_log_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb), + TP_STRUCT__entry( + __string(name, priv_ep->name) + __field(struct cdns3_trb *, trb) + __field(u32, buffer) + __field(u32, length) + __field(u32, control) + __field(u32, type) + ), + TP_fast_assign( + __assign_str(name, priv_ep->name); + __entry->trb = trb; + __entry->buffer = trb->buffer; + __entry->length = trb->length; + __entry->control = trb->control; + __entry->type = usb_endpoint_type(priv_ep->endpoint.desc); + ), + TP_printk("%s: trb 0x%pa, dma buf: 0x%08x, size: %ld, ctrl: 0x%08x (%s%s%s%s%s%s%s)", + __get_str(name), __entry->trb, __entry->buffer, + TRB_LEN(__entry->length), __entry->control, + __entry->control & TRB_CYCLE ? "C=1, " : "C=0, ", + __entry->control & TRB_TOGGLE ? "T=1, " : "T=0, ", + __entry->control & TRB_ISP ? "ISP, " : "", + __entry->control & TRB_FIFO_MODE ? "FIFO, " : "", + __entry->control & TRB_CHAIN ? "CHAIN, " : "", + __entry->control & TRB_IOC ? "IOC, " : "", + TRB_FIELD_TO_TYPE(__entry->control) == TRB_NORMAL ? "Normal" : "LINK" + ) +); + +DEFINE_EVENT(cdns3_log_trb, cdns3_prepare_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb) +); + +DEFINE_EVENT(cdns3_log_trb, cdns3_complete_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb) +); + +DECLARE_EVENT_CLASS(cdns3_log_ring, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __field(struct cdns3_endpoint *, priv_ep) + __field(int, free_trbs) + __field(u8, pcs) + __field(u8, ccs) + __field(int, enqueue) + __field(int, dequeue) + __dynamic_array(u32, ring, TRB_RING_SIZE) + __dynamic_array(char, buffer, + (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX) + ), + TP_fast_assign( + __entry->priv_ep = priv_ep; + __entry->free_trbs = priv_ep->free_trbs; + __entry->pcs = priv_ep->pcs; + __entry->ccs = priv_ep->ccs; + __entry->enqueue = priv_ep->enqueue; + __entry->dequeue = priv_ep->dequeue; + memcpy(__get_dynamic_array(ring), priv_ep->trb_pool, + TRB_RING_SIZE); + ), + + TP_printk("%s", + cdns3_dbg_ring(__entry->priv_ep, __entry->free_trbs, + __entry->pcs, __entry->ccs, + __entry->enqueue, __entry->dequeue, + (struct cdns3_trb *)__get_str(ring), + __get_str(buffer))) +); + +DEFINE_EVENT(cdns3_log_ring, cdns3_ring, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DECLARE_EVENT_CLASS(cdns3_log_ep, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __string(name, priv_ep->name) + __field(unsigned int, maxpacket) + __field(unsigned int, maxpacket_limit) + __field(unsigned int, max_streams) + __field(unsigned int, maxburst) + __field(unsigned int, flags) + __field(unsigned int, dir) + __field(u8, enqueue) + __field(u8, dequeue) + ), + TP_fast_assign( + __assign_str(name, priv_ep->name); + __entry->maxpacket = priv_ep->endpoint.maxpacket; + __entry->maxpacket_limit = priv_ep->endpoint.maxpacket_limit; + __entry->max_streams = priv_ep->endpoint.max_streams; + __entry->maxburst = priv_ep->endpoint.maxburst; + __entry->flags = priv_ep->flags; + __entry->dir = priv_ep->dir; + __entry->enqueue = priv_ep->enqueue; + __entry->dequeue = priv_ep->dequeue; + ), + TP_printk("%s: mps: %d/%d. streams: %d, burst: %d, enq idx: %d, " + "deq idx: %d, flags %s%s%s%s%s%s%s%s, dir: %s", + __get_str(name), __entry->maxpacket, + __entry->maxpacket_limit, __entry->max_streams, + __entry->maxburst, __entry->enqueue, + __entry->dequeue, + __entry->flags & EP_ENABLED ? "EN | " : "", + __entry->flags & EP_STALL ? "STALL | " : "", + __entry->flags & EP_WEDGE ? "WEDGE | " : "", + __entry->flags & EP_TRANSFER_STARTED ? "STARTED | " : "", + __entry->flags & EP_UPDATE_EP_TRBADDR ? "UPD TRB | " : "", + __entry->flags & EP_PENDING_REQUEST ? "REQ PEN | " : "", + __entry->flags & EP_RING_FULL ? "RING FULL |" : "", + __entry->flags & EP_CLAIMED ? "CLAIMED " : "", + __entry->dir ? "IN" : "OUT" + ) +); + +DEFINE_EVENT(cdns3_log_ep, cdns3_gadget_ep_enable, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DEFINE_EVENT(cdns3_log_ep, cdns3_gadget_ep_disable, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); +#endif /* __LINUX_CDNS3_TRACE */ + +/* this part must be outside header guard */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include -- 2.17.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pawel Laszczak Subject: [PATCH v1 2/2] usb:cdns3 Add Cadence USB3 DRD Driver Date: Mon, 10 Dec 2018 12:39:15 +0000 Message-ID: <1544445555-17325-3-git-send-email-pawell@cadence.com> References: <1544445555-17325-1-git-send-email-pawell@cadence.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: In-Reply-To: <1544445555-17325-1-git-send-email-pawell@cadence.com> Sender: linux-kernel-owner@vger.kernel.org To: devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, balbi@kernel.org, rogerq@ti.com, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com, Pawel Laszczak List-Id: devicetree@vger.kernel.org This patch introduce new Cadence USBSS DRD driver to linux kernel. The Cadence USBSS DRD Driver is a highly configurable IP Core which can be instantiated as Dual-Role Device (DRD), Peripheral Only and Host Only (XHCI) configurations. The current driver has been validated with FPGA burned. We have support for PCIe bus, which is used on FPGA prototyping. The host side of USBSS-DRD controller is compliance with XHCI specification, so it works with standard XHCI linux driver. Signed-off-by: Pawel Laszczak --- drivers/usb/Kconfig | 2 + drivers/usb/Makefile | 2 + drivers/usb/cdns3/Kconfig | 44 + drivers/usb/cdns3/Makefile | 16 + drivers/usb/cdns3/cdns3-pci-wrap.c | 157 +++ drivers/usb/cdns3/core.c | 451 +++++++ drivers/usb/cdns3/core.h | 108 ++ drivers/usb/cdns3/debug.h | 346 ++++++ drivers/usb/cdns3/debugfs.c | 168 +++ drivers/usb/cdns3/drd.c | 315 +++++ drivers/usb/cdns3/drd.h | 129 ++ drivers/usb/cdns3/ep0.c | 864 +++++++++++++ drivers/usb/cdns3/gadget-export.h | 28 + drivers/usb/cdns3/gadget.c | 1802 ++++++++++++++++++++++++++++ drivers/usb/cdns3/gadget.h | 1177 ++++++++++++++++++ drivers/usb/cdns3/host-export.h | 28 + drivers/usb/cdns3/host.c | 74 ++ drivers/usb/cdns3/trace.c | 11 + drivers/usb/cdns3/trace.h | 343 ++++++ 19 files changed, 6065 insertions(+) create mode 100644 drivers/usb/cdns3/Kconfig create mode 100644 drivers/usb/cdns3/Makefile create mode 100644 drivers/usb/cdns3/cdns3-pci-wrap.c create mode 100644 drivers/usb/cdns3/core.c create mode 100644 drivers/usb/cdns3/core.h create mode 100644 drivers/usb/cdns3/debug.h create mode 100644 drivers/usb/cdns3/debugfs.c create mode 100644 drivers/usb/cdns3/drd.c create mode 100644 drivers/usb/cdns3/drd.h create mode 100644 drivers/usb/cdns3/ep0.c create mode 100644 drivers/usb/cdns3/gadget-export.h create mode 100644 drivers/usb/cdns3/gadget.c create mode 100644 drivers/usb/cdns3/gadget.h create mode 100644 drivers/usb/cdns3/host-export.h create mode 100644 drivers/usb/cdns3/host.c create mode 100644 drivers/usb/cdns3/trace.c create mode 100644 drivers/usb/cdns3/trace.h diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 987fc5ba6321..5f9334019d04 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" endif +source "drivers/usb/cdns3/Kconfig" + source "drivers/usb/mtu3/Kconfig" source "drivers/usb/musb/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 7d1b8c82b208..ab125b966cac 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_ISP1760) += isp1760/ +obj-$(CONFIG_USB_CDNS3) += cdns3/ + obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MTU3) += mtu3/ diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig new file mode 100644 index 000000000000..4adfd87811e8 --- /dev/null +++ b/drivers/usb/cdns3/Kconfig @@ -0,0 +1,44 @@ +config USB_CDNS3 + tristate "Cadence USB3 Dual-Role Controller" + depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA + help + Say Y here if your system has a cadence USB3 dual-role controller. + It supports: dual-role switch, Host-only, and Peripheral-only. + + If you choose to build this driver is a dynamically linked + module, the module will be called cdns3.ko. + +if USB_CDNS3 + +config USB_CDNS3_GADGET + bool "Cadence USB3 device controller" + depends on USB_GADGET + help + Say Y here to enable device controller functionality of the + cadence USBSS-DEV driver. + + This controller supports FF, HS and SS mode. It doesn't support + LS and SSP mode + +config USB_CDNS3_HOST + bool "Cadence USB3 host controller" + depends on USB_XHCI_HCD + help + Say Y here to enable host controller functionality of the + cadence driver. + + Host controller is compliance with XHCI so it will use + standard XHCI driver. + +config USB_CDNS3_PCI_WRAP + tristate "Cadence USB3 support on PCIe-based platforms" + depends on USB_PCI && ACPI + default USB_CDNS3 + help + If you're using the USBSS Core IP with a PCIe, please say + 'Y' or 'M' here. + + If you choose to build this driver as module it will + be dynamically linked and module will be called cdns3-pci.ko + +endif diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile new file mode 100644 index 000000000000..3f63baa24294 --- /dev/null +++ b/drivers/usb/cdns3/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# define_trace.h needs to know how to find our header +CFLAGS_trace.o := -I$(src) + +obj-$(CONFIG_USB_CDNS3) += cdns3.o +obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci.o + +cdns3-y := core.o drd.o trace.o + +ifneq ($(CONFIG_DEBUG_FS),) + cdns3-y += debugfs.o +endif + +cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o +cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o +cdns3-pci-y := cdns3-pci-wrap.o diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c new file mode 100644 index 000000000000..e93179c45ece --- /dev/null +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS PCI Glue driver + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +struct cdns3_wrap { + struct platform_device *plat_dev; + struct pci_dev *hg_dev; + struct resource dev_res[4]; +}; + +struct cdns3_wrap wrap; + +#define RES_IRQ_ID 0 +#define RES_HOST_ID 1 +#define RES_DEV_ID 2 +#define RES_DRD_ID 3 + +#define PCI_BAR_HOST 0 +#define PCI_BAR_DEV 2 +#define PCI_BAR_OTG 4 + +#define PCI_DEV_FN_HOST_DEVICE 0 +#define PCI_DEV_FN_OTG 1 + +#define PCI_DRIVER_NAME "cdns3-pci-usbss" +#define PLAT_DRIVER_NAME "cdns-usb3" + +#define CDNS_VENDOR_ID 0x17cd +#define CDNS_DEVICE_ID 0x0100 + +/** + * cdns3_pci_probe - Probe function for Cadence USB wrapper driver + * @pdev: platform device object + * @id: pci device id + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct platform_device_info plat_info; + struct cdns3_wrap *wrap; + struct resource *res; + int err; + + /* + * for GADGET/HOST PCI (devfn) function number is 0, + * for OTG PCI (devfn) function number is 1 + */ + if (!id || pdev->devfn != PCI_DEV_FN_HOST_DEVICE) + return -EINVAL; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); + return err; + } + + pci_set_master(pdev); + wrap = devm_kzalloc(&pdev->dev, sizeof(*wrap), GFP_KERNEL); + if (!wrap) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + /* function 0: host(BAR_0) + device(BAR_1) + otg(BAR_2)). */ + memset(wrap->dev_res, 0x00, + sizeof(struct resource) * ARRAY_SIZE(wrap->dev_res)); + dev_dbg(&pdev->dev, "Initialize Device resources\n"); + res = wrap->dev_res; + + res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV); + res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV); + res[RES_DEV_ID].name = "cdns3-dev-regs"; + res[RES_DEV_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n", + &res[RES_DEV_ID].start); + + res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST); + res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST); + res[RES_HOST_ID].name = "cdns3-xhci-regs"; + res[RES_HOST_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n", + &res[RES_HOST_ID].start); + + res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG); + res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG); + res[RES_DRD_ID].name = "cdns3-otg"; + res[RES_DRD_ID].flags = IORESOURCE_MEM; + dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n", + &res[RES_DRD_ID].start); + + /* Interrupt common for both device and XHCI */ + wrap->dev_res[RES_IRQ_ID].start = pdev->irq; + wrap->dev_res[RES_IRQ_ID].name = "cdns3-irq"; + wrap->dev_res[RES_IRQ_ID].flags = IORESOURCE_IRQ; + + /* set up platform device info */ + memset(&plat_info, 0, sizeof(plat_info)); + plat_info.parent = &pdev->dev; + plat_info.fwnode = pdev->dev.fwnode; + plat_info.name = PLAT_DRIVER_NAME; + plat_info.id = pdev->devfn; + plat_info.res = wrap->dev_res; + plat_info.num_res = ARRAY_SIZE(wrap->dev_res); + plat_info.dma_mask = pdev->dma_mask; + + /* register platform device */ + wrap->plat_dev = platform_device_register_full(&plat_info); + if (IS_ERR(wrap->plat_dev)) { + err = PTR_ERR(wrap->plat_dev); + return err; + } + + pci_set_drvdata(pdev, wrap); + + return err; +} + +void cdns3_pci_remove(struct pci_dev *pdev) +{ + struct cdns3_wrap *wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev); + + platform_device_unregister(wrap->plat_dev); +} + +static const struct pci_device_id cdns3_pci_ids[] = { + { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, + { 0, } +}; + +static struct pci_driver cdns3_pci_driver = { + .name = PCI_DRIVER_NAME, + .id_table = cdns3_pci_ids, + .probe = cdns3_pci_probe, + .remove = cdns3_pci_remove, +}; + +module_pci_driver(cdns3_pci_driver); +MODULE_DEVICE_TABLE(pci, cdns3_pci_ids); + +MODULE_AUTHOR("Pawel Laszczak "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr"); + diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c new file mode 100644 index 000000000000..b93e3788bd33 --- /dev/null +++ b/drivers/usb/cdns3/core.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2017-2018 NXP + * + * Author: Peter Chen + * Pawel Laszczak + */ + +#include +#include +#include +#include +#include +#include + +#include "gadget.h" +#include "core.h" +#include "host-export.h" +#include "gadget-export.h" +#include "drd.h" +#include "debug.h" + +static inline +struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) +{ + WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]); + return cdns->roles[cdns->role]; +} + +static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role) +{ + int ret; + + if (WARN_ON(role >= CDNS3_ROLE_END)) + return 0; + + if (!cdns->roles[role]) + return -ENXIO; + + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE) + return 0; + + mutex_lock(&cdns->mutex); + cdns->role = role; + ret = cdns->roles[role]->start(cdns); + if (!ret) + cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE; + mutex_unlock(&cdns->mutex); + return ret; +} + +void cdns3_role_stop(struct cdns3 *cdns) +{ + enum cdns3_roles role = cdns->role; + + if (role >= CDNS3_ROLE_END) { + WARN_ON(role > CDNS3_ROLE_END); + return; + } + + if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE) + return; + + mutex_lock(&cdns->mutex); + cdns->roles[role]->stop(cdns); + cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE; + mutex_unlock(&cdns->mutex); +} + +/* + * cdns->role gets from cdns3_get_initial_role, and this API tells role at the + * runtime. + * If both roles are supported, the role is selected based on vbus/id. + * It could be read from OTG register or external connector. + * If only single role is supported, only one role structure + * is allocated, cdns->roles[CDNS3_ROLE_HOST] or cdns->roles[CDNS3_ROLE_GADGET]. + */ +static enum cdns3_roles cdns3_get_initial_role(struct cdns3 *cdns) +{ + if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) { + if (cdns3_is_host(cdns)) + return CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + return CDNS3_ROLE_GADGET; + } + return cdns->roles[CDNS3_ROLE_HOST] + ? CDNS3_ROLE_HOST + : CDNS3_ROLE_GADGET; +} + +static void cdns3_exit_roles(struct cdns3 *cdns) +{ + cdns3_role_stop(cdns); + cdns3_drd_exit(cdns); +} + +/** + * cdns3_core_init_role - initialize role of operation + * @cdns: Pointer to cdns3 structure + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_core_init_role(struct cdns3 *cdns) +{ + struct device *dev = cdns->dev; + enum usb_dr_mode best_dr_mode; + enum usb_dr_mode dr_mode; + int ret = 0; + + dr_mode = usb_get_dr_mode(dev); + cdns->role = CDNS3_ROLE_END; + + /* + * If driver can't read mode by means of usb_get_dr_mdoe function then + * chooses mode according with Kernel configuration. This setting + * can be restricted later depending on strap pin configuration. + */ + if (dr_mode == USB_DR_MODE_UNKNOWN) { + if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && + IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_OTG; + else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + dr_mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) + dr_mode = USB_DR_MODE_PERIPHERAL; + } + + best_dr_mode = USB_DR_MODE_OTG; + + if (dr_mode == USB_DR_MODE_OTG) { + best_dr_mode = cdns->dr_mode; + } else if (cdns->dr_mode == USB_DR_MODE_OTG) { + best_dr_mode = dr_mode; + } else if (cdns->dr_mode != dr_mode) { + dev_err(dev, "Incorrect DRD configuration\n"); + return -EINVAL; + } + + dr_mode = best_dr_mode; + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { + ret = cdns3_host_init(cdns); + if (ret) { + dev_err(dev, "Host initialization failed with %d\n", + ret); + goto err; + } + } + + if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { + ret = cdns3_gadget_init(cdns); + if (ret) { + dev_err(dev, "Device initialization failed with %d\n", + ret); + goto err; + } + } + + cdns->desired_dr_mode = dr_mode; + cdns->dr_mode = dr_mode; + /* + * dr_mode could be change so DRD must update controller + * configuration + */ + ret = cdns3_drd_update_mode(cdns); + + cdns->role = cdns3_get_initial_role(cdns); + + ret = cdns3_role_start(cdns, cdns->role); + if (ret) { + dev_err(dev, "can't start %s role\n", + cdns3_get_current_role_driver(cdns)->name); + goto err; + } + + return ret; +err: + cdns3_exit_roles(cdns); + return ret; +} + +/** + * cdsn3_get_real_role - get real role of controller based on hardware settings. + * @cdns: Pointer to cdns3 structure + * + * Returns role + */ +enum cdns3_roles cdsn3_get_real_role(struct cdns3 *cdns) +{ + enum cdns3_roles role = CDNS3_ROLE_END; + + if (cdns->current_dr_mode == USB_DR_MODE_OTG) { + if (cdns3_get_id(cdns)) + role = CDNS3_ROLE_GADGET; + else + role = CDNS3_ROLE_HOST; + } else { + if (cdns3_is_host(cdns)) + role = CDNS3_ROLE_HOST; + if (cdns3_is_device(cdns)) + role = CDNS3_ROLE_GADGET; + } + + return role; +} + +/** + * cdns3_role_switch - work queue handler for role switch + * + * @work: work queue item structure + * + * Handles below events: + * - Role switch for dual-role devices + * - CDNS3_ROLE_GADGET <--> CDNS3_ROLE_END for peripheral-only devices + */ +static void cdns3_role_switch(struct work_struct *work) +{ + enum cdns3_roles role = CDNS3_ROLE_END; + struct cdns3_role_driver *role_drv; + enum cdns3_roles current_role; + struct cdns3 *cdns; + int ret = 0; + + cdns = container_of(work, struct cdns3, role_switch_wq); + + /* During switching cdns->role can be different then role */ + role = cdsn3_get_real_role(cdns); + + role_drv = cdns3_get_current_role_driver(cdns); + + pm_runtime_get_sync(cdns->dev); + + /* Disable current role. This state can be forced from user space. */ + if (cdns->debug_disable && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) { + cdns3_role_stop(cdns); + goto exit; + } + + /* Do nothing if nothing changed */ + if (cdns->role == role && role_drv->state == CDNS3_ROLE_STATE_ACTIVE) + goto exit; + + cdns3_role_stop(cdns); + + role = cdsn3_get_real_role(cdns); + + current_role = cdns->role; + dev_dbg(cdns->dev, "Switching role"); + + ret = cdns3_role_start(cdns, role); + + if (ret) { + /* Back to current role */ + dev_err(cdns->dev, "set %d has failed, back to %d\n", + role, current_role); + cdns3_role_start(cdns, current_role); + } +exit: + pm_runtime_put_sync(cdns->dev); +} + +/** + * cdns3_probe - probe for cdns3 core device + * @pdev: Pointer to cdns3 core platform device + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct cdns3 *cdns; + void __iomem *regs; + int ret; + + cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); + if (!cdns) + return -ENOMEM; + + cdns->dev = dev; + + platform_set_drvdata(pdev, cdns); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + cdns->irq = res->start; + + cdns->xhci_res[0] = *res; + + /* + * Request memory region + * region-0: xHCI + * region-1: Peripheral + * region-2: OTG registers + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cdns->xhci_res[1] = *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + cdns->dev_regs = regs; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + cdns->otg_regs = regs; + + mutex_init(&cdns->mutex); + + cdns->phy = devm_phy_get(dev, "cdns3,usbphy"); + if (IS_ERR(cdns->phy)) { + ret = PTR_ERR(cdns->phy); + if (ret == -ENOSYS || ret == -ENODEV) { + cdns->phy = NULL; + } else if (ret == -EPROBE_DEFER) { + return ret; + } else { + dev_err(dev, "no phy found\n"); + goto err0; + } + } + + phy_init(cdns->phy); + + INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch); + + ret = cdns3_drd_init(cdns); + if (ret) + goto err1; + + ret = cdns3_core_init_role(cdns); + if (ret) + goto err1; + + cdns3_debugfs_init(cdns); + device_set_wakeup_capable(dev, true); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + /* + * The controller needs less time between bus and controller suspend, + * and we also needs a small delay to avoid frequently entering low + * power mode. + */ + pm_runtime_set_autosuspend_delay(dev, 20); + pm_runtime_mark_last_busy(dev); + pm_runtime_use_autosuspend(dev); + dev_dbg(dev, "Cadence USB3 core: probe succeed\n"); + + return 0; + +err1: + phy_exit(cdns->phy); +err0: + return ret; +} + +/** + * cdns3_remove - unbind drd driver and clean up + * @pdev: Pointer to Linux platform device + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_remove(struct platform_device *pdev) +{ + struct cdns3 *cdns = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + cdns3_debugfs_exit(cdns); + cdns3_exit_roles(cdns); + phy_exit(cdns->phy); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id of_cdns3_match[] = { + { .compatible = "cdns,usb3" }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_cdns3_match); +#endif + +#ifdef CONFIG_PM + +#ifdef CONFIG_PM_SLEEP +static int cdns3_suspend(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} + +static int cdns3_resume(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ +static int cdns3_runtime_suspend(struct device *dev) +{ /* TODO: Implements this function. */ + return 0; +} + +static int cdns3_runtime_resume(struct device *dev) +{ + /* TODO: Implements this function. */ + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops cdns3_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cdns3_suspend, cdns3_resume) + SET_RUNTIME_PM_OPS(cdns3_runtime_suspend, cdns3_runtime_resume, NULL) +}; + +static struct platform_driver cdns3_driver = { + .probe = cdns3_probe, + .remove = cdns3_remove, + .driver = { + .name = "cdns-usb3", + .of_match_table = of_match_ptr(of_cdns3_match), + .pm = &cdns3_pm_ops, + }, +}; + +static int __init cdns3_driver_platform_register(void) +{ + return platform_driver_register(&cdns3_driver); +} +module_init(cdns3_driver_platform_register); + +static void __exit cdns3_driver_platform_unregister(void) +{ + platform_driver_unregister(&cdns3_driver); +} +module_exit(cdns3_driver_platform_unregister); + +MODULE_ALIAS("platform:cdns3"); +MODULE_AUTHOR("Pawel Laszczak "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver"); diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h new file mode 100644 index 000000000000..ffd1971ff893 --- /dev/null +++ b/drivers/usb/cdns3/core.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Header File. + * + * Copyright (C) 2017-2018 NXP + * Copyright (C) 2018 Cadence. + * + * Authors: Peter Chen + * Pawel Laszczak + */ +#include + +#ifndef __LINUX_CDNS3_CORE_H +#define __LINUX_CDNS3_CORE_H + +struct cdns3; +enum cdns3_roles { + CDNS3_ROLE_HOST = 0, + CDNS3_ROLE_GADGET, + CDNS3_ROLE_END, +}; + +/** + * struct cdns3_role_driver - host/gadget role driver + * @start: start this role + * @stop: stop this role + * @suspend: suspend callback for this role + * @resume: resume callback for this role + * @irq: irq handler for this role + * @name: role name string (host/gadget) + * @state: current state + */ +struct cdns3_role_driver { + int (*start)(struct cdns3 *cdns); + void (*stop)(struct cdns3 *cdns); + int (*suspend)(struct cdns3 *cdns, bool do_wakeup); + int (*resume)(struct cdns3 *cdns, bool hibernated); + const char *name; +#define CDNS3_ROLE_STATE_INACTIVE 0 +#define CDNS3_ROLE_STATE_ACTIVE 1 + int state; +}; + +#define CDNS3_XHCI_RESOURCES_NUM 2 +/** + * struct cdns3 - Representation of Cadence USB3 DRD controller. + * @dev: pointer to Cadence device struct + * @xhci_regs: pointer to base of xhci registers + * @xhci_res: the resource for xhci + * @dev_regs: pointer to base of dev registers + * @otg_regs: pointer to base of otg registers + * @irq: irq number for controller + * @roles: array of supported roles for this controller + * @role: current role + * @host_dev: the child host device pointer for cdns3 core + * @gadget_dev: the child gadget device pointer for cdns3 core + * @usb: phy for this controller + * @role_switch_wq: work queue item for role switch + * @in_lpm: the controller in low power mode + * @wakeup_int: the wakeup interrupt + * @mutex: the mutex for concurrent code at driver + * @dr_mode: supported mode of operation it can be only Host, only Device + * or OTG mode that allow to switch between Device and Host mode. + * This field based on firmware setting, kernel configuration + * and hardware configuration. + * @current_dr_mode: current mode of operation when in dual-role mode + * @desired_dr_mode: desired mode of operation when in dual-role mode. + * This value can be changed during runtime. + * Available options depends on dr_mode: + * dr_mode | desired_dr_mode and current_dr_mode + * ---------------------------------------------------------------- + * USB_DR_MODE_HOST | only USB_DR_MODE_HOST + * USB_DR_MODE_PERIPHERAL | only USB_DR_MODE_PERIPHERAL + * USB_DR_MODE_OTG | only USB_DR_MODE_HOST + * USB_DR_MODE_OTG | only USB_DR_MODE_PERIPHERAL + * USB_DR_MODE_OTG | USB_DR_MODE_OTG + * + * Desired_dr_role can be changed by means of debugfs. + * @root: debugfs root folder pointer + * @debug_disable: + */ +struct cdns3 { + struct device *dev; + void __iomem *xhci_regs; + struct resource xhci_res[CDNS3_XHCI_RESOURCES_NUM]; + struct cdns3_usb_regs __iomem *dev_regs; + struct cdns3_otg_regs *otg_regs; + int irq; + struct cdns3_role_driver *roles[CDNS3_ROLE_END]; + enum cdns3_roles role; + struct platform_device *host_dev; + struct cdns3_device *gadget_dev; + struct phy *phy; + struct work_struct role_switch_wq; + int in_lpm:1; + int wakeup_int:1; + /* mutext used in workqueue*/ + struct mutex mutex; + enum usb_dr_mode dr_mode; + enum usb_dr_mode current_dr_mode; + enum usb_dr_mode desired_dr_mode; + struct dentry *root; + int debug_disable:1; +}; + +void cdns3_role_stop(struct cdns3 *cdns); + +#endif /* __LINUX_CDNS3_CORE_H */ diff --git a/drivers/usb/cdns3/debug.h b/drivers/usb/cdns3/debug.h new file mode 100644 index 000000000000..afb81d224718 --- /dev/null +++ b/drivers/usb/cdns3/debug.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver. + * Debug header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ +#ifndef __LINUX_CDNS3_DEBUG +#define __LINUX_CDNS3_DEBUG +#include "gadget.h" + +static inline void cdns3_decode_get_status(u8 bRequestType, u16 wIndex, + u16 wLength, char *str) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + sprintf(str, "Get Interface Status Intf = %d, L: = %d", + wIndex, wLength); + break; + case USB_RECIP_ENDPOINT: + sprintf(str, "Get Endpoint Status ep%d%s", + wIndex & ~USB_DIR_IN, + wIndex & USB_DIR_IN ? "in" : "out"); + break; + } +} + +static inline const char *cdns3_decode_device_feature(u16 wValue) +{ + switch (wValue) { + case USB_DEVICE_SELF_POWERED: + return "Self Powered"; + case USB_DEVICE_REMOTE_WAKEUP: + return "Remote Wakeup"; + case USB_DEVICE_TEST_MODE: + return "Test Mode"; + case USB_DEVICE_U1_ENABLE: + return "U1 Enable"; + case USB_DEVICE_U2_ENABLE: + return "U2 Enable"; + case USB_DEVICE_LTM_ENABLE: + return "LTM Enable"; + default: + return "UNKNOWN"; + } +} + +static inline const char *cdns3_decode_test_mode(u16 wIndex) +{ + switch (wIndex) { + case TEST_J: + return ": TEST_J"; + case TEST_K: + return ": TEST_K"; + case TEST_SE0_NAK: + return ": TEST_SE0_NAK"; + case TEST_PACKET: + return ": TEST_PACKET"; + case TEST_FORCE_EN: + return ": TEST_FORCE_EN"; + default: + return ": UNKNOWN"; + } +} + +static inline void cdns3_decode_set_clear_feature(u8 bRequestType, u8 bRequest, + u16 wValue, u16 wIndex, + char *str) +{ + switch (bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + sprintf(str, "%s Device Feature(%s%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + cdns3_decode_device_feature(wValue), + wValue == USB_DEVICE_TEST_MODE ? + cdns3_decode_test_mode(wIndex) : ""); + break; + case USB_RECIP_INTERFACE: + sprintf(str, "%s Interface Feature(%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + wIndex == USB_INTRF_FUNC_SUSPEND ? + "Function Suspend" : "UNKNOWN"); + break; + case USB_RECIP_ENDPOINT: + sprintf(str, "%s Endpoint Feature(%s ep%d%s)", + bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", + wIndex == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", + wIndex & ~USB_DIR_IN, + wIndex & USB_DIR_IN ? "in" : "out"); + break; + } +} + +static inline const char *cdns3_decode_descriptor(u16 wValue) +{ + switch (wValue >> 8) { + case USB_DT_DEVICE: + return "Device"; + case USB_DT_CONFIG: + return "Configuration"; + case USB_DT_STRING: + return "String"; + case USB_DT_INTERFACE: + return "Interface"; + case USB_DT_ENDPOINT: + return "Endpoint"; + case USB_DT_DEVICE_QUALIFIER: + return "Device Qualifier"; + case USB_DT_OTHER_SPEED_CONFIG: + return "Other Speed Config"; + case USB_DT_INTERFACE_POWER: + return "Interface Power"; + case USB_DT_OTG: + return "OTG"; + case USB_DT_DEBUG: + return "Debug"; + case USB_DT_INTERFACE_ASSOCIATION: + return "Interface Association"; + case USB_DT_BOS: + return "BOS"; + case USB_DT_DEVICE_CAPABILITY: + return "Device Capability"; + case USB_DT_SS_ENDPOINT_COMP: + return "SS Endpoint Companion"; + case USB_DT_SSP_ISOC_ENDPOINT_COMP: + return "SSP Isochronous Endpoint Companion"; + default: + return "UNKNOWN"; + } +} + +/** + * cdns3_decode_ctrl - returns a string represetion of ctrl request + */ +static inline const char *cdns3_decode_ctrl(char *str, u8 bRequestType, + u8 bRequest, u16 wValue, + u16 wIndex, u16 wLength) +{ + switch (bRequest) { + case USB_REQ_GET_STATUS: + cdns3_decode_get_status(bRequestType, wIndex, + wLength, str); + break; + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + cdns3_decode_set_clear_feature(bRequestType, bRequest, + wValue, wIndex, str); + break; + case USB_REQ_SET_ADDRESS: + sprintf(str, "Set Address Addr: %02x", wValue); + break; + case USB_REQ_GET_DESCRIPTOR: + sprintf(str, "GET %s Descriptor I: %d, L: %d", + cdns3_decode_descriptor(wValue), + wValue & 0xff, wLength); + break; + case USB_REQ_SET_DESCRIPTOR: + sprintf(str, "SET %s Descriptor I: %d, L: %d", + cdns3_decode_descriptor(wValue), + wValue & 0xff, wLength); + break; + case USB_REQ_GET_CONFIGURATION: + sprintf(str, "Get Configuration L: %d", wLength); + break; + case USB_REQ_SET_CONFIGURATION: + sprintf(str, "Set Configuration Config: %d ", wValue); + break; + case USB_REQ_GET_INTERFACE: + sprintf(str, "Get Interface Intf: %d, L: %d", wIndex, wLength); + break; + case USB_REQ_SET_INTERFACE: + sprintf(str, "Set Interface Intf: %d, Alt: %d", wIndex, wValue); + break; + case USB_REQ_SYNCH_FRAME: + sprintf(str, "Synch Frame Ep: %d, L: %d", wIndex, wLength); + break; + case USB_REQ_SET_SEL: + sprintf(str, "Set SEL L: %d", wLength); + break; + case USB_REQ_SET_ISOCH_DELAY: + sprintf(str, "Set Isochronous Delay Delay: %d ns", wValue); + break; + default: + sprintf(str, + "SETUP BRT: %02x BR: %02x V: %04x I: %04x L: %04x\n", + bRequestType, bRequest, + wValue, wIndex, wLength); + } + + return str; +} + +static inline char *cdns3_decode_usb_irq(struct cdns3_device *priv_dev, + u32 usb_ists) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ %08x = ", usb_ists); + + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { + u32 speed = cdns3_get_speed(priv_dev); + + ret += sprintf(str + ret, "Connection %s\n", + usb_speed_string(speed)); + } + if (usb_ists & USB_ISTS_CON2I || usb_ists & USB_ISTS_CONI) + ret += sprintf(str + ret, "Disconnection "); + if (usb_ists & USB_ISTS_L2ENTI) + ret += sprintf(str + ret, "suspended "); + + if (usb_ists & USB_ISTS_L2EXTI) + ret += sprintf(str + ret, "L2 exit "); + if (usb_ists & USB_ISTS_U3EXTI) + ret += sprintf(str + ret, "U3 exit "); + if (usb_ists & USB_ISTS_UWRESI) + ret += sprintf(str + ret, "Warm Reset "); + if (usb_ists & USB_ISTS_UHRESI) + ret += sprintf(str + ret, "Hot Reset "); + if (usb_ists & USB_ISTS_U2RESI) + ret += sprintf(str + ret, "Reset"); + + return str; +} + +static inline char *cdns3_decode_ep_irq(u32 ep_sts, const char *ep_name) +{ + static char str[256]; + int ret; + + ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts); + + if (ep_sts & EP_STS_SETUP) + ret += sprintf(str + ret, "SETUP "); + if (ep_sts & EP_STS_IOC) + ret += sprintf(str + ret, "IOC "); + if (ep_sts & EP_STS_ISP) + ret += sprintf(str + ret, "ISP "); + if (ep_sts & EP_STS_DESCMIS) + ret += sprintf(str + ret, "DESCMIS "); + if (ep_sts & EP_STS_STREAMR) + ret += sprintf(str + ret, "STREAMR "); + if (ep_sts & EP_STS_MD_EXIT) + ret += sprintf(str + ret, "MD_EXIT "); + if (ep_sts & EP_STS_TRBERR) + ret += sprintf(str + ret, "TRBERR "); + if (ep_sts & EP_STS_NRDY) + ret += sprintf(str + ret, "NRDY "); + if (ep_sts & EP_STS_PRIME) + ret += sprintf(str + ret, "PRIME "); + if (ep_sts & EP_STS_SIDERR) + ret += sprintf(str + ret, "SIDERRT "); + if (ep_sts & EP_STS_OUTSMM) + ret += sprintf(str + ret, "OUTSMM "); + if (ep_sts & EP_STS_ISOERR) + ret += sprintf(str + ret, "ISOERR "); + if (ep_sts & EP_STS_IOT) + ret += sprintf(str + ret, "IOT "); + + return str; +} + +static inline char *cdns3_decode_epx_irq(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + priv_ep->name); +} + +static inline char *cdns3_decode_ep0_irq(struct cdns3_device *priv_dev) +{ + if (priv_dev->ep0_data_dir) + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0IN"); + else + return cdns3_decode_ep_irq(readl(&priv_dev->regs->ep_sts), + "ep0OUT"); +} + +/** + * Debug a transfer ring. + * + * Prints out all TRBs in the endpoint ring, even those after the Link TRB. + *. + */ +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, + int free_trbs, u8 pcs, u8 ccs, + int enqueue, int dequeue, + struct cdns3_trb *ring, char *str) +{ + u64 addr = priv_ep->trb_pool_dma; + struct cdns3_trb *trb; + int ret = 0; + int i; + + trb = &ring[priv_ep->dequeue]; + ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name); + + ret += sprintf(str + ret, + "\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n", + dequeue, trb, + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); + + trb = &ring[priv_ep->enqueue]; + ret += sprintf(str + ret, + "\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n", + enqueue, trb, + (unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb)); + + ret += sprintf(str + ret, + "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", free_trbs, ccs, + pcs); + + if (TRBS_PER_SEGMENT > 64) { + sprintf(str + ret, "\t\tTo big transfer ring %d\n", + TRBS_PER_SEGMENT); + return str; + } + + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &ring[i]; + ret += sprintf(str + ret, + "\t\t@%016llx %08x %08x %08x\n", addr, + le32_to_cpu(trb->buffer), + le32_to_cpu(trb->length), + le32_to_cpu(trb->control)); + addr += sizeof(*trb); + } + + return str; +} + +#ifdef CONFIG_DEBUG_FS +void cdns3_debugfs_init(struct cdns3 *cdns); +void cdns3_debugfs_exit(struct cdns3 *cdns); +#else +void cdns3_debugfs_init(struct cdns3 *cdns); +{ } +void cdns3_debugfs_exit(struct cdns3 *cdns); +{ } +#endif + +#endif /*__LINUX_CDNS3_DEBUG*/ diff --git a/drivers/usb/cdns3/debugfs.c b/drivers/usb/cdns3/debugfs.c new file mode 100644 index 000000000000..d7919f5c1d90 --- /dev/null +++ b/drivers/usb/cdns3/debugfs.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Controller DebugFS filer. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#include +#include +#include +#include + +#include "core.h" +#include "gadget.h" +#include "drd.h" + +static int cdns3_mode_show(struct seq_file *s, void *unused) +{ + struct cdns3 *cdns = s->private; + + switch (cdns->current_dr_mode) { + case USB_DR_MODE_HOST: + seq_puts(s, "host\n"); + break; + case USB_DR_MODE_PERIPHERAL: + seq_puts(s, "device\n"); + break; + case USB_DR_MODE_OTG: + seq_puts(s, "otg\n"); + break; + default: + seq_puts(s, "UNKNOWN mode\n"); + } + + return 0; +} + +static int cdns3_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_mode_show, inode->i_private); +} + +static ssize_t cdns3_mode_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3 *cdns = s->private; + u32 mode = USB_DR_MODE_UNKNOWN; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "host", 4)) { + if (cdns->dr_mode == USB_DR_MODE_HOST || + cdns->dr_mode == USB_DR_MODE_OTG) { + mode = USB_DR_MODE_HOST; + } + } + + if (!strncmp(buf, "device", 6)) + if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL || + cdns->dr_mode == USB_DR_MODE_OTG) + mode = USB_DR_MODE_PERIPHERAL; + + if (!strncmp(buf, "otg", 3) && cdns->dr_mode == USB_DR_MODE_OTG) + mode = USB_DR_MODE_OTG; + + if (mode == USB_DR_MODE_UNKNOWN) { + dev_err(cdns->dev, "Failed: incorrect mode setting\n"); + return -EFAULT; + } + + if (cdns->current_dr_mode != mode) { + cdns->desired_dr_mode = mode; + cdns->debug_disable = 0; + cdns3_role_stop(cdns); + cdns3_drd_update_mode(cdns); + queue_work(system_freezable_wq, &cdns->role_switch_wq); + } + + return count; +} + +static const struct file_operations cdns3_mode_fops = { + .open = cdns3_mode_open, + .write = cdns3_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int cdns3_disable_show(struct seq_file *s, void *unused) +{ + struct cdns3 *cdns = s->private; + + if (!cdns->debug_disable) + seq_puts(s, "0\n"); + else + seq_puts(s, "1\n"); + + return 0; +} + +static ssize_t cdns3_disable_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct cdns3 *cdns = s->private; + int disable; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1) || !strncmp(buf, "yes", 3)) { + disable = 1; + } else if (!strncmp(buf, "0", 1) || !strncmp(buf, "no", 2)) { + disable = 0; + } else { + dev_err(cdns->dev, "Failed: incorrect disable setting\n"); + return -EFAULT; + } + + if (disable != cdns->debug_disable) { + cdns->debug_disable = disable; + queue_work(system_freezable_wq, &cdns->role_switch_wq); + } + + return count; +} + +static int cdns3_disable_open(struct inode *inode, struct file *file) +{ + return single_open(file, cdns3_disable_show, inode->i_private); +} + +static const struct file_operations cdns3_disable_fops = { + .open = cdns3_disable_open, + .write = cdns3_disable_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void cdns3_debugfs_init(struct cdns3 *cdns) +{ + struct dentry *root; + + root = debugfs_create_dir(dev_name(cdns->dev), NULL); + cdns->root = root; + if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) && + IS_ENABLED(CONFIG_USB_CDNS3_HOST)) + debugfs_create_file("mode", 0644, root, cdns, + &cdns3_mode_fops); + + debugfs_create_file("disable", 0644, root, cdns, + &cdns3_disable_fops); +} + +void cdns3_debugfs_exit(struct cdns3 *cdns) +{ + debugfs_remove_recursive(cdns->root); +} diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c new file mode 100644 index 000000000000..45573427ba83 --- /dev/null +++ b/drivers/usb/cdns3/drd.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak +#include +#include +#include + +#include "gadget.h" +#include "drd.h" +#include "core.h" + +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on); + +/** + * cdns3_set_mode - change mode of OTG Core + * @cdns: pointer to context structure + * @mode: selected mode from cdns_role + */ +void cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) +{ + u32 reg; + + cdns->current_dr_mode = mode; + + switch (mode) { + case USB_DR_MODE_PERIPHERAL: + dev_info(cdns->dev, "Set controller to Gadget mode\n"); + cdns3_drd_switch_gadget(cdns, 1); + break; + case USB_DR_MODE_HOST: + dev_info(cdns->dev, "Set controller to Host mode\n"); + cdns3_drd_switch_host(cdns, 1); + break; + case USB_DR_MODE_OTG: + dev_info(cdns->dev, "Set controller to OTG mode\n"); + reg = readl(&cdns->otg_regs->override); + reg |= OVERRIDE_IDPULLUP; + writel(reg, &cdns->otg_regs->override); + + /* + * Hardware specification says: "ID_VALUE must be valid within + * 50ms after idpullup is set to '1" so driver must wait + * 50ms before reading this pin. + */ + usleep_range(50000, 60000); + break; + default: + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; + dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode); + return; + } +} + +int cdns3_get_id(struct cdns3 *cdns) +{ + int id; + + id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE; + dev_dbg(cdns->dev, "OTG ID: %d", id); + return id; +} + +int cdns3_is_host(struct cdns3 *cdns) +{ + if (cdns->current_dr_mode == USB_DR_MODE_HOST) + return 1; + else if (!cdns3_get_id(cdns)) + return 1; + + return 0; +} + +int cdns3_is_device(struct cdns3 *cdns) +{ + if (cdns->current_dr_mode == USB_DR_MODE_PERIPHERAL) + return 1; + else if (cdns->current_dr_mode == USB_DR_MODE_OTG) + if (cdns3_get_id(cdns)) + return 1; + + return 0; +} + +/** + * cdns3_otg_disable_irq - Disable all OTG interrupts + * @cdns: Pointer to controller context structure + */ +static void cdns3_otg_disable_irq(struct cdns3 *cdns) +{ + writel(0, &cdns->otg_regs->ien); +} + +/** + * cdns3_otg_enable_irq - enable id and sess_valid interrupts + * @cdns: Pointer to controller context structure + */ +static void cdns3_otg_enable_irq(struct cdns3 *cdns) +{ + writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT | + OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien); +} + +/** + * cdns3_drd_switch_host - start/stop host + * @cdns: Pointer to controller context structure + * @on: 1 for start, 0 for stop + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_drd_switch_host(struct cdns3 *cdns, int on) +{ + int ret; + u32 reg = OTGCMD_OTG_DIS; + + /* switch OTG core */ + if (on) { + writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); + + dev_dbg(cdns->dev, "Waiting for Host mode is turned on\n"); + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_XHCI_READY, + OTGSTS_XHCI_READY, 100000); + + if (ret) + return ret; + } else { + usleep_range(30, 40); + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + } + + return 0; +} + +/** + * cdns3_drd_switch_gadget - start/stop gadget + * @cdns: Pointer to controller context structure + * @on: 1 for start, 0 for stop + * + * Returns 0 on success otherwise negative errno + */ +static int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) +{ + int ret; + u32 reg = OTGCMD_OTG_DIS; + + /* switch OTG core */ + if (on) { + writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); + + dev_dbg(cdns->dev, "Waiting for Device mode is turned on\n"); + + ret = cdns3_handshake(&cdns->otg_regs->sts, OTGSTS_DEV_READY, + OTGSTS_DEV_READY, 100000); + + if (ret) + return ret; + } else { + /* + * driver should wait at least 10us after disabling Device + * before turning-off Device (DEV_BUS_DROP) + */ + usleep_range(20, 30); + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + } + + return 0; +} + +/** + * cdns3_init_otg_mode - initialize drd controller + * @cdns: Pointer to controller context structure + * + * Returns 0 on success otherwise negative errno + */ +static void cdns3_init_otg_mode(struct cdns3 *cdns) +{ + cdns3_otg_disable_irq(cdns); + /* clear all interrupts */ + writel(~0, &cdns->otg_regs->ivect); + + cdns3_set_mode(cdns, USB_DR_MODE_OTG); + + if (cdns3_is_host(cdns)) + cdns3_drd_switch_host(cdns, 1); + else + cdns3_drd_switch_gadget(cdns, 1); + + cdns3_otg_enable_irq(cdns); +} + +/** + * cdns3_drd_update_mode - initialize mode of operation + * @cdns: Pointer to controller context structure + * + * Returns 0 on success otherwise negative errno + */ +int cdns3_drd_update_mode(struct cdns3 *cdns) +{ + int ret = 0; + + if (cdns->desired_dr_mode == cdns->current_dr_mode) + return ret; + + cdns3_drd_switch_gadget(cdns, 0); + cdns3_drd_switch_host(cdns, 0); + + switch (cdns->desired_dr_mode) { + case USB_DR_MODE_PERIPHERAL: + cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL); + break; + case USB_DR_MODE_HOST: + cdns3_set_mode(cdns, USB_DR_MODE_HOST); + break; + case USB_DR_MODE_OTG: + cdns3_init_otg_mode(cdns); + break; + default: + dev_err(cdns->dev, "Unsupported mode of operation %d\n", + cdns->dr_mode); + return -EINVAL; + } + + return ret; +} + +/** + * cdns3_drd_irq - interrupt handler for OTG events + * + * @irq: irq number for cdns3 core device + * @data: structure of cdns3 + * + * Returns IRQ_HANDLED or IRQ_NONE + */ +static irqreturn_t cdns3_drd_irq(int irq, void *data) +{ + irqreturn_t ret = IRQ_NONE; + struct cdns3 *cdns = data; + u32 reg; + + if (cdns->dr_mode != USB_DR_MODE_OTG) + return ret; + + reg = readl(&cdns->otg_regs->ivect); + if (!reg) + return ret; + + if (reg & OTGIEN_ID_CHANGE_INT) { + dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", + cdns3_get_id(cdns)); + + queue_work(system_freezable_wq, &cdns->role_switch_wq); + + ret = IRQ_HANDLED; + } + + writel(~0, &cdns->otg_regs->ivect); + return ret; +} + +int cdns3_drd_init(struct cdns3 *cdns) +{ + int ret = 0; + u32 state; + + state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts)); + + /* Update dr_mode according to STRAP configuration. */ + cdns->dr_mode = USB_DR_MODE_OTG; + if (state == OTGSTS_STRAP_HOST) { + dev_info(cdns->dev, "Controller strapped to HOST\n"); + cdns->dr_mode = USB_DR_MODE_HOST; + } else if (state == OTGSTS_STRAP_GADGET) { + dev_info(cdns->dev, "Controller strapped to PERIPHERAL\n"); + cdns->dr_mode = USB_DR_MODE_PERIPHERAL; + } + + cdns->desired_dr_mode = cdns->dr_mode; + cdns->current_dr_mode = USB_DR_MODE_UNKNOWN; + + ret = devm_request_irq(cdns->dev, cdns->irq, cdns3_drd_irq, IRQF_SHARED, + dev_name(cdns->dev), cdns); + + if (ret) + return ret; + + state = readl(&cdns->otg_regs->sts); + if (OTGSTS_OTG_NRDY(state) != 0) { + dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); + return -ENODEV; + } + + ret = cdns3_drd_update_mode(cdns); + + dev_info(cdns->dev, "Controller Device ID: %08lx, Revision ID: %08lx\n", + CDNS_RID(readl(&cdns->otg_regs->rid)), + CDNS_DID(readl(&cdns->otg_regs->did))); + + return ret; +} + +int cdns3_drd_exit(struct cdns3 *cdns) +{ + return cdns3_drd_switch_host(cdns, 0); +} diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h new file mode 100644 index 000000000000..4159e6e612ac --- /dev/null +++ b/drivers/usb/cdns3/drd.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USB3 DRD header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ +#ifndef __LINUX_CDNS3_DRD +#define __LINUX_CDNS3_DRD + +#include +#include +#include "core.h" + +/* DRD register interface. */ +struct cdns3_otg_regs { + __le32 did; + __le32 rid; + __le32 capabilities; + __le32 reserved1; + __le32 cmd; + __le32 sts; + __le32 state; + __le32 reserved2; + __le32 ien; + __le32 ivect; + __le32 refclk; + __le32 tmr; + __le32 reserved3[4]; + __le32 simulate; + __le32 override; + __le32 susp_ctrl; + __le32 reserved4; + __le32 anasts; + __le32 adp_ramp_time; + __le32 ctrl1; + __le32 ctrl2; +}; + +/* CDNS_RID - bitmasks */ +#define CDNS_RID(p) ((p) & GENMASK(15, 0)) + +/* CDNS_VID - bitmasks */ +#define CDNS_DID(p) ((p) & GENMASK(31, 0)) + +/* OTGCMD - bitmasks */ +/* "Request the bus for Device mode. */ +#define OTGCMD_DEV_BUS_REQ BIT(0) +/* Request the bus for Host mode */ +#define OTGCMD_HOST_BUS_REQ BIT(1) +/* Enable OTG mode. */ +#define OTGCMD_OTG_EN BIT(2) +/* Disable OTG mode */ +#define OTGCMD_OTG_DIS BIT(3) +/*"Configure OTG as A-Device. */ +#define OTGCMD_A_DEV_EN BIT(4) +/*"Configure OTG as A-Device. */ +#define OTGCMD_A_DEV_DIS BIT(5) +/* Drop the bus for Device mod e. */ +#define OTGCMD_DEV_BUS_DROP BIT(8) +/* Drop the bus for Host mode*/ +#define OTGCMD_HOST_BUS_DROP BIT(9) +/* Power Down USBSS-DEV. */ +#define OTGCMD_DEV_POWER_OFF BIT(11) +/* Power Down CDNSXHCI. */ +#define OTGCMD_HOST_POWER_OFF BIT(12) + +/* OTGIEN - bitmasks */ +/* ID change interrupt enable */ +#define OTGIEN_ID_CHANGE_INT BIT(0) +/* Vbusvalid fall detected interrupt enable.*/ +#define OTGIEN_VBUSVALID_RISE_INT BIT(4) +/* Vbusvalid fall detected interrupt enable */ +#define OTGIEN_VBUSVALID_FALL_INT BIT(5) + +/* OTGSTS - bitmasks */ +/* + * Current value of the ID pin. It is only valid when idpullup in + * OTGCTRL1_TYPE register is set to '1'. + */ +#define OTGSTS_ID_VALUE BIT(0) +/* Current value of the vbus_valid */ +#define OTGSTS_VBUS_VALID BIT(1) +/* Current value of the b_sess_vld */ +#define OTGSTS_SESSION_VALID BIT(2) +/*Device mode is active*/ +#define OTGSTS_DEV_ACTIVE BIT(3) +/* Host mode is active. */ +#define OTGSTS_HOST_ACTIVE BIT(4) +/* OTG Controller not ready. */ +#define OTGSTS_OTG_NRDY_MASK BIT(11) +#define OTGSTS_OTG_NRDY(p) ((p) & OTGSTS_OTG_NRDY_MASK) +/* + * Value of the strap pins. + * 000 - no default configuration + * 010 - Controller initiall configured as Host + * 100 - Controller initially configured as Device + */ +#define OTGSTS_STRAP(p) (((p) & GENMASK(14, 12)) >> 12) +#define OTGSTS_STRAP_NO_DEFAULT_CFG 0x00 +#define OTGSTS_STRAP_HOST_OTG 0x01 +#define OTGSTS_STRAP_HOST 0x02 +#define OTGSTS_STRAP_GADGET 0x04 +/* Host mode is turned on. */ +#define OTGSTS_XHCI_READY BIT(26) +/* "Device mode is turned on .*/ +#define OTGSTS_DEV_READY BIT(27) + +/* OTGSTATE- bitmasks */ +#define OTGSTATE_HOST_STATE_MASK GENMASK(5, 3) +#define OTGSTATE_HOST_STATE_IDLE 0x0 +#define OTGSTATE_HOST_STATE_VBUS_FALL 0x7 +#define OTGSTATE_HOST_STATE(p) (((p) & OTGSTATE_HOST_STATE_MASK) >> 3) + +/* OTGREFCLK - bitmasks */ +#define OTGREFCLK_STB_CLK_SWITCH_EN BIT(31) + +/* OVERRIDE - bitmasks */ +#define OVERRIDE_IDPULLUP BIT(0) + +int cdns3_is_host(struct cdns3 *cdns); +int cdns3_is_device(struct cdns3 *cdns); +int cdns3_get_id(struct cdns3 *cdns); +int cdns3_drd_init(struct cdns3 *cdns); +int cdns3_drd_exit(struct cdns3 *cdns); +int cdns3_drd_update_mode(struct cdns3 *cdns); + +#endif /* __LINUX_CDNS3_DRD */ diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c new file mode 100644 index 000000000000..1ef0e9f73e3e --- /dev/null +++ b/drivers/usb/cdns3/ep0.c @@ -0,0 +1,864 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include + +#include "gadget.h" +#include "trace.h" + +static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +/** + * cdns3_ep0_run_transfer - Do transfer on default endpoint hardware + * @priv_dev: extended gadget object + * @dma_addr: physical address where data is/will be stored + * @length: data length + * @erdy: set it to 1 when ERDY packet should be sent - + * exit from flow control state + */ +static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, + dma_addr_t dma_addr, + unsigned int length, int erdy) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + priv_dev->ep0_trb->buffer = TRB_BUFFER(dma_addr); + priv_dev->ep0_trb->length = TRB_LEN(length); + priv_dev->ep0_trb->control = TRB_CYCLE | TRB_IOC | TRB_TYPE(TRB_NORMAL); + + trace_cdns3_prepare_trb(priv_ep, priv_dev->ep0_trb); + + cdns3_select_ep(priv_dev, priv_dev->ep0_data_dir); + + writel(EP_STS_TRBERR, ®s->ep_sts); + writel(EP_TRADDR_TRADDR(priv_dev->ep0_trb_dma), ®s->ep_traddr); + trace_cdns3_doorbell_ep0(priv_dev->ep0_data_dir ? "ep0in" : "ep0out"); + + /* TRB should be prepared before starting transfer */ + writel(EP_CMD_DRDY, ®s->ep_cmd); + + if (erdy) + writel(EP_CMD_ERDY, &priv_dev->regs->ep_cmd); +} + +/** + * cdns3_ep0_delegate_req - Returns status of handling setup packet + * Setup is handled by gadget driver + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns zero on success or negative value on failure + */ +static int cdns3_ep0_delegate_req(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + spin_unlock(&priv_dev->lock); + priv_dev->setup_pending = 1; + ret = priv_dev->gadget_driver->setup(&priv_dev->gadget, ctrl_req); + priv_dev->setup_pending = 0; + spin_lock(&priv_dev->lock); + return ret; +} + +static void cdns3_prepare_setup_packet(struct cdns3_device *priv_dev) +{ + priv_dev->ep0_data_dir = 0; + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + sizeof(struct usb_ctrlrequest), 0); +} + +/** + * cdns3_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, USB_GADGET_DELAYED_STATUS on deferred status stage, + * error code on error + */ +static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + struct cdns3_endpoint *priv_ep; + u32 config = le16_to_cpu(ctrl_req->wValue); + int result = 0; + int i; + + switch (device_state) { + case USB_STATE_ADDRESS: + /* Configure non-control EPs */ + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { + priv_ep = priv_dev->eps[i]; + if (!priv_ep) + continue; + + if (priv_ep->flags & EP_CLAIMED) + cdns3_ep_config(priv_ep); + } + + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (result) + return result; + + if (config) { + cdns3_set_hw_configuration(priv_dev); + } else { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, + USB_STATE_ADDRESS); + } + break; + case USB_STATE_CONFIGURED: + result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + + if (!config && !result) { + cdns3_gadget_unconfig(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, + USB_STATE_ADDRESS); + } + break; + default: + result = -EINVAL; + } + + return result; +} + +/** + * cdns3_req_ep0_set_address - Handling of SET_ADDRESS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + enum usb_device_state device_state = priv_dev->gadget.state; + u32 reg; + u32 addr; + + addr = le16_to_cpu(ctrl_req->wValue); + + if (addr > USB_DEVICE_MAX_ADDRESS) { + dev_err(priv_dev->dev, + "Device address (%d) cannot be greater than %d\n", + addr, USB_DEVICE_MAX_ADDRESS); + return -EINVAL; + } + + if (device_state == USB_STATE_CONFIGURED) { + dev_err(priv_dev->dev, + "can't set_address from configured state\n"); + return -EINVAL; + } + + reg = readl(&priv_dev->regs->usb_cmd); + + writel(reg | USB_CMD_FADDR(addr) | USB_CMD_SET_ADDR, + &priv_dev->regs->usb_cmd); + + usb_gadget_set_state(&priv_dev->gadget, + (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT)); + + cdns3_prepare_setup_packet(priv_dev); + + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + return 0; +} + +/** + * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl) +{ + __le16 *response_pkt; + u16 usb_status = 0; + u32 recip; + u32 reg; + + recip = ctrl->bRequestType & USB_RECIP_MASK; + + switch (recip) { + case USB_RECIP_DEVICE: + /* self powered */ + if (priv_dev->is_selfpowered) + usb_status = BIT(USB_DEVICE_SELF_POWERED); + + if (priv_dev->wake_up_flag) + usb_status |= BIT(USB_DEVICE_REMOTE_WAKEUP); + + if (priv_dev->gadget.speed != USB_SPEED_SUPER) + break; + + reg = readl(&priv_dev->regs->usb_sts); + + if (priv_dev->u1_allowed) + usb_status |= BIT(USB_DEV_STAT_U1_ENABLED); + + if (priv_dev->u2_allowed) + usb_status |= BIT(USB_DEV_STAT_U2_ENABLED); + + break; + case USB_RECIP_INTERFACE: + return cdns3_ep0_delegate_req(priv_dev, ctrl); + case USB_RECIP_ENDPOINT: + /* check if endpoint is stalled */ + cdns3_select_ep(priv_dev, ctrl->wIndex); + if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts))) + usb_status = BIT(USB_ENDPOINT_HALT); + break; + default: + return -EINVAL; + } + + response_pkt = (__le16 *)priv_dev->setup_buf; + *response_pkt = cpu_to_le16(usb_status); + + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, + sizeof(*response_pkt), 1); + return 0; +} + +static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + enum usb_device_state state; + enum usb_device_speed speed; + int ret = 0; + u32 wValue; + u32 wIndex; + u16 tmode; + + wValue = le16_to_cpu(ctrl->wValue); + wIndex = le16_to_cpu(ctrl->wIndex); + state = priv_dev->gadget.state; + speed = priv_dev->gadget.speed; + + switch (ctrl->wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + priv_dev->wake_up_flag = !!set; + break; + case USB_DEVICE_U1_ENABLE: + if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) + return -EINVAL; + + priv_dev->u1_allowed = !!set; + break; + case USB_DEVICE_U2_ENABLE: + if (state != USB_STATE_CONFIGURED || speed != USB_SPEED_SUPER) + return -EINVAL; + + priv_dev->u2_allowed = !!set; + break; + case USB_DEVICE_LTM_ENABLE: + ret = -EINVAL; + break; + case USB_DEVICE_TEST_MODE: + if (state != USB_STATE_CONFIGURED || speed > USB_SPEED_HIGH) + return -EINVAL; + + tmode = le16_to_cpu(ctrl->wIndex); + + if (!set || (tmode & 0xff) != 0) + return -EINVAL; + + switch (tmode >> 8) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + cdns3_set_register_bit(&priv_dev->regs->usb_cmd, + USB_CMD_STMODE | + USB_STS_TMODE_SEL(tmode - 1)); + break; + default: + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cdns3_ep0_feature_handle_intf(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + u32 wValue; + int ret = 0; + + wValue = le16_to_cpu(ctrl->wValue); + + switch (wValue) { + case USB_INTRF_FUNC_SUSPEND: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + struct cdns3_endpoint *priv_ep; + int ret = 0; + u8 index; + + if (le16_to_cpu(ctrl->wValue) != USB_ENDPOINT_HALT) + return -EINVAL; + + if (!(ctrl->wIndex & ~USB_DIR_IN)) + return 0; + + index = cdns3_ep_addr_to_index(ctrl->wIndex); + priv_ep = priv_dev->eps[index]; + + cdns3_select_ep(priv_dev, ctrl->wIndex); + + if (set) { + writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd); + priv_ep->flags |= EP_STALL; + } else { + struct usb_request *request; + + if (priv_dev->eps[index]->flags & EP_WEDGE) { + cdns3_select_ep(priv_dev, 0x00); + return 0; + } + + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + /* wait for EPRST cleared */ + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + if (ret) + return -EINVAL; + + priv_ep->flags &= ~EP_STALL; + + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + return ret; +} + +/** + * cdns3_req_ep0_handle_feature - + * Handling of GET/SET_FEATURE standard USB request + * + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * @set: must be set to 1 for SET_FEATURE request + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_handle_feature(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl, + int set) +{ + int ret = 0; + u32 recip; + + recip = ctrl->bRequestType & USB_RECIP_MASK; + + switch (recip) { + case USB_RECIP_DEVICE: + ret = cdns3_ep0_feature_handle_device(priv_dev, ctrl, set); + break; + case USB_RECIP_INTERFACE: + ret = cdns3_ep0_feature_handle_intf(priv_dev, ctrl, set); + break; + case USB_RECIP_ENDPOINT: + ret = cdns3_ep0_feature_handle_endpoint(priv_dev, ctrl, set); + break; + default: + return -EINVAL; + } + + if (!ret) + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + return ret; +} + +/** + * cdns3_req_ep0_set_sel - Handling of SET_SEL standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_sel(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + if (priv_dev->gadget.state < USB_STATE_ADDRESS) + return -EINVAL; + + if (ctrl_req->wLength != 6) { + dev_err(priv_dev->dev, "Set SEL should be 6 bytes, got %d\n", + ctrl_req->wLength); + return -EINVAL; + } + + cdns3_ep0_run_transfer(priv_dev, priv_dev->setup_dma, 6, 1); + return 0; +} + +/** + * cdns3_req_ep0_set_isoch_delay - + * Handling of GET_ISOCH_DELAY standard USB request + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_req_ep0_set_isoch_delay(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + if (ctrl_req->wIndex || ctrl_req->wLength) + return -EINVAL; + + priv_dev->isoch_delay = ctrl_req->wValue; + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + return 0; +} + +/** + * cdns3_ep0_standard_request - Handling standard USB requests + * @priv_dev: extended gadget object + * @ctrl_req: pointer to received setup packet + * + * Returns 0 if success, error code on error + */ +static int cdns3_ep0_standard_request(struct cdns3_device *priv_dev, + struct usb_ctrlrequest *ctrl_req) +{ + int ret; + + switch (ctrl_req->bRequest) { + case USB_REQ_SET_ADDRESS: + ret = cdns3_req_ep0_set_address(priv_dev, ctrl_req); + break; + case USB_REQ_SET_CONFIGURATION: + ret = cdns3_req_ep0_set_configuration(priv_dev, ctrl_req); + break; + case USB_REQ_GET_STATUS: + ret = cdns3_req_ep0_get_status(priv_dev, ctrl_req); + break; + case USB_REQ_CLEAR_FEATURE: + ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 0); + break; + case USB_REQ_SET_FEATURE: + ret = cdns3_req_ep0_handle_feature(priv_dev, ctrl_req, 1); + break; + case USB_REQ_SET_SEL: + ret = cdns3_req_ep0_set_sel(priv_dev, ctrl_req); + break; + case USB_REQ_SET_ISOCH_DELAY: + ret = cdns3_req_ep0_set_isoch_delay(priv_dev, ctrl_req); + break; + default: + ret = cdns3_ep0_delegate_req(priv_dev, ctrl_req); + break; + } + + return ret; +} + +static void __pending_setup_status_handler(struct cdns3_device *priv_dev) +{ + struct usb_request *request = priv_dev->pending_status_request; + + if (priv_dev->status_completion_no_call && request && + request->complete) { + request->complete(priv_dev->gadget.ep0, request); + priv_dev->status_completion_no_call = 0; + } +} + +void cdns3_pending_setup_status_handler(struct work_struct *work) +{ + struct cdns3_device *priv_dev = container_of(work, struct cdns3_device, + pending_status_wq); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + __pending_setup_status_handler(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); +} + +/** + * cdns3_gadget_ep_giveback - call struct usb_request's ->complete callback + * @priv_ep: The endpoint to whom the request belongs to + * @priv_req: The request we're giving back + * @status: completion code for the request + * + * Must be called with controller's lock held and interrupts disabled. This + * function will unmap @req and call its ->complete() callback to notify upper + * layers that it has completed. + */ + +void cdns3_gadget_ep0_giveback(struct cdns3_device *priv_dev, + int status) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + + priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + request = cdns3_next_request(&priv_ep->request_list); + + priv_ep->dir = priv_dev->ep0_data_dir; + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), status); + priv_dev->ep0_request = NULL; +} + +/** + * cdns3_ep0_setup_phase - Handling setup USB requests + * @priv_dev: extended gadget object + */ +static void cdns3_ep0_setup_phase(struct cdns3_device *priv_dev) +{ + struct usb_ctrlrequest *ctrl = priv_dev->setup_buf; + struct cdns3_endpoint *priv_ep; + int result; + + priv_dev->ep0_data_dir = ctrl->bRequestType & USB_DIR_IN; + priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + trace_cdns3_ctrl_req(ctrl); + + if (!list_empty(&priv_ep->request_list)) + cdns3_gadget_ep0_giveback(priv_dev, -ECONNRESET); + + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) + result = cdns3_ep0_standard_request(priv_dev, ctrl); + else + result = cdns3_ep0_delegate_req(priv_dev, ctrl); + + if (result != 0 && result != USB_GADGET_DELAYED_STATUS) { + dev_dbg(priv_dev->dev, "STALL for ep0\n"); + /* set_stall on ep0 */ + cdns3_select_ep(priv_dev, 0x00); + writel(EP_CMD_SSTALL, &priv_dev->regs->ep_cmd); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + } +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(priv_dev->gadget.ep0); + + if (priv_dev->ep0_request) { + trace_cdns3_complete_trb(priv_ep, priv_dev->ep0_trb); + + priv_dev->ep0_request->actual = + TRB_LEN(le32_to_cpu(priv_dev->ep0_trb->length)); + + cdns3_gadget_ep0_giveback(priv_dev, 0); + } + + cdns3_prepare_setup_packet(priv_dev); + writel(EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); +} + +/** + * cdns3_check_new_setup - Check if controller receive new SETUP packet. + * @priv_dev: extended gadget object + * + * The SETUP packet can be kept in on-chip memory or in system memory. + */ +static bool cdns3_check_new_setup(struct cdns3_device *priv_dev) +{ + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT); + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + + return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT)); +} + +/** + * cdns3_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0 + * @priv_dev: extended gadget object + * @dir: USB_DIR_IN for IN direction, USB_DIR_OUT for OUT direction + */ +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) +{ + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, dir); + + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + writel(ep_sts_reg, &priv_dev->regs->ep_sts); + + trace_cdns3_ep0_irq(priv_dev); + + __pending_setup_status_handler(priv_dev); + + if ((ep_sts_reg & EP_STS_SETUP)) { + cdns3_ep0_setup_phase(priv_dev); + } else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { + priv_dev->ep0_data_dir = dir; + cdns3_transfer_completed(priv_dev); + } + + if (ep_sts_reg & EP_STS_DESCMIS) { + if (dir == 0 && !priv_dev->setup_pending) + cdns3_prepare_setup_packet(priv_dev); + } +} + +/** + * cdns3_gadget_ep0_enable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_disable + * Function shouldn't be called by gadget driver, + * endpoint 0 is allways active + */ +static int cdns3_gadget_ep0_disable(struct usb_ep *ep) +{ + return -EINVAL; +} + +/** + * cdns3_gadget_ep0_set_halt + * @ep: pointer to endpoint zero object + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 + */ +static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) +{ + /* TODO */ + return 0; +} + +/** + * cdns3_gadget_ep0_queue Transfer data on endpoint zero + * @ep: pointer to endpoint zero object + * @request: pointer to request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep0_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int erdy_sent = 0; + int ret = 0; + + dev_dbg(priv_dev->dev, "Queue to Ep0%s L: %d\n", + priv_dev->ep0_data_dir ? "IN" : "OUT", + request->length); + + /* cancel the request if controller receive new SETUP packet. */ + if (cdns3_check_new_setup(priv_dev)) + return -ECONNRESET; + + /* send STATUS stage. Should be called only for SET_CONFIGURATION */ + if (request->length == 0 && request->zero == 0) { + spin_lock_irqsave(&priv_dev->lock, flags); + cdns3_select_ep(priv_dev, 0x00); + + erdy_sent = !priv_dev->hw_configured_flag; + cdns3_set_hw_configuration(priv_dev); + + if (!erdy_sent) + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, + &priv_dev->regs->ep_cmd); + + cdns3_prepare_setup_packet(priv_dev); + request->actual = 0; + priv_dev->status_completion_no_call = true; + priv_dev->pending_status_request = request; + spin_unlock_irqrestore(&priv_dev->lock, flags); + + /* + * Since there is no completion interrupt for status stage, + * it needs to call ->completion in software after + * ep0_queue is back. + */ + queue_work(system_freezable_wq, &priv_dev->pending_status_wq); + return 0; + } + + spin_lock_irqsave(&priv_dev->lock, flags); + if (!list_empty(&priv_ep->request_list)) { + dev_err(priv_dev->dev, + "can't handle multiple requests for ep0\n"); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return -EBUSY; + } + + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, + priv_dev->ep0_data_dir); + if (ret) { + spin_unlock_irqrestore(&priv_dev->lock, flags); + dev_err(priv_dev->dev, "failed to map request\n"); + return -EINVAL; + } + + request->status = -EINPROGRESS; + priv_dev->ep0_request = request; + list_add_tail(&request->list, &priv_ep->request_list); + cdns3_ep0_run_transfer(priv_dev, request->dma, request->length, 1); + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +/** + * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint + * @ep: endpoint object + * + * Returns 0 + */ +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + dev_dbg(priv_dev->dev, "Wedge for %s\n", ep->name); + cdns3_gadget_ep_set_halt(ep, 1); + priv_ep->flags |= EP_WEDGE; + + return 0; +} + +const struct usb_ep_ops cdns3_gadget_ep0_ops = { + .enable = cdns3_gadget_ep0_enable, + .disable = cdns3_gadget_ep0_disable, + .alloc_request = cdns3_gadget_ep_alloc_request, + .free_request = cdns3_gadget_ep_free_request, + .queue = cdns3_gadget_ep0_queue, + .dequeue = cdns3_gadget_ep_dequeue, + .set_halt = cdns3_gadget_ep0_set_halt, + .set_wedge = cdns3_gadget_ep_set_wedge, +}; + +/** + * cdns3_ep0_config - Configures default endpoint + * @priv_dev: extended gadget object + * + * Functions sets parameters: maximal packet size and enables interrupts + */ +void cdns3_ep0_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs; + u32 max_packet_size = 64; + + regs = priv_dev->regs; + + if (priv_dev->gadget.speed == USB_SPEED_SUPER) + max_packet_size = 512; + + if (priv_dev->ep0_request) { + list_del_init(&priv_dev->ep0_request->list); + priv_dev->ep0_request = NULL; + } + + priv_dev->u1_allowed = 0; + priv_dev->u2_allowed = 0; + + priv_dev->gadget.ep0->maxpacket = max_packet_size; + cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(max_packet_size); + + /* init ep out */ + cdns3_select_ep(priv_dev, USB_DIR_OUT); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_DESCMISEN | EP_STS_EN_TRBERREN, + ®s->ep_sts_en); + + /* init ep in */ + cdns3_select_ep(priv_dev, USB_DIR_IN); + + writel(EP_CFG_ENABLE | EP_CFG_MAXPKTSIZE(max_packet_size), + ®s->ep_cfg); + + writel(EP_STS_EN_SETUPEN | EP_STS_EN_TRBERREN, ®s->ep_sts_en); + + cdns3_set_register_bit(®s->usb_conf, USB_CONF_U1DS | USB_CONF_U2DS); + cdns3_prepare_setup_packet(priv_dev); +} + +/** + * cdns3_init_ep0 Initializes software endpoint 0 of gadget + * @cdns3: extended gadget object + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_init_ep0(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *ep0; + + ep0 = devm_kzalloc(priv_dev->dev, sizeof(struct cdns3_endpoint), + GFP_KERNEL); + + if (!ep0) + return -ENOMEM; + + ep0->cdns3_dev = priv_dev; + sprintf(ep0->name, "ep0"); + + /* fill linux fields */ + ep0->endpoint.ops = &cdns3_gadget_ep0_ops; + ep0->endpoint.maxburst = 1; + usb_ep_set_maxpacket_limit(&ep0->endpoint, CDNS3_EP0_MAX_PACKET_LIMIT); + ep0->endpoint.address = 0; + ep0->endpoint.caps.type_control = 1; + ep0->endpoint.caps.dir_in = 1; + ep0->endpoint.caps.dir_out = 1; + ep0->endpoint.name = ep0->name; + ep0->endpoint.desc = &cdns3_gadget_ep0_desc; + priv_dev->gadget.ep0 = &ep0->endpoint; + INIT_LIST_HEAD(&ep0->request_list); + + return 0; +} diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h new file mode 100644 index 000000000000..577469eee961 --- /dev/null +++ b/drivers/usb/cdns3/gadget-export.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver - Gadget Export APIs. + * + * Copyright (C) 2017 NXP + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET_EXPORT +#define __LINUX_CDNS3_GADGET_EXPORT + +#ifdef CONFIG_USB_CDNS3_GADGET + +int cdns3_gadget_init(struct cdns3 *cdns); +void cdns3_gadget_exit(struct cdns3 *cdns); +#else + +static inline int cdns3_gadget_init(struct cdns3 *cdns) +{ + return -ENXIO; +} + +static inline void cdns3_gadget_exit(struct cdns3 *cdns) { } + +#endif + +#endif /* __LINUX_CDNS3_GADGET_EXPORT */ diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c new file mode 100644 index 000000000000..a021eaf07aee --- /dev/null +++ b/drivers/usb/cdns3/gadget.c @@ -0,0 +1,1802 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - gadget side. + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Pawel Jez , + * Pawel Laszczak + * Peter Chen + */ + +#include +#include + +#include "core.h" +#include "gadget-export.h" +#include "gadget.h" + +#include "trace.h" + +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags); + +/** + * cdns3_handshake - spin reading until handshake completes or fails + * @ptr: address of device controller register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + */ +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl(ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/** + * cdns3_set_register_bit - set bit in given register. + * @ptr: address of device controller register to be read and changed + * @mask: bits requested to set + */ +void cdns3_set_register_bit(void __iomem *ptr, u32 mask) +{ + mask = readl(ptr) | mask; + writel(mask, ptr); +} + +/** + * cdns3_ep_reg_pos_to_index - Macro converts bit position of ep_ists register + * to index of endpoint object in cdns3_device.eps[] container + * @i: bit position of endpoint for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u8 cdns3_ep_reg_pos_to_index(int i) +{ + return ((i / 16) + (((i % 16) - 2) * 2)); +} + +/** + * cdns3_ep_addr_to_index - Macro converts endpoint address to + * index of endpoint object in cdns3_device.eps[] container + * @ep_addr: endpoint address for which endpoint object is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +u8 cdns3_ep_addr_to_index(u8 ep_addr) +{ + return (((ep_addr & 0x7F) - 1) + ((ep_addr & USB_DIR_IN) ? 1 : 0)); +} + +/** + * cdns3_ep_addr_to_bit_pos - Macro converts endpoint address to + * bit position in ep_ists register + * @ep_addr: endpoint address for which bit position is required + * + * Remember that endpoint container doesn't contain default endpoint + */ +static u32 cdns3_ep_addr_to_bit_pos(u8 ep_addr) +{ + return (1 << (ep_addr & 0x7F)) << ((ep_addr & 0x80) ? 16 : 0); +} + +/** + * cdns3_next_request - returns next request from list + * @list: list containing requests + * + * Returns request or NULL if no requests in list + */ +struct usb_request *cdns3_next_request(struct list_head *list) +{ + if (list_empty(list)) + return NULL; + return list_first_entry(list, struct usb_request, list); +} + +/** + * select_ep - selects endpoint + * @priv_dev: extended gadget object + * @ep: endpoint address + */ +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) +{ + if (priv_dev->selected_ep == ep) + return; + + priv_dev->selected_ep = ep; + writel(ep, &priv_dev->regs->ep_sel); +} + +dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, + struct cdns3_trb *trb) +{ + u32 offset = (char *)trb - (char *)priv_ep->trb_pool; + + return priv_ep->trb_pool_dma + offset; +} + +/** + * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint + * @priv_ep: endpoint object + * + * Function will return 0 on success or -ENOMEM on allocation error + */ +static int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *link_trb; + + if (!priv_ep->trb_pool) { + priv_ep->trb_pool = dma_zalloc_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + &priv_ep->trb_pool_dma, + GFP_DMA); + if (!priv_ep->trb_pool) + return -ENOMEM; + } else { + memset(priv_ep->trb_pool, 0, TRB_RING_SIZE); + } + + if (!priv_ep->aligned_buff) { + void *buff = dma_alloc_coherent(priv_dev->sysdev, + CDNS3_ALIGNED_BUF_SIZE, + &priv_ep->aligned_dma_addr, + GFP_DMA); + + priv_ep->aligned_buff = buff; + if (!priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + priv_ep->trb_pool, + priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + + return -ENOMEM; + } + } + + /* Initialize the last TRB as Link TRB */ + link_trb = (priv_ep->trb_pool + TRBS_PER_SEGMENT - 1); + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma); + link_trb->control = TRB_CYCLE | TRB_TYPE(TRB_LINK) | + TRB_CHAIN | TRB_TOGGLE; + + return 0; +} + +static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + if (priv_ep->trb_pool) { + dma_free_coherent(priv_dev->sysdev, + TRB_RING_SIZE, + priv_ep->trb_pool, priv_ep->trb_pool_dma); + priv_ep->trb_pool = NULL; + } + + if (priv_ep->aligned_buff) { + dma_free_coherent(priv_dev->sysdev, CDNS3_ALIGNED_BUF_SIZE, + priv_ep->aligned_buff, + priv_ep->aligned_dma_addr); + priv_ep->aligned_buff = NULL; + } +} + +/** + * cdns3_data_flush - flush data at onchip buffer + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + * + * Returns zero on success or negative value on failure + */ +static int cdns3_data_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + return cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); +} + +/** + * cdns3_ep_stall_flush - Stalls and flushes selected endpoint + * @priv_ep: endpoint object + * + * Endpoint must be selected before call to this function + */ +static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + + writel(EP_CMD_DFLUSH | EP_CMD_ERDY | EP_CMD_SSTALL, + &priv_dev->regs->ep_cmd); + + /* wait for DFLUSH cleared */ + cdns3_handshake(&priv_dev->regs->ep_cmd, EP_CMD_DFLUSH, 0, 100); + priv_ep->flags |= EP_STALL; +} + +/** + * cdns3_gadget_unconfig - reset device configuration + * @priv_dev: extended gadget object + */ +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev) +{ + /* RESET CONFIGURATION */ + writel(USB_CONF_CFGRST, &priv_dev->regs->usb_conf); + + cdns3_allow_enable_l1(priv_dev, 0); + priv_dev->hw_configured_flag = 0; + priv_dev->onchip_mem_allocated_size = 0; +} + +/** + * cdns3_ep_inc_trb - increment a trb index. + * @index: Pointer to the TRB index to increment. + * @cs: Cycle state + * + * The index should never point to the link TRB. After incrementing, + * if it is point to the link TRB, wrap around to the beginning and revert + * cycle state bit The + * link TRB is always at the last TRB entry. + */ +static void cdns3_ep_inc_trb(int *index, u8 *cs) +{ + (*index)++; + if (*index == (TRBS_PER_SEGMENT - 1)) { + *index = 0; + *cs ^= 1; + } +} + +/** + * cdns3_ep_inc_enq - increment endpoint's enqueue pointer + * @priv_ep: The endpoint whose enqueue pointer we're incrementing + */ +static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs--; + cdns3_ep_inc_trb(&priv_ep->enqueue, &priv_ep->pcs); +} + +/** + * cdns3_ep_inc_deq - increment endpoint's dequeue pointer + * @priv_ep: The endpoint whose dequeue pointer we're incrementing + */ +static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep) +{ + priv_ep->free_trbs++; + cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs); +} + +/** + * cdns3_allow_enable_l1 - enable/disable permits to transition to L1. + * @priv_dev: Extended gadget object + * @enable: Enable/disable permit to transition to L1. + * + * If bit USB_CONF_L1EN is set and device receive Extended Token packet, + * then controller answer with ACK handshake. + * If bit USB_CONF_L1DS is set and device receive Extended Token packet, + * then controller answer with NYET handshake. + */ +void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable) +{ + if (enable) + writel(USB_CONF_L1EN, &priv_dev->regs->usb_conf); + else + writel(USB_CONF_L1DS, &priv_dev->regs->usb_conf); +} + +enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev) +{ + u32 reg; + + reg = readl(&priv_dev->regs->usb_sts); + + if (DEV_SUPERSPEED(reg)) + return USB_SPEED_SUPER; + else if (DEV_HIGHSPEED(reg)) + return USB_SPEED_HIGH; + else if (DEV_FULLSPEED(reg)) + return USB_SPEED_FULL; + else if (DEV_LOWSPEED(reg)) + return USB_SPEED_LOW; + return USB_SPEED_UNKNOWN; +} + +/** + * cdns3_start_all_request - add to ring all request not started + * @priv_dev: Extended gadget object + * @priv_ep: The endpoint for whom request will be started. + * + * Returns return ENOMEM if transfer ring i not enough TRBs to start + * all requests. + */ +static int cdns3_start_all_request(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + struct usb_request *req, *req_temp; + int ret = 0; + + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { + struct cdns3_request *priv_req = to_cdns3_request(req); + + if (!(priv_req->flags & REQUEST_PENDING)) { + ret = cdns3_ep_run_transfer(priv_ep, req); + if (ret) + return ret; + } + } + + priv_ep->flags &= ~EP_RING_FULL; + return ret; +} + +/** + * cdns3_gadget_giveback - call struct usb_request's ->complete callback + * @priv_ep: The endpoint to whom the request belongs to + * @priv_req: The request we're giving back + * @status: completion code for the request + * + * Must be called with controller's lock held and interrupts disabled. This + * function will unmap @req and call its ->complete() callback to notify upper + * layers that it has completed. + */ +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req, + int status) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *request = &priv_req->request; + + list_del_init(&request->list); + + if (request->status == -EINPROGRESS) + request->status = status; + + usb_gadget_unmap_request_by_dev(priv_dev->sysdev, request, + priv_ep->dir); + + priv_req->flags &= ~REQUEST_PENDING; + trace_cdns3_gadget_giveback(priv_req); + + if (priv_req->flags & REQUEST_INTERNAL) { + struct usb_request *req; + + req = cdns3_next_request(&priv_ep->request_list); + + priv_ep->descmis_pending = false; + priv_ep->descmis_finished = true; + + /* + * If no request is queued then driver can't do nothing + * with just completed request. Request with flag set to + * REQUEST_INTERNAL is only internal used request and driver + * can't call complete callback. Before calling completion, data + * must be copied to normal usb_request object + */ + if (!req) + return; + + req->actual = request->actual; + req->status = request->status; + memcpy(req->buf, request->buf, request->actual); + + request = req; + list_del_init(&request->list); + cdns3_start_all_request(priv_dev, priv_ep); + priv_ep->descmis_finished = false; + } + + /* Start all not pending request */ + if (priv_ep->flags & EP_RING_FULL) + cdns3_start_all_request(priv_dev, priv_ep); + + if (request->complete) { + spin_unlock(&priv_dev->lock); + usb_gadget_giveback_request(&priv_ep->endpoint, + request); + spin_lock(&priv_dev->lock); + } + + if (request->buf == priv_dev->zlp_buf) + cdns3_gadget_ep_free_request(&priv_ep->endpoint, request); +} + +/** + * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware + * @priv_ep: endpoint object + * + * Returns zero on success or negative value on failure + */ +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + struct usb_request *request) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + dma_addr_t trb_dma; + int sg_iter = 0; + u32 first_pcs; + int num_trb; + int address; + int pcs; + + num_trb = request->num_sgs ? request->num_sgs : 1; + + if (num_trb > priv_ep->free_trbs) { + priv_ep->flags |= EP_RING_FULL; + return -ENOMEM; + } + + priv_req = to_cdns3_request(request); + address = priv_ep->endpoint.desc->bEndpointAddress; + + if (priv_ep->descmis_pending) + return 0; + + if (priv_req->flags & REQUEST_PENDING) + goto arm; + + priv_ep->flags |= EP_PENDING_REQUEST; + trb_dma = request->dma; + + /* must allocate buffer aligned to 8 */ + if ((request->dma % 8)) { + if (request->length <= CDNS3_ALIGNED_BUF_SIZE) { + memcpy(priv_ep->aligned_buff, request->buf, + request->length); + trb_dma = priv_ep->aligned_dma_addr; + } else { + return -ENOMEM; + } + } + + trb = priv_ep->trb_pool + priv_ep->enqueue; + priv_req->trb = trb; + priv_req->start_trb = priv_ep->enqueue; + + /* prepare ring */ + if ((priv_ep->enqueue + num_trb) >= (TRBS_PER_SEGMENT - 1)) { + /*updating C bt in Link TRB before starting DMA*/ + struct cdns3_trb *link_trb = priv_ep->trb_pool + + (TRBS_PER_SEGMENT - 1); + link_trb->control = ((priv_ep->pcs) ? TRB_CYCLE : 0) | + TRB_TYPE(TRB_LINK) | TRB_CHAIN | + TRB_TOGGLE; + } + + first_pcs = priv_ep->pcs ? TRB_CYCLE : 0; + + do { + /* fill TRB */ + trb->buffer = TRB_BUFFER(request->num_sgs == 0 + ? trb_dma : request->sg[sg_iter].dma_address); + + trb->length = TRB_BURST_LEN(16) | + TRB_LEN(request->num_sgs == 0 ? + request->length : request->sg[sg_iter].length); + + trb->control = TRB_TYPE(TRB_NORMAL); + pcs = priv_ep->pcs ? TRB_CYCLE : 0; + + /* + * first trb should be prepared as last to avoid processing + * transfer to early + */ + if (sg_iter == request->num_sgs && sg_iter != 0) + trb->control |= pcs | TRB_IOC | TRB_ISP; + else if (sg_iter != 0) + trb->control |= pcs; + + ++sg_iter; + ++trb; + cdns3_ep_inc_enq(priv_ep); + } while (sg_iter < request->num_sgs); + + trb = priv_req->trb; + /* + * Memory barrier = Cycle Bit must be set before trb->length and + * trb->buffer fields. + */ + wmb(); + + /* give the TD to the consumer*/ + if (sg_iter == 1) + trb->control |= first_pcs | TRB_IOC | TRB_ISP; + else + trb->control |= first_pcs; + + priv_req->flags |= REQUEST_PENDING; + + if (priv_req->flags & REQUEST_INTERNAL) + priv_ep->descmis_pending = true; + + trace_cdns3_prepare_trb(priv_ep, priv_req->trb); + trace_cdns3_ring(priv_ep); + +arm: + /* arm transfer on selected endpoint */ + cdns3_select_ep(priv_ep->cdns3_dev, address); + + /* + * For DMULT mode we can set address to transfer ring only once after + * enabling endpoint. + */ + if (priv_ep->flags & EP_UPDATE_EP_TRBADDR) { + writel(EP_TRADDR_TRADDR(priv_ep->trb_pool_dma), + &priv_dev->regs->ep_traddr); + priv_ep->flags &= ~EP_UPDATE_EP_TRBADDR; + } + + if (priv_dev->hw_configured_flag) { + /*clearing TRBERR and EP_STS_DESCMIS before seting DRDY*/ + writel(EP_STS_TRBERR | EP_STS_DESCMIS, &priv_dev->regs->ep_sts); + trace_cdns3_doorbell_epx(priv_ep->name); + writel(EP_CMD_DRDY, &priv_dev->regs->ep_cmd); + } + + return 0; +} + +void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) +{ + struct cdns3_endpoint *priv_ep; + struct usb_request *request; + struct usb_ep *ep; + int result = 0; + + if (priv_dev->hw_configured_flag) + return; + + writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); + writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); + + cdns3_set_register_bit(&priv_dev->regs->usb_conf, + USB_CONF_U1EN | USB_CONF_U2EN); + + /* wait until configuration set */ + result = cdns3_handshake(&priv_dev->regs->usb_sts, + USB_STS_CFGSTS_MASK, 1, 100); + + priv_dev->hw_configured_flag = 1; + cdns3_allow_enable_l1(priv_dev, 1); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + if (ep->enabled) { + priv_ep = ep_to_cdns3_ep(ep); + request = cdns3_next_request(&priv_ep->request_list); + if (request) + cdns3_ep_run_transfer(priv_ep, request); + } + } +} + +static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req) +{ + int current_index; + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_trb *trb = priv_req->trb; + + if (!(priv_req->flags & REQUEST_PENDING)) + return false; + + cdns3_select_ep(priv_dev, priv_ep->endpoint.desc->bEndpointAddress); + current_index = (readl(&priv_dev->regs->ep_traddr) - + priv_ep->trb_pool_dma) / TRB_SIZE; + + trb = &priv_ep->trb_pool[priv_req->start_trb]; + + if ((trb->control & TRB_CYCLE) != priv_ep->ccs) + return false; + + /** + * case where ep_traddr point to last trb in ring (link trb) + * and dequeue pointer already has been changed to first trb + */ + if ((current_index == (TRBS_PER_SEGMENT - 1)) && !priv_ep->dequeue) + return false; + + if (priv_req->start_trb != current_index) + return true; + + return false; +} + +static void cdns3_transfer_completed(struct cdns3_device *priv_dev, + struct cdns3_endpoint *priv_ep) +{ + struct usb_request *request; + struct cdns3_request *priv_req; + struct cdns3_trb *trb; + + while (!list_empty(&priv_ep->request_list)) { + request = cdns3_next_request(&priv_ep->request_list); + priv_req = to_cdns3_request(request); + + if (!cdns3_request_handled(priv_ep, priv_req)) + return; + + if (request->dma % 8 && priv_ep->dir == USB_DIR_OUT) + memcpy(request->buf, priv_ep->aligned_buff, + request->length); + + trb = priv_ep->trb_pool + priv_ep->dequeue; + trace_cdns3_complete_trb(priv_ep, trb); + if (trb != priv_req->trb) + dev_warn(priv_dev->dev, + "request_trb=0x%p, queue_trb=0x%p\n", + priv_req->trb, trb); + + request->actual = TRB_LEN(le32_to_cpu(trb->length)); + + cdns3_ep_inc_deq(priv_ep); + + cdns3_gadget_giveback(priv_ep, priv_req, 0); + } + + priv_ep->flags &= ~EP_PENDING_REQUEST; +} + +/** + * cdns3_descmissing_packet - handles descriptor missing event. + * @priv_dev: extended gadget object + * + * Function protects gadget functions from getting stuck. + * Controller for OUT endpoints has shared on-chip buffers for all incoming + * packets, including ep0out. It's FIFO buffer, so packets must be handle by DMA + * in correct order. If the first packet in the buffer will not be handled, + * then the following packets directed for other endpoints and functions + * will be blocked. + * Additionally the packets directed to one endpoint can clog entire on-chip + * buffers. In this case transfer to other endpoints also will blocked. + * + * To resolve this issue after raising the descriptor missing interrupt + * driver prepares internal usb_request object and use it to arm DMA transfer + * for the right endpoint. Driver use only single usb_request with + * allocated 64KB buffer, so if host send more not expected transfers, then only + * the last will be saved and returned to gadget function. + * Such blocking situation was observed on ACM gadget, because host send OUT + * data packet but ACM function doesn't want their. + */ +static void cdns3_descmissing_packet(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_request *priv_req = priv_ep->descmis_req; + struct usb_request *request; + + if (!priv_req) { + request = cdns3_gadget_ep_alloc_request(&priv_ep->endpoint, + GFP_ATOMIC); + priv_req = to_cdns3_request(request); + priv_req->flags |= REQUEST_INTERNAL; + priv_req->request.buf = kzalloc(CDNS3_DESCMIS_BUF_SIZE, + GFP_ATOMIC); + priv_req->request.length = CDNS3_DESCMIS_BUF_SIZE; + priv_ep->descmis_req = priv_req; + } + + priv_ep->descmis_finished = false; + __cdns3_gadget_ep_queue(&priv_ep->endpoint, + &priv_ep->descmis_req->request, + GFP_ATOMIC); +} + +/** + * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint + * @priv_ep: endpoint object + * + * Returns 0 + */ +static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep) +{ + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + u32 ep_sts_reg; + + cdns3_select_ep(priv_dev, priv_ep->endpoint.address); + ep_sts_reg = readl(&priv_dev->regs->ep_sts); + writel(ep_sts_reg, &priv_dev->regs->ep_sts); + + trace_cdns3_epx_irq(priv_ep); + + if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) + cdns3_transfer_completed(priv_dev, priv_ep); + + if (ep_sts_reg & EP_STS_DESCMIS) + cdns3_descmissing_packet(priv_ep); + + return 0; +} + +/** + * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device + * @priv_dev: extended gadget object + * @usb_ists: bitmap representation of device's reported interrupts + * (usb_ists register value) + */ +static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev, + u32 usb_ists) +{ + int speed = 0; + + trace_cdns3_usb_irq(priv_dev, usb_ists); + /* Connection detected */ + if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) { + speed = cdns3_get_speed(priv_dev); + priv_dev->gadget.speed = speed; + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_POWERED); + cdns3_ep0_config(priv_dev); + } + + /* Disconnection detected */ + if (usb_ists & (USB_ISTS_DIS2I | USB_ISTS_DISI)) { + if (priv_dev->gadget_driver && + priv_dev->gadget_driver->disconnect) { + spin_unlock(&priv_dev->lock); + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); + spin_lock(&priv_dev->lock); + } + + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_NOTATTACHED); + cdns3_gadget_unconfig(priv_dev); + } + + /* reset*/ + if (usb_ists & (USB_ISTS_UWRESI | USB_ISTS_UHRESI | USB_ISTS_U2RESI)) { + /*read again to check the actuall speed*/ + speed = cdns3_get_speed(priv_dev); + usb_gadget_set_state(&priv_dev->gadget, USB_STATE_DEFAULT); + priv_dev->gadget.speed = speed; + cdns3_gadget_unconfig(priv_dev); + cdns3_ep0_config(priv_dev); + } +} + +/** + * cdns3_device_irq_handler- interrupt handler for device part of controller + * + * @irq: irq number for cdns3 core device + * @data: structure of cdns3 + * + * Returns IRQ_HANDLED or IRQ_NONE + */ +static irqreturn_t cdns3_device_irq_handler(int irq, void *data) +{ + struct cdns3_device *priv_dev; + struct cdns3 *cdns = data; + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + u32 reg; + + priv_dev = cdns->gadget_dev; + spin_lock_irqsave(&priv_dev->lock, flags); + + /* check USB device interrupt */ + reg = readl(&priv_dev->regs->usb_ists); + writel(reg, &priv_dev->regs->usb_ists); + + if (reg) { + dev_dbg(priv_dev->dev, "IRQ: usb_ists: %08X\n", reg); + cdns3_check_usb_interrupt_proceed(priv_dev, reg); + ret = IRQ_HANDLED; + } + + /* check endpoint interrupt */ + reg = readl(&priv_dev->regs->ep_ists); + + /* handle default endpoint OUT */ + if (reg & EP_ISTS_EP_OUT0) { + cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_OUT); + ret = IRQ_HANDLED; + } + + /* handle default endpoint IN */ + if (reg & EP_ISTS_EP_IN0) { + cdns3_check_ep0_interrupt_proceed(priv_dev, USB_DIR_IN); + ret = IRQ_HANDLED; + } + + /* check if interrupt from non default endpoint, if no exit */ + reg &= ~(EP_ISTS_EP_OUT0 | EP_ISTS_EP_IN0); + if (!reg) + goto irqend; + + do { + unsigned int bit_pos = ffs(reg); + u32 bit_mask = 1 << (bit_pos - 1); + int index; + + index = cdns3_ep_reg_pos_to_index(bit_pos); + cdns3_check_ep_interrupt_proceed(priv_dev->eps[index]); + reg &= ~bit_mask; + ret = IRQ_HANDLED; + } while (reg); + +irqend: + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_ep_onchip_buffer_reserve - Try to reserve onchip buf for EP + * + * The real reservation will occur during write to EP_CFG register, + * this function is used to check if the 'size' reservation is allowed. + * + * @priv_dev: extended gadget object + * @size: the size (KB) for EP would like to allocate + * + * Return 0 if the required size can met or negative value on failure + */ +static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev, + int size) +{ + u32 onchip_mem; + + priv_dev->onchip_mem_allocated_size += size; + + onchip_mem = USB_CAP2_ACTUAL_MEM_SIZE(readl(&priv_dev->regs->usb_cap2)); + if (!onchip_mem) + onchip_mem = 256; + + /* 2KB is reserved for EP0*/ + onchip_mem -= 2; + if (priv_dev->onchip_mem_allocated_size > onchip_mem) { + priv_dev->onchip_mem_allocated_size -= size; + return -EPERM; + } + + return 0; +} + +/** + * cdns3_ep_config Configure hardware endpoint + * @priv_ep: extended endpoint object + */ +void cdns3_ep_config(struct cdns3_endpoint *priv_ep) +{ + bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + u32 bEndpointAddress = priv_ep->num | priv_ep->dir; + u32 interrupt_mask = EP_STS_EN_TRBERREN; + u32 max_packet_size = 0; + u32 ep_cfg = 0; + int ret; + + if (!priv_ep->dir) + interrupt_mask |= EP_STS_EN_DESCMISEN; + + if (priv_ep->type == USB_ENDPOINT_XFER_INT) { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_INT); + } else if (priv_ep->type == USB_ENDPOINT_XFER_BULK) { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_BULK); + } else { + ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC); + interrupt_mask = 0xFFFFFFFF; + } + + switch (priv_dev->gadget.speed) { + case USB_SPEED_FULL: + max_packet_size = is_iso_ep ? 1023 : 64; + break; + case USB_SPEED_HIGH: + max_packet_size = is_iso_ep ? 1024 : 512; + break; + case USB_SPEED_SUPER: + max_packet_size = 1024; + break; + default: + /* all other speed are not supported */ + return; + } + + ret = cdns3_ep_onchip_buffer_reserve(priv_dev, CDNS3_EP_BUF_SIZE); + if (ret) { + dev_err(priv_dev->dev, "onchip mem is full, ep is invalid\n"); + return; + } + + ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) | + EP_CFG_BUFFERING(CDNS3_EP_BUF_SIZE - 1) | + EP_CFG_MAXBURST(priv_ep->endpoint.maxburst); + + cdns3_select_ep(priv_dev, bEndpointAddress); + + writel(ep_cfg, &priv_dev->regs->ep_cfg); + writel(interrupt_mask, &priv_dev->regs->ep_sts_en); + + dev_dbg(priv_dev->dev, "Configure %s: with val %08x\n", + priv_ep->name, ep_cfg); + + /* enable interrupt for selected endpoint */ + cdns3_set_register_bit(&priv_dev->regs->ep_ien, + cdns3_ep_addr_to_bit_pos(bEndpointAddress)); +} + +/* Find correct direction for HW endpoint according to description */ +static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, + struct cdns3_endpoint *priv_ep) +{ + return (priv_ep->endpoint.caps.dir_in && usb_endpoint_dir_in(desc)) || + (priv_ep->endpoint.caps.dir_out && usb_endpoint_dir_out(desc)); +} + +static struct +cdns3_endpoint *cdns3_find_available_ep(struct cdns3_device *priv_dev, + struct usb_endpoint_descriptor *desc) +{ + struct usb_ep *ep; + struct cdns3_endpoint *priv_ep; + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + unsigned long num; + int ret; + /* ep name pattern likes epXin or epXout */ + char c[2] = {ep->name[2], '\0'}; + + ret = kstrtoul(c, 10, &num); + if (ret) + return ERR_PTR(ret); + + priv_ep = ep_to_cdns3_ep(ep); + if (cdns3_ep_dir_is_correct(desc, priv_ep)) { + if (!(priv_ep->flags & EP_CLAIMED)) { + priv_ep->num = num; + return priv_ep; + } + } + } + return ERR_PTR(-ENOENT); +} + +static struct +usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *comp_desc) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + unsigned long flags; + + priv_ep = cdns3_find_available_ep(priv_dev, desc); + if (IS_ERR(priv_ep)) { + dev_err(priv_dev->dev, "no available ep\n"); + return NULL; + } + + dev_dbg(priv_dev->dev, "match endpoint: %s\n", priv_ep->name); + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + priv_ep->flags |= EP_CLAIMED; + spin_unlock_irqrestore(&priv_dev->lock, flags); + return &priv_ep->endpoint; +} + +/** + * cdns3_gadget_ep_alloc_request Allocates request + * @ep: endpoint object associated with request + * @gfp_flags: gfp flags + * + * Returns allocated request address, NULL on allocation error + */ +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_request *priv_req; + + priv_req = kzalloc(sizeof(*priv_req), gfp_flags); + if (!priv_req) + return NULL; + + priv_req->priv_ep = priv_ep; + + trace_cdns3_alloc_request(priv_req); + return &priv_req->request; +} + +/** + * cdns3_gadget_ep_free_request Free memory occupied by request + * @ep: endpoint object associated with request + * @request: request to free memory + */ +void cdns3_gadget_ep_free_request(struct usb_ep *ep, + struct usb_request *request) +{ + struct cdns3_request *priv_req = to_cdns3_request(request); + + trace_cdns3_free_request(priv_req); + kfree(priv_req); +} + +/** + * cdns3_gadget_ep_enable Enable endpoint + * @ep: endpoint object + * @desc: endpoint descriptor + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct cdns3_endpoint *priv_ep; + struct cdns3_device *priv_dev; + unsigned long flags; + int ret; + u32 reg; + + priv_ep = ep_to_cdns3_ep(ep); + priv_dev = priv_ep->cdns3_dev; + + if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { + dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + return -EINVAL; + } + + if (!desc->wMaxPacketSize) { + dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n"); + return -EINVAL; + } + + if (dev_WARN_ONCE(priv_dev->dev, priv_ep->flags & EP_ENABLED, + "%s is already enabled\n", priv_ep->name)) + return 0; + + ret = cdns3_allocate_trb_pool(priv_ep); + if (ret) + return ret; + + trace_cdns3_gadget_ep_enable(priv_ep); + spin_lock_irqsave(&priv_dev->lock, flags); + + priv_ep->endpoint.desc = desc; + priv_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT; + priv_ep->type = usb_endpoint_type(desc); + + cdns3_select_ep(priv_dev, desc->bEndpointAddress); + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_CSTALL | EP_CMD_EPRST, 0, 100); + + cdns3_set_register_bit(&priv_dev->regs->ep_cfg, EP_CFG_ENABLE); + + ep->desc = desc; + priv_ep->flags &= ~(EP_PENDING_REQUEST | EP_STALL); + priv_ep->flags |= EP_ENABLED | EP_UPDATE_EP_TRBADDR; + priv_ep->enqueue = 0; + priv_ep->dequeue = 0; + reg = readl(&priv_dev->regs->ep_sts); + priv_ep->pcs = !!EP_STS_CCS(reg); + priv_ep->ccs = !!EP_STS_CCS(reg); + /* one TRB is reserved for link TRB used in DMULT mode*/ + priv_ep->free_trbs = TRBS_PER_SEGMENT - 1; + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_ep_disable Disable endpoint + * @ep: endpoint object + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_ep_disable(struct usb_ep *ep) +{ + struct cdns3_endpoint *priv_ep; + struct cdns3_device *priv_dev; + unsigned long flags; + int ret = 0; + struct usb_request *request; + u32 ep_cfg; + + if (!ep) { + dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + return -EINVAL; + } + + priv_ep = ep_to_cdns3_ep(ep); + priv_dev = priv_ep->cdns3_dev; + + if (dev_WARN_ONCE(priv_dev->dev, !(priv_ep->flags & EP_ENABLED), + "%s is already disabled\n", priv_ep->name)) + return 0; + + spin_lock_irqsave(&priv_dev->lock, flags); + + trace_cdns3_gadget_ep_disable(priv_ep); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + ret = cdns3_data_flush(priv_ep); + + ep_cfg = readl(&priv_dev->regs->ep_cfg); + ep_cfg &= ~EP_CFG_ENABLE; + writel(ep_cfg, &priv_dev->regs->ep_cfg); + + while (!list_empty(&priv_ep->request_list)) { + request = cdns3_next_request(&priv_ep->request_list); + + cdns3_gadget_giveback(priv_ep, to_cdns3_request(request), + -ESHUTDOWN); + } + + if (priv_ep->descmis_req) { + kfree(priv_ep->descmis_req->request.buf); + cdns3_gadget_ep_free_request(&priv_ep->endpoint, + &priv_ep->descmis_req->request); + priv_ep->descmis_req = NULL; + priv_ep->descmis_pending = false; + priv_ep->descmis_finished = false; + } + + ep->desc = NULL; + priv_ep->flags &= ~EP_ENABLED; + + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +/** + * cdns3_gadget_ep_queue Transfer data on endpoint + * @ep: endpoint object + * @request: request object + * @gfp_flags: gfp flags + * + * Returns 0 on success, error code elsewhere + */ +static int __cdns3_gadget_ep_queue(struct usb_ep *ep, + struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_request *priv_req; + int ret = 0; + + request->actual = 0; + request->status = -EINPROGRESS; + priv_req = to_cdns3_request(request); + + trace_cdns3_ep_queue(priv_req); + + /* Data will be copied from internal usb_request object. */ + if (priv_ep->descmis_finished) { + priv_ep->descmis_finished = false; + request->actual = priv_ep->descmis_req->request.actual; + + memcpy(request->buf, priv_ep->descmis_req->request.buf, + priv_ep->descmis_req->request.actual); + list_add_tail(&request->list, &priv_ep->request_list); + + cdns3_gadget_giveback(priv_ep, + priv_req, + priv_ep->descmis_req->request.status); + + return ret; + } + + ret = usb_gadget_map_request_by_dev(priv_dev->sysdev, request, + usb_endpoint_dir_in(ep->desc)); + if (ret) + return ret; + + list_add_tail(&request->list, &priv_ep->request_list); + + cdns3_ep_run_transfer(priv_ep, request); + + return ret; +} + +static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, + gfp_t gfp_flags) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *zlp_request; + unsigned long flags; + int ret; + + if (!request || !ep) + return -EINVAL; + + spin_lock_irqsave(&priv_dev->lock, flags); + ret = __cdns3_gadget_ep_queue(ep, request, gfp_flags); + + if (ret == 0 && request->zero && request->length && + (request->length % ep->maxpacket == 0)) { + struct cdns3_request *priv_req; + + zlp_request = cdns3_gadget_ep_alloc_request(ep, GFP_ATOMIC); + zlp_request->buf = priv_dev->zlp_buf; + zlp_request->length = 0; + + priv_req = to_cdns3_request(zlp_request); + priv_req->flags |= REQUEST_ZLP; + + dev_dbg(priv_dev->dev, "Queuing ZLP for endpoint: %s\n", + priv_ep->name); + ret = __cdns3_gadget_ep_queue(ep, zlp_request, gfp_flags); + } + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_gadget_ep_dequeue Remove request from transfer queue + * @ep: endpoint object associated with request + * @request: request object + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, + struct usb_request *request) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct usb_request *req, *req_temp; + struct cdns3_request *priv_req; + unsigned long flags; + int ret = 0; + + if (!ep || !request || !ep->desc) + return -EINVAL; + + spin_lock_irqsave(&priv_dev->lock, flags); + + priv_req = to_cdns3_request(request); + + trace_cdns3_ep_dequeue(priv_req); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + + list_for_each_entry_safe(req, req_temp, &priv_ep->request_list, list) { + if (request == req) { + cdns3_gadget_giveback(priv_ep, + priv_req, + -ECONNRESET); + break; + } + } + + spin_unlock_irqrestore(&priv_dev->lock, flags); + return ret; +} + +/** + * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint + * @ep: endpoint object to set/clear stall on + * @value: 1 for set stall, 0 for clear stall + * + * Returns 0 on success, error code elsewhere + */ +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value) +{ + struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); + struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + unsigned long flags; + int ret = 0; + + if (!(priv_ep->flags & EP_ENABLED)) + return -EPERM; + + spin_lock_irqsave(&priv_dev->lock, flags); + + /* if actual transfer is pending defer setting stall on this endpoint */ + if ((priv_ep->flags & EP_PENDING_REQUEST) && value) { + priv_ep->flags |= EP_STALL; + goto finish; + } + + dev_dbg(priv_dev->dev, "Halt endpoint %s\n", priv_ep->name); + + cdns3_select_ep(priv_dev, ep->desc->bEndpointAddress); + if (value) { + cdns3_ep_stall_flush(priv_ep); + } else { + priv_ep->flags &= ~EP_WEDGE; + writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + + /* wait for EPRST cleared */ + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + if (unlikely(ret)) { + dev_err(priv_dev->dev, + "Clearing halt condition failed for %s\n", + priv_ep->name); + goto finish; + + } else { + priv_ep->flags &= ~EP_STALL; + } + } + + priv_ep->flags &= ~EP_PENDING_REQUEST; +finish: + spin_unlock_irqrestore(&priv_dev->lock, flags); + + return ret; +} + +extern const struct usb_ep_ops cdns3_gadget_ep0_ops; + +static const struct usb_ep_ops cdns3_gadget_ep_ops = { + .enable = cdns3_gadget_ep_enable, + .disable = cdns3_gadget_ep_disable, + .alloc_request = cdns3_gadget_ep_alloc_request, + .free_request = cdns3_gadget_ep_free_request, + .queue = cdns3_gadget_ep_queue, + .dequeue = cdns3_gadget_ep_dequeue, + .set_halt = cdns3_gadget_ep_set_halt, + .set_wedge = cdns3_gadget_ep_set_wedge, +}; + +/** + * cdns3_gadget_get_frame Returns number of actual ITP frame + * @gadget: gadget object + * + * Returns number of actual ITP frame + */ +static int cdns3_gadget_get_frame(struct usb_gadget *gadget) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + + return readl(&priv_dev->regs->usb_iptn); +} + +static int cdns3_gadget_wakeup(struct usb_gadget *gadget) +{ + return 0; +} + +static int cdns3_gadget_set_selfpowered(struct usb_gadget *gadget, + int is_selfpowered) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_dev->is_selfpowered = !!is_selfpowered; + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +static int cdns3_gadget_pullup(struct usb_gadget *gadget, int is_on) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + + if (is_on) + writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf); + else + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); + + return 0; +} + +static void cdns3_gadget_config(struct cdns3_device *priv_dev) +{ + struct cdns3_usb_regs __iomem *regs = priv_dev->regs; + + cdns3_ep0_config(priv_dev); + + /* enable interrupts for endpoint 0 (in and out) */ + writel(EP_IEN_EP_OUT0 | EP_IEN_EP_IN0, ®s->ep_ien); + + /* enable generic interrupt*/ + writel(USB_IEN_INIT, ®s->usb_ien); + writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); + writel(USB_CONF_DMULT, ®s->usb_conf); + writel(USB_CONF_DEVEN, ®s->usb_conf); +} + +/** + * cdns3_gadget_udc_start Gadget start + * @gadget: gadget object + * @driver: driver which operates on this gadget + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_gadget_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + unsigned long flags; + + spin_lock_irqsave(&priv_dev->lock, flags); + priv_dev->gadget_driver = driver; + cdns3_gadget_config(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_udc_stop Stops gadget + * @gadget: gadget object + * + * Returns 0 + */ +static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) +{ + struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); + struct cdns3_endpoint *priv_ep; + u32 bEndpointAddress; + struct usb_ep *ep; + int ret = 0; + int i; + + priv_dev->gadget_driver = NULL; + + priv_dev->onchip_mem_allocated_size = 0; + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + + for (i = 0; i < priv_dev->ep_nums ; i++) + cdns3_free_trb_pool(priv_dev->eps[i]); + + list_for_each_entry(ep, &priv_dev->gadget.ep_list, ep_list) { + priv_ep = ep_to_cdns3_ep(ep); + bEndpointAddress = priv_ep->num | priv_ep->dir; + cdns3_select_ep(priv_dev, bEndpointAddress); + writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); + ret = cdns3_handshake(&priv_dev->regs->ep_cmd, + EP_CMD_EPRST, 0, 100); + } + + /* disable interrupt for device */ + writel(0, &priv_dev->regs->usb_ien); + writel(USB_CONF_DEVDS, &priv_dev->regs->usb_conf); + + return ret; +} + +static const struct usb_gadget_ops cdns3_gadget_ops = { + .get_frame = cdns3_gadget_get_frame, + .wakeup = cdns3_gadget_wakeup, + .set_selfpowered = cdns3_gadget_set_selfpowered, + .pullup = cdns3_gadget_pullup, + .udc_start = cdns3_gadget_udc_start, + .udc_stop = cdns3_gadget_udc_stop, + .match_ep = cdns3_gadget_match_ep, +}; + +static void cdns3_free_all_ep(struct cdns3_device *priv_dev) +{ + int i; + + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) + if (priv_dev->eps[i]) + devm_kfree(priv_dev->dev, priv_dev->eps[i]); + + if (priv_dev->gadget.ep0) + devm_kfree(priv_dev->dev, priv_dev->gadget.ep0); +} + +/** + * cdns3_init_ep Initializes software endpoints of gadget + * @cdns3: extended gadget object + * + * Returns 0 on success, error code elsewhere + */ +static int cdns3_init_ep(struct cdns3_device *priv_dev) +{ + u32 ep_enabled_reg, iso_ep_reg; + struct cdns3_endpoint *priv_ep; + int found_endpoints = 0; + int ep_dir, ep_number; + u32 ep_mask; + int i; + + /* Read it from USB_CAP3 to USB_CAP5 */ + ep_enabled_reg = readl(&priv_dev->regs->usb_cap3); + iso_ep_reg = readl(&priv_dev->regs->usb_cap4); + + dev_dbg(priv_dev->dev, "Initializing non-zero endpoints\n"); + + for (i = 0; i < CDNS3_ENDPOINTS_MAX_COUNT; i++) { + ep_number = (i / 2) + 1; + ep_dir = i % 2; + ep_mask = BIT((16 * ep_dir) + ep_number); + + if (!(ep_enabled_reg & ep_mask)) + continue; + + priv_ep = devm_kzalloc(priv_dev->dev, sizeof(*priv_ep), + GFP_KERNEL); + if (!priv_ep) + return -ENOMEM; + + /* set parent of endpoint object */ + priv_ep->cdns3_dev = priv_dev; + priv_dev->eps[found_endpoints++] = priv_ep; + + snprintf(priv_ep->name, sizeof(priv_ep->name), "ep%d%s", + ep_number, !!ep_dir ? "in" : "out"); + priv_ep->endpoint.name = priv_ep->name; + + usb_ep_set_maxpacket_limit(&priv_ep->endpoint, + CDNS3_EP_MAX_PACKET_LIMIT); + priv_ep->endpoint.max_streams = CDNS3_EP_MAX_STREAMS; + priv_ep->endpoint.ops = &cdns3_gadget_ep_ops; + if (ep_dir) + priv_ep->endpoint.caps.dir_in = 1; + else + priv_ep->endpoint.caps.dir_out = 1; + + if (iso_ep_reg & ep_mask) + priv_ep->endpoint.caps.type_iso = 1; + + priv_ep->endpoint.caps.type_bulk = 1; + priv_ep->endpoint.caps.type_int = 1; + priv_ep->endpoint.maxburst = CDNS3_EP_BUF_SIZE - 1; + + priv_ep->flags = 0; + + dev_info(priv_dev->dev, "Initialized %s support: %s %s\n", + priv_ep->name, + priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "", + priv_ep->endpoint.caps.type_iso ? "ISO" : ""); + + list_add_tail(&priv_ep->endpoint.ep_list, + &priv_dev->gadget.ep_list); + INIT_LIST_HEAD(&priv_ep->request_list); + } + + priv_dev->ep_nums = found_endpoints; + return 0; +} + +static void cdns3_gadget_disable(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + + priv_dev = cdns->gadget_dev; + + if (priv_dev->gadget_driver) + priv_dev->gadget_driver->disconnect(&priv_dev->gadget); + + usb_gadget_disconnect(&priv_dev->gadget); + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; +} + +void cdns3_gadget_exit(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + + priv_dev = cdns->gadget_dev; + + cdns3_gadget_disable(cdns); + + devm_free_irq(cdns->dev, cdns->irq, cdns); + + pm_runtime_mark_last_busy(cdns->dev); + pm_runtime_put_autosuspend(cdns->dev); + + usb_del_gadget_udc(&priv_dev->gadget); + + cdns3_free_all_ep(priv_dev); + + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, + priv_dev->setup_dma); + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->ep0_trb, + priv_dev->ep0_trb_dma); + + kfree(priv_dev->zlp_buf); + kfree(priv_dev); + cdns->gadget_dev = NULL; +} + +static int cdns3_gadget_start(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + u32 max_speed; + int ret; + + priv_dev = kzalloc(sizeof(*priv_dev), GFP_KERNEL); + if (!priv_dev) + return -ENOMEM; + + cdns->gadget_dev = priv_dev; + priv_dev->sysdev = cdns->dev; + priv_dev->dev = cdns->dev; + priv_dev->regs = cdns->dev_regs; + + max_speed = usb_get_maximum_speed(cdns->dev); + + /* Check the maximum_speed parameter */ + switch (max_speed) { + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", + max_speed); + /* fall through */ + case USB_SPEED_UNKNOWN: + /* default to superspeed */ + max_speed = USB_SPEED_SUPER; + break; + } + + /* fill gadget fields */ + priv_dev->gadget.max_speed = max_speed; + priv_dev->gadget.speed = USB_SPEED_UNKNOWN; + priv_dev->gadget.ops = &cdns3_gadget_ops; + priv_dev->gadget.name = "usb-ss-gadget"; + priv_dev->gadget.sg_supported = 1; + + spin_lock_init(&priv_dev->lock); + INIT_WORK(&priv_dev->pending_status_wq, + cdns3_pending_setup_status_handler); + + /* initialize endpoint container */ + INIT_LIST_HEAD(&priv_dev->gadget.ep_list); + + ret = cdns3_init_ep0(priv_dev); + if (ret) { + dev_err(priv_dev->dev, "Failed to create endpoint 0\n"); + goto err1; + } + + ret = cdns3_init_ep(priv_dev); + if (ret) { + dev_err(priv_dev->dev, "Failed to create non zero endpoints\n"); + goto err1; + } + + /* allocate memory for default endpoint TRB */ + priv_dev->ep0_trb = dma_alloc_coherent(priv_dev->sysdev, TRB_SIZE * 2, + &priv_dev->ep0_trb_dma, GFP_DMA); + if (!priv_dev->ep0_trb) { + dev_err(priv_dev->dev, "Failed to allocate memory for ep0 TRB\n"); + ret = -ENOMEM; + goto err1; + } + + /* allocate memory for setup packet buffer */ + priv_dev->setup_buf = dma_alloc_coherent(priv_dev->sysdev, 8, + &priv_dev->setup_dma, GFP_DMA); + if (!priv_dev->setup_buf) { + dev_err(priv_dev->dev, "Failed to allocate memory for SETUP buffer\n"); + ret = -ENOMEM; + goto err2; + } + + dev_dbg(priv_dev->dev, "Device Controller version: %08x\n", + readl(&priv_dev->regs->usb_cap6)); + dev_dbg(priv_dev->dev, "USB Capabilities:: %08x\n", + readl(&priv_dev->regs->usb_cap1)); + dev_dbg(priv_dev->dev, "On-Chip memory cnfiguration: %08x\n", + readl(&priv_dev->regs->usb_cap2)); + + priv_dev->zlp_buf = kzalloc(CDNS3_EP_ZLP_BUF_SIZE, GFP_KERNEL); + if (!priv_dev->zlp_buf) { + ret = -ENOMEM; + goto err3; + } + + /* add USB gadget device */ + ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget); + if (ret < 0) { + dev_err(priv_dev->dev, + "Failed to register USB device controller\n"); + goto err4; + } + + return 0; +err4: + kfree(priv_dev->zlp_buf); +err3: + dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf, + priv_dev->setup_dma); +err2: + dma_free_coherent(priv_dev->sysdev, TRB_SIZE * 2, priv_dev->ep0_trb, + priv_dev->ep0_trb_dma); +err1: + cdns->gadget_dev = NULL; + return ret; +} + +static int __cdns3_gadget_init(struct cdns3 *cdns) +{ + struct cdns3_device *priv_dev; + unsigned long flags; + int ret = 0; + + ret = cdns3_gadget_start(cdns); + if (ret) + return ret; + + priv_dev = cdns->gadget_dev; + ret = devm_request_irq(cdns->dev, cdns->irq, cdns3_device_irq_handler, + IRQF_SHARED, dev_name(cdns->dev), cdns); + + if (ret) + goto err0; + + pm_runtime_get_sync(cdns->dev); + spin_lock_irqsave(&priv_dev->lock, flags); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +err0: + cdns3_gadget_exit(cdns); + return ret; +} + +static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) +{ + cdns3_gadget_disable(cdns); + return 0; +} + +static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) +{ + struct cdns3_device *priv_dev; + unsigned long flags; + + priv_dev = cdns->gadget_dev; + spin_lock_irqsave(&priv_dev->lock, flags); + + if (!priv_dev->gadget_driver) { + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; + } + + cdns3_gadget_config(priv_dev); + spin_unlock_irqrestore(&priv_dev->lock, flags); + return 0; +} + +/** + * cdns3_gadget_init - initialize device structure + * + * cdns: cdns3 instance + * + * This function initializes the gadget. + */ +int cdns3_gadget_init(struct cdns3 *cdns) +{ + struct cdns3_role_driver *rdrv; + + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = __cdns3_gadget_init; + rdrv->stop = cdns3_gadget_exit; + rdrv->suspend = cdns3_gadget_suspend; + rdrv->resume = cdns3_gadget_resume; + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; + rdrv->name = "gadget"; + cdns->roles[CDNS3_ROLE_GADGET] = rdrv; + + return 0; +} diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h new file mode 100644 index 000000000000..db398dff65fc --- /dev/null +++ b/drivers/usb/cdns3/gadget.h @@ -0,0 +1,1177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver header file + * + * Copyright (C) 2018 Cadence. + * Copyright (C) 2017-2018 NXP + * + * Author: Pawel Laszczak + * Pawel Jez + * Peter Chen + */ +#ifndef __LINUX_CDNS3_GADGET +#define __LINUX_CDNS3_GADGET +#include + +/* + * USBSS-DEV register interface. + * This corresponds to the USBSS Device Controller Interface + */ + +/** + * struct cdns3_usb_regs - device controller registers. + * @usb_conf: Global Configuration Register. + * @usb_sts: Global Status Register. + * @usb_cmd: Global Command Register. + * @usb_iptn: ITP/SOF number Register. + * @usb_lpm: Global Command Register. + * @usb_ien: USB Interrupt Enable Register. + * @usb_ists: USB Interrupt Status Register. + * @ep_sel: Endpoint Select Register. + * @ep_traddr: Endpoint Transfer Ring Address Register. + * @ep_cfg: Endpoint Configuration Register. + * @ep_cmd: Endpoint Command Register. + * @ep_sts: Endpoint Status Register. + * @ep_sts_sid: Endpoint Status Register. + * @ep_sts_en: Endpoint Status Register Enable. + * @drbl: Doorbell Register. + * @ep_ien: EP Interrupt Enable Register. + * @ep_ists: EP Interrupt Status Register. + * @usb_pwr: Global Power Configuration Register. + * @usb_conf2: Global Configuration Register 2. + * @usb_cap1: Capability Register 1. + * @usb_cap2: Capability Register 2. + * @usb_cap3: Capability Register 3. + * @usb_cap4: Capability Register 4. + * @usb_cap5: Capability Register 5. + * @usb_cap6: Capability Register 6. + * @usb_cpkt1: Custom Packet Register 1. + * @usb_cpkt2: Custom Packet Register 2. + * @usb_cpkt3: Custom Packet Register 3. + * @reserved1: Reserved. + * @cfg_regs: Configuration registers. + * @reserved2: Reserved. + * @dma_axi_ctrl: AXI Control register. + * @dma_axi_id: AXI ID register. + * @dma_axi_cap: AXI Capability register. + * @dma_axi_ctrl0: AXI Control 0 register. + * @dma_axi_ctrl1: AXI Control 1 register. + */ +struct cdns3_usb_regs { + __le32 usb_conf; + __le32 usb_sts; + __le32 usb_cmd; + __le32 usb_iptn; + __le32 usb_lpm; + __le32 usb_ien; + __le32 usb_ists; + __le32 ep_sel; + __le32 ep_traddr; + __le32 ep_cfg; + __le32 ep_cmd; + __le32 ep_sts; + __le32 ep_sts_sid; + __le32 ep_sts_en; + __le32 drbl; + __le32 ep_ien; + __le32 ep_ists; + __le32 usb_pwr; + __le32 usb_conf2; + __le32 usb_cap1; + __le32 usb_cap2; + __le32 usb_cap3; + __le32 usb_cap4; + __le32 usb_cap5; + __le32 usb_cap6; + __le32 usb_cpkt1; + __le32 usb_cpkt2; + __le32 usb_cpkt3; + __le32 reserved1[36]; + __le32 cfg_reg1; + __le32 dbg_link1; + __le32 dbg_link2; + __le32 cfg_regs[74]; + __le32 reserved2[34]; + __le32 dma_axi_ctrl; + __le32 dma_axi_id; + __le32 dma_axi_cap; + __le32 dma_axi_ctrl0; + __le32 dma_axi_ctrl1; +}; + +/* USB_CONF - bitmasks */ +/* Reset USB device configuration. */ +#define USB_CONF_CFGRST BIT(0) +/* Set Configuration. */ +#define USB_CONF_CFGSET BIT(1) +/* Disconnect USB device in SuperSpeed. */ +#define USB_CONF_USB3DIS BIT(3) +/* Disconnect USB device in HS/FS */ +#define USB_CONF_USB2DIS BIT(4) +/* Little Endian access - default */ +#define USB_CONF_LENDIAN BIT(5) +/* + * Big Endian access. Driver assume that byte order for + * SFRs access always is as Little Endian so this bit + * is not used. + */ +#define USB_CONF_BENDIAN BIT(6) +/* Device software reset. */ +#define USB_CONF_SWRST BIT(7) +/* Singular DMA transfer mode. */ +#define USB_CONF_DSING BIT(8) +/* Multiple DMA transfers mode. */ +#define USB_CONF_DMULT BIT(9) +/* DMA clock turn-off enable. */ +#define USB_CONF_DMAOFFEN BIT(10) +/* DMA clock turn-off disable. */ +#define USB_CONF_DMAOFFDS BIT(11) +/* Clear Force Full Speed. */ +#define USB_CONF_CFORCE_FS BIT(12) +/* Set Force Full Speed. */ +#define USB_CONF_SFORCE_FS BIT(13) +/* Device enable. */ +#define USB_CONF_DEVEN BIT(14) +/* Device disable. */ +#define USB_CONF_DEVDS BIT(15) +/* L1 LPM state entry enable (used in HS/FS mode). */ +#define USB_CONF_L1EN BIT(16) +/* L1 LPM state entry disable (used in HS/FS mode). */ +#define USB_CONF_L1DS BIT(17) +/* USB 2.0 clock gate disable. */ +#define USB_CONF_CLK2OFFEN BIT(18) +/* USB 2.0 clock gate enable. */ +#define USB_CONF_CLK2OFFDS BIT(19) +/* L0 LPM state entry request (used in HS/FS mode). */ +#define USB_CONF_LGO_L0 BIT(20) +/* USB 3.0 clock gate disable. */ +#define USB_CONF_CLK3OFFEN BIT(21) +/* USB 3.0 clock gate enable. */ +#define USB_CONF_CLK3OFFDS BIT(22) +/* Bit 23 is reserved*/ +/* U1 state entry enable (used in SS mode). */ +#define USB_CONF_U1EN BIT(24) +/* U1 state entry disable (used in SS mode). */ +#define USB_CONF_U1DS BIT(25) +/* U2 state entry enable (used in SS mode). */ +#define USB_CONF_U2EN BIT(26) +/* U2 state entry disable (used in SS mode). */ +#define USB_CONF_U2DS BIT(27) +/* U0 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U0 BIT(28) +/* U1 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U1 BIT(29) +/* U2 state entry request (used in SS mode). */ +#define USB_CONF_LGO_U2 BIT(30) +/* SS.Inactive state entry request (used in SS mode) */ +#define USB_CONF_LGO_SSINACT BIT(31) + +/* USB_STS - bitmasks */ +/* + * Configuration status. + * 1 - device is in the configured state. + * 0 - device is not configured. + */ +#define USB_STS_CFGSTS_MASK BIT(0) +#define USB_STS_CFGSTS(p) ((p) & USB_STS_CFGSTS_MASK) +/* + * On-chip memory overflow. + * 0 - On-chip memory status OK. + * 1 - On-chip memory overflow. + */ +#define USB_STS_OV_MASK BIT(1) +#define USB_STS_OV(p) ((p) & USB_STS_OV_MASK) +/* + * SuperSpeed connection status. + * 0 - USB in SuperSpeed mode disconnected. + * 1 - USB in SuperSpeed mode connected. + */ +#define USB_STS_USB3CONS_MASK BIT(2) +#define USB_STS_USB3CONS(p) ((p) & USB_STS_USB3CONS_MASK) +/* + * DMA transfer configuration status. + * 0 - single request. + * 1 - multiple TRB chain + */ +#define USB_STS_DTRANS_MASK BIT(3) +#define USB_STS_DTRANS(p) ((p) & USB_STS_DTRANS_MASK) +/* + * Device speed. + * 0 - Undefined (value after reset). + * 1 - Low speed + * 2 - Full speed + * 3 - High speed + * 4 - Super speed + */ +#define USB_STS_USBSPEED_MASK GENMASK(6, 4) +#define USB_STS_USBSPEED(p) (((p) & USB_STS_USBSPEED_MASK) >> 4) +#define USB_STS_LS (0x1 << 4) +#define USB_STS_FS (0x2 << 4) +#define USB_STS_HS (0x3 << 4) +#define USB_STS_SS (0x4 << 4) +#define DEV_UNDEFSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == (0x0 << 4)) +#define DEV_LOWSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_LS) +#define DEV_FULLSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_FS) +#define DEV_HIGHSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_HS) +#define DEV_SUPERSPEED(p) (((p) & USB_STS_USBSPEED_MASK) == USB_STS_SS) +/* + * Endianness for SFR access. + * 0 - Little Endian order (default after hardware reset). + * 1 - Big Endian order + */ +#define USB_STS_ENDIAN_MASK BIT(7) +#define USB_STS_ENDIAN(p) ((p) & USB_STS_ENDIAN_MASK) +/* + * HS/FS clock turn-off status. + * 0 - hsfs clock is always on. + * 1 - hsfs clock turn-off in L2 (HS/FS mode) is enabled + * (default after hardware reset). + */ +#define USB_STS_CLK2OFF_MASK BIT(8) +#define USB_STS_CLK2OFF(p) ((p) & USB_STS_CLK2OFF_MASK) +/* + * PCLK clock turn-off status. + * 0 - pclk clock is always on. + * 1 - pclk clock turn-off in U3 (SS mode) is enabled + * (default after hardware reset). + */ +#define USB_STS_CLK3OFF_MASK BIT(9) +#define USB_STS_CLK3OFF(p) ((p) & USB_STS_CLK3OFF_MASK) +/* + * Controller in reset state. + * 0 - Internal reset is active. + * 1 - Internal reset is not active and controller is fully operational. + */ +#define USB_STS_IN_RST_MASK BIT(10) +#define USB_STS_IN_RST(p) ((p) & USB_STS_IN_RST_MASK) +/* + * Device enable Status. + * 0 - USB device is disabled (VBUS input is disconnected from internal logic). + * 1 - USB device is enabled (VBUS input is connected to the internal logic). + */ +#define USB_STS_DEVS_MASK BIT(14) +#define USB_STS_DEVS(p) ((p) & USB_STS_DEVS_MASK) +/* + * DAddress statuss. + * 0 - USB device is default state. + * 1 - USB device is at least in address state. + */ +#define USB_STS_ADDRESSED_MASK BIT(15) +#define USB_STS_ADDRESSED(p) ((p) & USB_STS_ADDRESSED_MASK) +/* + * L1 LPM state enable status (used in HS/FS mode). + * 0 - Entering to L1 LPM state disabled. + * 1 - Entering to L1 LPM state enabled. + */ +#define USB_STS_L1ENS_MASK BIT(16) +#define USB_STS_L1ENS(p) ((p) & USB_STS_L1ENS_MASK) +/* + * Internal VBUS connection status (used both in HS/FS and SS mode). + * 0 - internal VBUS is not detected. + * 1 - internal VBUS is detected. + */ +#define USB_STS_VBUSS_MASK BIT(17) +#define USB_STS_VBUSS(p) ((p) & USB_STS_VBUSS_MASK) +/* + * HS/FS LPM state (used in FS/HS mode). + * 0 - L0 State + * 1 - L1 State + * 2 - L2 State + * 3 - L3 State + */ +#define USB_STS_LPMST_MASK GENMASK(19, 18) +#define DEV_L0_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x0 << 18)) +#define DEV_L1_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x1 << 18)) +#define DEV_L2_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x2 << 18)) +#define DEV_L3_STATE(p) (((p) & USB_STS_LPMST_MASK) == (0x3 << 18)) +/* + * Disable HS status (used in FS/HS mode). + * 0 - the disconnect bit for HS/FS mode is set . + * 1 - the disconnect bit for HS/FS mode is not set. + */ +#define USB_STS_USB2CONS_MASK BIT(20) +#define USB_STS_USB2CONS(p) ((p) & USB_STS_USB2CONS_MASK) +/* + * HS/FS mode connection status (used in FS/HS mode). + * 0 - High Speed operations in USB2.0 (FS/HS) mode not disabled. + * 1 - High Speed operations in USB2.0 (FS/HS). + */ +#define USB_STS_DISABLE_HS_MASK BIT(21) +#define USB_STS_DISABLE_HS(p) ((p) & USB_STS_DISABLE_HS_MASK) +/* + * U1 state enable status (used in SS mode). + * 0 - Entering to U1 state disabled. + * 1 - Entering to U1 state enabled. + */ +#define USB_STS_U1ENS_MASK BIT(24) +#define USB_STS_U1ENS(p) ((p) & USB_STS_U1ENS_MASK) +/* + * U2 state enable status (used in SS mode). + * 0 - Entering to U2 state disabled. + * 1 - Entering to U2 state enabled. + */ +#define USB_STS_U2ENS_MASK BIT(25) +#define USB_STS_U2ENS(p) ((p) & USB_STS_U2ENS_MASK) +/* + * SuperSpeed Link LTSSM state. This field reflects USBSS-DEV current + * SuperSpeed link state + */ +#define USB_STS_LST_MASK GENMASK(29, 26) +#define DEV_LST_U0 (((p) & USB_STS_LST_MASK) == (0x0 << 26)) +#define DEV_LST_U1 (((p) & USB_STS_LST_MASK) == (0x1 << 26)) +#define DEV_LST_U2 (((p) & USB_STS_LST_MASK) == (0x2 << 26)) +#define DEV_LST_U3 (((p) & USB_STS_LST_MASK) == (0x3 << 26)) +#define DEV_LST_DISABLED (((p) & USB_STS_LST_MASK) == (0x4 << 26)) +#define DEV_LST_RXDETECT (((p) & USB_STS_LST_MASK) == (0x5 << 26)) +#define DEV_LST_INACTIVE (((p) & USB_STS_LST_MASK) == (0x6 << 26)) +#define DEV_LST_POLLING (((p) & USB_STS_LST_MASK) == (0x7 << 26)) +#define DEV_LST_RECOVERY (((p) & USB_STS_LST_MASK) == (0x8 << 26)) +#define DEV_LST_HOT_RESET (((p) & USB_STS_LST_MASK) == (0x9 << 26)) +#define DEV_LST_COMP_MODE (((p) & USB_STS_LST_MASK) == (0xa << 26)) +#define DEV_LST_LB_STATE (((p) & USB_STS_LST_MASK) == (0xb << 26)) +/* + * DMA clock turn-off status. + * 0 - DMA clock is always on (default after hardware reset). + * 1 - DMA clock turn-off in U1, U2 and U3 (SS mode) is enabled. + */ +#define USB_STS_DMAOFF_MASK BIT(30) +#define USB_STS_DMAOFF(p) ((p) & USB_STS_DMAOFF_MASK) +/* + * SFR Endian statuss. + * 0 - Little Endian order (default after hardware reset). + * 1 - Big Endian order. + */ +#define USB_STS_ENDIAN2_MASK BIT(31) +#define USB_STS_ENDIAN2(p) ((p) & USB_STS_ENDIAN2_MASK) + +/* USB_CMD - bitmasks */ +/* Set Function Address */ +#define USB_CMD_SET_ADDR BIT(0) +/* + * Function Address This field is saved to the device only when the field + * SET_ADDR is set '1 ' during write to USB_CMD register. + * Software is responsible for entering the address of the device during + * SET_ADDRESS request service. This field should be set immediately after + * the SETUP packet is decoded, and prior to confirmation of the status phase + */ +#define USB_CMD_FADDR_MASK GENMASK(7, 1) +#define USB_CMD_FADDR(p) (((p) << 1) & USB_CMD_FADDR_MASK) +/* Send Function Wake Device Notification TP (used only in SS mode). */ +#define USB_CMD_SDNFW BIT(8) +/* Set Test Mode (used only in HS/FS mode). */ +#define USB_CMD_STMODE BIT(9) +/* Test mode selector (used only in HS/FS mode) */ +#define USB_STS_TMODE_SEL_MASK GENMASK(11, 10) +#define USB_STS_TMODE_SEL(p) (((p) << 10) & USB_STS_TMODE_SEL_MASK) +/* + * Send Latency Tolerance Message Device Notification TP (used only + * in SS mode). + */ +#define USB_CMD_SDNLTM BIT(12) +/* Send Custom Transaction Packet (used only in SS mode) */ +#define USB_CMD_SPKT BIT(13) +/*Device Notification 'Function Wake' - Interface value (only in SS mode. */ +#define USB_CMD_DNFW_INT_MASK GENMASK(23, 16) +#define USB_STS_DNFW_INT(p) (((p) << 16) & USB_CMD_DNFW_INT_MASK) +/* + * Device Notification 'Latency Tolerance Message' -373 BELT value [7:0] + * (used only in SS mode). + */ +#define USB_CMD_DNLTM_BELT_MASK GENMASK(27, 16) +#define USB_STS_DNLTM_BELT(p) (((p) << 16) & USB_CMD_DNLTM_BELT_MASK) + +/* USB_ITPN - bitmasks */ +/* + * ITP(SS) / SOF (HS/FS) number + * In SS mode this field represent number of last ITP received from host. + * In HS/FS mode this field represent number of last SOF received from host. + */ +#define USB_ITPN_MASK GENMASK(13, 0) +#define USB_ITPN(p) ((p) & USB_ITPN_MASK) + +/* USB_LPM - bitmasks */ +/* Host Initiated Resume Duration. */ +#define USB_LPM_HIRD_MASK GENMASK(3, 0) +#define USB_LPM_HIRD(p) ((p) & USB_LPM_HIRD_MASK) +/* Remote Wakeup Enable (bRemoteWake). */ +#define USB_LPM_BRW BIT(4) + +/* USB_IEN - bitmasks */ +/* SS connection interrupt enable */ +#define USB_IEN_CONIEN BIT(0) +/* SS disconnection interrupt enable. */ +#define USB_IEN_DISIEN BIT(1) +/* USB SS warm reset interrupt enable. */ +#define USB_IEN_UWRESIEN BIT(2) +/* USB SS hot reset interrupt enable */ +#define USB_IEN_UHRESIEN BIT(3) +/* SS link U3 state enter interrupt enable (suspend).*/ +#define USB_IEN_U3ENTIEN BIT(4) +/* SS link U3 state exit interrupt enable (wakeup). */ +#define USB_IEN_U3EXTIEN BIT(5) +/* SS link U2 state enter interrupt enable.*/ +#define USB_IEN_U2ENTIEN BIT(6) +/* SS link U2 state exit interrupt enable.*/ +#define USB_IEN_U2EXTIEN BIT(7) +/* SS link U1 state enter interrupt enable.*/ +#define USB_IEN_U1ENTIEN BIT(8) +/* SS link U1 state exit interrupt enable.*/ +#define USB_IEN_U1EXTIEN BIT(9) +/* ITP/SOF packet detected interrupt enable.*/ +#define USB_IEN_ITPIEN BIT(10) +/* Wakeup interrupt enable.*/ +#define USB_IEN_WAKEIEN BIT(11) +/* Send Custom Packet interrupt enable.*/ +#define USB_IEN_SPKTIEN BIT(12) +/* HS/FS mode connection interrupt enable.*/ +#define USB_IEN_CON2IEN BIT(16) +/* HS/FS mode disconnection interrupt enable.*/ +#define USB_IEN_DIS2IEN BIT(17) +/* USB reset (HS/FS mode) interrupt enable.*/ +#define USB_IEN_U2RESIEN BIT(18) +/* LPM L2 state enter interrupt enable.*/ +#define USB_IEN_L2ENTIEN BIT(20) +/* LPM L2 state exit interrupt enable.*/ +#define USB_IEN_L2EXTIEN BIT(21) +/* LPM L1 state enter interrupt enable.*/ +#define USB_IEN_L1ENTIEN BIT(24) +/* LPM L1 state exit interrupt enable.*/ +#define USB_IEN_L1EXTIEN BIT(25) +/* Configuration reset interrupt enable.*/ +#define USB_IEN_CFGRESIEN BIT(26) +/* Start of the USB SS warm reset interrupt enable.*/ +#define USB_IEN_UWRESSIEN BIT(28) +/* End of the USB SS warm reset interrupt enable.*/ +#define USB_IEN_UWRESEIEN BIT(29) + +#define USB_IEN_INIT (USB_IEN_U2RESIEN | USB_ISTS_DIS2I | USB_IEN_CON2IEN \ + | USB_IEN_UHRESIEN | USB_IEN_UWRESIEN | USB_IEN_DISIEN \ + | USB_IEN_CONIEN | USB_IEN_U3EXTIEN | USB_IEN_L2ENTIEN \ + | USB_IEN_L2EXTIEN) + +/* USB_ISTS - bitmasks */ +/* SS Connection detected. */ +#define USB_ISTS_CONI BIT(0) +/* SS Disconnection detected. */ +#define USB_ISTS_DISI BIT(1) +/* UUSB warm reset detectede. */ +#define USB_ISTS_UWRESI BIT(2) +/* USB hot reset detected. */ +#define USB_ISTS_UHRESI BIT(3) +/* U3 link state enter detected (suspend).*/ +#define USB_ISTS_U3ENTI BIT(4) +/* U3 link state exit detected (wakeup). */ +#define USB_ISTS_U3EXTI BIT(5) +/* U2 link state enter detected.*/ +#define USB_ISTS_U2ENTI BIT(6) +/* U2 link state exit detected.*/ +#define USB_ISTS_U2EXTI BIT(7) +/* U1 link state enter detected.*/ +#define USB_ISTS_U1ENTI BIT(8) +/* U1 link state exit detected.*/ +#define USB_ISTS_U1EXTI BIT(9) +/* ITP/SOF packet detected.*/ +#define USB_ISTS_ITPI BIT(10) +/* Wakeup detected.*/ +#define USB_ISTS_WAKEI BIT(11) +/* Send Custom Packet detected.*/ +#define USB_ISTS_SPKTI BIT(12) +/* HS/FS mode connection detected.*/ +#define USB_ISTS_CON2I BIT(16) +/* HS/FS mode disconnection detected.*/ +#define USB_ISTS_DIS2I BIT(17) +/* USB reset (HS/FS mode) detected.*/ +#define USB_ISTS_U2RESI BIT(18) +/* LPM L2 state enter detected.*/ +#define USB_ISTS_L2ENTI BIT(20) +/* LPM L2 state exit detected.*/ +#define USB_ISTS_L2EXTI BIT(21) +/* LPM L1 state enter detected.*/ +#define USB_ISTS_L1ENTI BIT(24) +/* LPM L1 state exit detected.*/ +#define USB_ISTS_L1EXTI BIT(25) +/* USB configuration reset detected.*/ +#define USB_ISTS_CFGRESI BIT(26) +/* Start of the USB warm reset detected.*/ +#define USB_ISTS_UWRESSI BIT(28) +/* End of the USB warm reset detected.*/ +#define USB_ISTS_UWRESEI BIT(29) + +/* USB_SEL - bitmasks */ +#define EP_SEL_EPNO_MASK GENMASK(3, 0) +/* Endpoint number. */ +#define EP_SEL_EPNO(p) ((p) & EP_SEL_EPNO_MASK) +/* Endpoint direction bit - 0 - OUT, 1 - IN. */ +#define EP_SEL_DIR BIT(7) + +#define select_ep_in(nr) (EP_SEL_EPNO(p) | EP_SEL_DIR) +#define select_ep_out (EP_SEL_EPNO(p)) + +/* EP_TRADDR - bitmasks */ +/* Transfer Ring address. */ +#define EP_TRADDR_TRADDR(p) ((p)) + +/* EP_CFG - bitmasks */ +/* Endpoint enable */ +#define EP_CFG_ENABLE BIT(0) +/* + * Endpoint type. + * 1 - isochronous + * 2 - bulk + * 3 - interrupt + */ +#define EP_CFG_EPTYPE_MASK GENMASK(2, 1) +#define EP_CFG_EPTYPE(p) (((p) << 1) & EP_CFG_EPTYPE_MASK) +/* Stream support enable (only in SS mode). */ +#define EP_CFG_STREAM_EN BIT(3) +/* TDL check (only in SS mode for BULK EP). */ +#define EP_CFG_TDL_CHK BIT(4) +/* SID check (only in SS mode for BULK OUT EP). */ +#define EP_CFG_SID_CHK BIT(5) +/* DMA transfer endianness. */ +#define EP_CFG_EPENDIAN BIT(7) +/* Max burst size (used only in SS mode). */ +#define EP_CFG_MAXBURST_MASK GENMASK(11, 8) +#define EP_CFG_MAXBURST(p) (((p) << 8) & EP_CFG_MAXBURST_MASK) +/* ISO max burst. */ +#define EP_CFG_MULT_MASK GENMASK(15, 14) +#define EP_CFG_MULT(p) (((p) << 14) & EP_CFG_MULT) +/* ISO max burst. */ +#define EP_CFG_MAXPKTSIZE_MASK GENMASK(26, 16) +#define EP_CFG_MAXPKTSIZE(p) (((p) << 16) & EP_CFG_MAXPKTSIZE_MASK) +/* Max number of buffered packets. */ +#define EP_CFG_BUFFERING_MASK GENMASK(31, 27) +#define EP_CFG_BUFFERING(p) (((p) << 27) & EP_CFG_BUFFERING_MASK) + +/* EP_CMD - bitmasks */ +/* Endpoint reset. */ +#define EP_CMD_EPRST BIT(0) +/* Endpoint STALL set. */ +#define EP_CMD_SSTALL BIT(1) +/* Endpoint STALL clear. */ +#define EP_CMD_CSTALL BIT(2) +/* Send ERDY TP. */ +#define EP_CMD_ERDY BIT(3) +/* Request complete. */ +#define EP_CMD_REQ_CMPL BIT(5) +/* Transfer descriptor ready. */ +#define EP_CMD_DRDY BIT(6) +/* Data flush. */ +#define EP_CMD_DFLUSH BIT(7) +/* + * Transfer Descriptor Length write (used only for Bulk Stream capable + * endpoints in SS mode). + */ +#define EP_CMD_STDL BIT(8) +/* Transfer Descriptor Length (used only in SS mode for bulk endpoints). */ +#define EP_CMD_TDL_MASK GENMASK(15, 9) +#define EP_CMD_TDL(p) (((p) << 9) & EP_CMD_TDL_MASK) +/* ERDY Stream ID value (used in SS mode). */ +#define EP_CMD_ERDY_SID_MASK GENMASK(31, 16) +#define EP_CMD_ERDY_SID(p) (((p) << 16) & EP_CMD_SID_MASK) + +/* EP_STS - bitmasks */ +/* Setup transfer complete. */ +#define EP_STS_SETUP BIT(0) +/* Endpoint STALL status. */ +#define EP_STS_STALL(p) ((p) & BIT(1)) +/* Interrupt On Complete. */ +#define EP_STS_IOC BIT(2) +/* Interrupt on Short Packet. */ +#define EP_STS_ISP BIT(3) +/* Transfer descriptor missing. */ +#define EP_STS_DESCMIS BIT(4) +/* Stream Rejected (used only in SS mode) */ +#define EP_STS_STREAMR BIT(5) +/* EXIT from MOVE DATA State (used only for stream transfers in SS mode). */ +#define EP_STS_MD_EXIT BIT(6) +/* TRB error. */ +#define EP_STS_TRBERR BIT(7) +/* Not ready (used only in SS mode). */ +#define EP_STS_NRDY BIT(8) +/* DMA busy. */ +#define EP_STS_DBUSY(p) ((p) & BIT(9)) +/* Endpoint Buffer Empty */ +#define EP_STS_BUFFEMPTY(p) ((p) & BIT(10)) +/* Current Cycle Status */ +#define EP_STS_CCS(p) ((p) & BIT(11)) +/* Prime (used only in SS mode. */ +#define EP_STS_PRIME BIT(12) +/* Stream error (used only in SS mode). */ +#define EP_STS_SIDERR BIT(13) +/* OUT size mismatch. */ +#define EP_STS_OUTSMM BIT(14) +/* ISO transmission error. */ +#define EP_STS_ISOERR BIT(15) +/* Host Packet Pending (only for SS mode). */ +#define EP_STS_HOSTPP(p) ((p) & BIT(16)) +/* Stream Protocol State Machine State (only for Bulk stream endpoints). */ +#define EP_STS_SPSMST_MASK GENMASK(18, 17) +#define EP_STS_SPSMST_DISABLED(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_IDLE(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_START_STREAM(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +#define EP_STS_SPSMST_MOVE_DATA(p) (((p) & EP_STS_SPSMST_MASK) >> 17) +/* Interrupt On Transfer complete. */ +#define EP_STS_IOT BIT(19) +/* OUT queue endpoint number. */ +#define EP_STS_OUTQ_NO_MASK GENMASK(27, 24) +#define EP_STS_OUTQ_NO(p) (((p) & EP_STS_OUTQ_NO_MASK) >> 24) +/* OUT queue valid flag. */ +#define EP_STS_OUTQ_VAL_MASK BIT(28) +#define EP_STS_OUTQ_VAL(p) ((p) & EP_STS_OUTQ_VAL_MASK) +/* SETUP WAIT. */ +#define EP_STS_STPWAIT BIT(31) + +/* EP_STS_SID - bitmasks */ +/* Stream ID (used only in SS mode). */ +#define EP_STS_SID_MASK GENMASK(15, 0) +#define EP_STS_SID(p) ((p) & EP_STS_SID_MASK) + +/* EP_STS_EN - bitmasks */ +/* SETUP interrupt enable. */ +#define EP_STS_EN_SETUPEN BIT(0) +/* OUT transfer missing descriptor enable. */ +#define EP_STS_EN_DESCMISEN BIT(4) +/* Stream Rejected enable. */ +#define EP_STS_EN_STREAMREN BIT(5) +/* Move Data Exit enable.*/ +#define EP_STS_EN_MD_EXITEN BIT(6) +/* TRB enable. */ +#define EP_STS_EN_TRBERREN BIT(7) +/* NRDY enable. */ +#define EP_STS_EN_NRDYEN BIT(8) +/* Prime enable. */ +#define EP_STS_EN_PRIMEEEN BIT(12) +/* Stream error enable. */ +#define EP_STS_EN_SIDERREN BIT(13) +/* OUT size mismatch enable. */ +#define EP_STS_EN_OUTSMMEN BIT(14) +/* ISO transmission error enable. */ +#define EP_STS_EN_ISOERREN BIT(15) +/* Interrupt on Transmission complete enable. */ +#define EP_STS_EN_IOTEN BIT(19) +/* Setup Wait interrupt enable. */ +#define EP_STS_EN_STPWAITEN BIT(31) + +/* DRBL- bitmasks */ +#define DB_VALUE_BY_INDEX(index) (1 << (index)) +#define DB_VALUE_EP0_OUT BIT(0) +#define DB_VALUE_EP0_IN BIT(16) + +/* EP_IEN - bitmasks */ +#define EP_IEN(index) (1 << (index)) +#define EP_IEN_EP_OUT0 BIT(0) +#define EP_IEN_EP_IN0 BIT(16) + +/* EP_ISTS - bitmasks */ +#define EP_ISTS(index) (1 << (index)) +#define EP_ISTS_EP_OUT0 BIT(0) +#define EP_ISTS_EP_IN0 BIT(16) + +/* EP_PWR- bitmasks */ +/*Power Shut Off capability enable*/ +#define PUSB_PWR_PSO_EN BIT(0) +/*Power Shut Off capability disable*/ +#define PUSB_PWR_PSO_DS BIT(1) +/* + * Enables turning-off Reference Clock. + * This bit is optional and implemented only when support for OTG is + * implemented (indicated by OTG_READY bit set to '1'). + */ +#define PUSB_PWR_STB_CLK_SWITCH_EN BIT(8) +/* + * Status bit indicating that operation required by STB_CLK_SWITCH_EN write + * is completed + */ +#define PUSB_PWR_STB_CLK_SWITCH_DONE BIT(9) +/* This bit informs if Fast Registers Access is enabled. */ +#define PUSB_PWR_FST_REG_ACCESS_STAT BIT(30) +/* Fast Registers Access Enable. */ +#define PUSB_PWR_FST_REG_ACCESS BIT(31) + +/* USB_CAP1- bitmasks */ +/* + * SFR Interface type + * These field reflects type of SFR interface implemented: + * 0x0 - OCP + * 0x1 - AHB, + * 0x2 - PLB + * 0x3 - AXI + * 0x4-0xF - reserved + */ +#define USB_CAP1_SFR_TYPE_MASK GENMASK(3, 0) +#define DEV_SFR_TYPE_OCP(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x0) +#define DEV_SFR_TYPE_AHB(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x1) +#define DEV_SFR_TYPE_PLB(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x2) +#define DEV_SFR_TYPE_AXI(p) (((p) & USB_CAP1_SFR_TYPE_MASK) == 0x3) +/* + * SFR Interface width + * These field reflects width of SFR interface implemented: + * 0x0 - 8 bit interface, + * 0x1 - 16 bit interface, + * 0x2 - 32 bit interface + * 0x3 - 64 bit interface + * 0x4-0xF - reserved + */ +#define USB_CAP1_SFR_WIDTH_MASK GENMASK(7, 4) +#define DEV_SFR_WIDTH_8(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x0 << 4)) +#define DEV_SFR_WIDTH_16(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x1 << 4)) +#define DEV_SFR_WIDTH_32(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x2 << 4)) +#define DEV_SFR_WIDTH_64(p) (((p) & USB_CAP1_SFR_WIDTH_MASK) == (0x3 << 4)) +/* + * DMA Interface type + * These field reflects type of DMA interface implemented: + * 0x0 - OCP + * 0x1 - AHB, + * 0x2 - PLB + * 0x3 - AXI + * 0x4-0xF - reserved + */ +#define USB_CAP1_DMA_TYPE_MASK GENMASK(11, 8) +#define DEV_DMA_TYPE_OCP(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x0 << 8)) +#define DEV_DMA_TYPE_AHB(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x1 << 8)) +#define DEV_DMA_TYPE_PLB(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x2 << 8)) +#define DEV_DMA_TYPE_AXI(p) (((p) & USB_CAP1_DMA_TYPE_MASK) == (0x3 << 8)) +/* + * DMA Interface width + * These field reflects width of DMA interface implemented: + * 0x0 - reserved, + * 0x1 - reserved, + * 0x2 - 32 bit interface + * 0x3 - 64 bit interface + * 0x4-0xF - reserved + */ +#define USB_CAP1_DMA_WIDTH_MASK GENMASK(15, 12) +#define DEV_DMA_WIDTH_32(p) (((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x2 << 12)) +#define DEV_DMA_WIDTH_64(p) (((p) & USB_CAP1_DMA_WIDTH_MASK) == (0x3 << 12)) +/* + * USB3 PHY Interface type + * These field reflects type of USB3 PHY interface implemented: + * 0x0 - USB PIPE, + * 0x1 - RMMI, + * 0x2-0xF - reserved + */ +#define USB_CAP1_U3PHY_TYPE_MASK GENMASK(19, 16) +#define DEV_U3PHY_PIPE(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x0 << 16)) +#define DEV_U3PHY_RMMI(p) (((p) & USB_CAP1_U3PHY_TYPE_MASK) == (0x1 << 16)) +/* + * USB3 PHY Interface width + * These field reflects width of USB3 PHY interface implemented: + * 0x0 - 8 bit PIPE interface, + * 0x1 - 16 bit PIPE interface, + * 0x2 - 32 bit PIPE interface, + * 0x3 - 64 bit PIPE interface + * 0x4-0xF - reserved + * Note: When SSIC interface is implemented this field shows the width of + * internal PIPE interface. The RMMI interface is always 20bit wide. + */ +#define USB_CAP1_U3PHY_WIDTH_MASK GENMASK(23, 20) +#define DEV_U3PHY_WIDTH_8(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x0 << 20)) +#define DEV_U3PHY_WIDTH_16(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x1 << 16)) +#define DEV_U3PHY_WIDTH_32(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x2 << 20)) +#define DEV_U3PHY_WIDTH_64(p) \ + (((p) & USB_CAP1_U3PHY_WIDTH_MASK) == (0x3 << 16)) + +/* + * USB2 PHY Interface enable + * These field informs if USB2 PHY interface is implemented: + * 0x0 - interface NOT implemented, + * 0x1 - interface implemented + */ +#define USB_CAP1_U2PHY_EN(p) ((p) & BIT(24)) +/* + * USB2 PHY Interface type + * These field reflects type of USB2 PHY interface implemented: + * 0x0 - UTMI, + * 0x1 - ULPI + */ +#define DEV_U2PHY_ULPI(p) ((p) & BIT(25)) +/* + * USB2 PHY Interface width + * These field reflects width of USB2 PHY interface implemented: + * 0x0 - 8 bit interface, + * 0x1 - 16 bit interface, + * Note: The ULPI interface is always 8bit wide. + */ +#define DEV_U2PHY_WIDTH_16(p) ((p) & BIT(26)) +/* + * OTG Ready + * 0x0 - pure device mode + * 0x1 - some features and ports for CDNS USB OTG controller are implemented. + */ +#define USB_CAP1_OTG_READY(p) ((p) & BIT(27)) + +/* USB_CAP2- bitmasks */ +/* + * The actual size of the connected On-chip RAM memory in kB: + * - 0 means 256 kB (max supported mem size) + * - value other than 0 reflects the mem size in kB + */ +#define USB_CAP2_ACTUAL_MEM_SIZE(p) ((p) & GENMASK(7, 0)) +/* + * Max supported mem size + * These field reflects width of on-chip RAM address bus width, + * which determines max supported mem size: + * 0x0-0x7 - reserved, + * 0x8 - support for 4kB mem, + * 0x9 - support for 8kB mem, + * 0xA - support for 16kB mem, + * 0xB - support for 32kB mem, + * 0xC - support for 64kB mem, + * 0xD - support for 128kB mem, + * 0xE - support for 256kB mem, + * 0xF - reserved + */ +#define USB_CAP2_MAX_MEM_SIZE(p) ((p) & GENMASK(11, 8)) + +/* USB_CAP3- bitmasks */ +#define EP_IS_IMPLEMENTED(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP4- bitmasks */ +#define EP_SUPPORT_ISO(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP5- bitmasks */ +#define EP_SUPPORT_STREAM(reg, index) ((reg) & (1 << (index))) + +/* USB_CAP6- bitmasks */ +/* The USBSS-DEV Controller Internal build number. */ +#define GET_DEV_VERSION__INTERNAL_NUMBER(p) ((p) & GENMASK(7, 0)) +/* The USBSS-DEV Controller version number. */ +#define GET_DEV_VERSION(p) ((p) & GENMASK(31, 8)) + +/* DBG_LINK1- bitmasks */ +/* + * LFPS_MIN_DET_U1_EXIT value This parameter configures the minimum + * time required for decoding the received LFPS as an LFPS.U1_Exit. + */ +#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT(p) ((p) & GENMASK(7, 0)) +/* + * LFPS_MIN_GEN_U1_EXIT value This parameter configures the minimum time for + * phytxelecidle deassertion when LFPS.U1_Exit + */ +#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT(p) (((p) << 8) & GENMASK(15, 8)) +/* + * RXDET_BREAK_DIS value This parameter configures terminating the Far-end + * Receiver termination detection sequence: + * 0: it is possible that USBSS_DEV will terminate Farend receiver + * termination detection sequence + * 1: USBSS_DEV will not terminate Far-end receiver termination + * detection sequence + */ +#define DBG_LINK1_RXDET_BREAK_DIS BIT(16) +/* LFPS_GEN_PING value This parameter configures the LFPS.Ping generation */ +#define DBG_LINK1_LFPS_GEN_PING(p) (((p) << 17) & GENMASK(21, 17)) +/* + * Set the LFPS_MIN_DET_U1_EXIT value Writing '1' to this bit writes the + * LFPS_MIN_DET_U1_EXIT field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_LFPS_MIN_DET_U1_EXIT_SET BIT(24) +/* + * Set the LFPS_MIN_GEN_U1_EXIT value. Writing '1' to this bit writes the + * LFPS_MIN_GEN_U1_EXIT field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_LFPS_MIN_GEN_U1_EXIT_SET BIT(25) +/* + * Set the RXDET_BREAK_DIS value Writing '1' to this bit writes + * the RXDET_BREAK_DIS field value to the device. This bit is automatically + * cleared. Writing '0' has no effect + */ +#define DBG_LINK1_RXDET_BREAK_DIS_SET BIT(26) +/* + * Set the LFPS_GEN_PING_SET value Writing '1' to this bit writes + * the LFPS_GEN_PING field value to the device. This bit is automatically + * cleared. Writing '0' has no effect." + */ +#define DBG_LINK1_LFPS_GEN_PING_SET BIT(27) + +#define gadget_to_cdns3_device(g) (container_of(g, struct cdns3_device, gadget)) + +#define ep_to_cdns3_ep(ep) (container_of(ep, struct cdns3_endpoint, endpoint)) + +/*-------------------------------------------------------------------------*/ +/* + * USBSS-DEV DMA interface . + */ +#define TRBS_PER_SEGMENT 16 + +/** + * struct cdns3_trb - represent Transfer Descriptor block. + * @buffer: pointer to buffer data + * @length: length of data + * @control: control flags. + * + * This structure describes transfer block serviced by DMA module. + */ +struct cdns3_trb { + __le32 buffer; + __le32 length; + __le32 control; +}; + +#define TRB_SIZE (sizeof(struct cdns3_trb)) +#define TRB_RING_SIZE (TRB_SIZE * TRBS_PER_SEGMENT) + +/* TRB bit mask */ +#define TRB_TYPE_BITMASK GENMASK(15, 10) +#define TRB_TYPE(p) ((p) << 10) +#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) + +/* TRB type IDs */ +/* bulk, interrupt, isoc , and control data stage */ +#define TRB_NORMAL 1 +/* TRB for linking ring segments */ +#define TRB_LINK 6 + +/* Cycle bit - indicates TRB ownership by driver or hw*/ +#define TRB_CYCLE BIT(0) +/* + * When set to '1', the device will toggle its interpretation of the Cycle bit + */ +#define TRB_TOGGLE BIT(1) + +/* Interrupt on short packet*/ +#define TRB_ISP BIT(2) +/*Setting this bit enables FIFO DMA operation mode*/ +#define TRB_FIFO_MODE BIT(3) +/* Set PCIe no snoop attribute */ +#define TRB_CHAIN BIT(4) +/* Interrupt on completion */ +#define TRB_IOC BIT(5) + +/* stream ID bitmasks. */ +#define TRB_STREAM_ID(p) ((p) & GENMASK(31, 16)) + +/* transfer_len bitmasks. */ +#define TRB_LEN(p) ((p) & GENMASK(16, 0)) + +/* transfer_len bitmasks - bits 31:24 */ +#define TRB_BURST_LEN(p) ((p) & GENMASK(31, 24)) + +/* Data buffer pointer bitmasks*/ +#define TRB_BUFFER(p) ((p) & GENMASK(31, 0)) + +/*-------------------------------------------------------------------------*/ +/* Driver numeric constants */ + +/* Such declaration should be added to ch9.h */ +#define USB_DEVICE_MAX_ADDRESS 127 + +/* Endpoint init values */ +#define CDNS3_EP_MAX_PACKET_LIMIT 1024 +#define CDNS3_EP_MAX_STREAMS 15 + +#define CDNS3_EP0_MAX_PACKET_LIMIT 512 + +/* All endpoints except EP0 */ +#define CDNS3_ENDPOINTS_MAX_COUNT 30 + +#define CDNS3_EP_ZLP_BUF_SIZE 1024 + +/*-------------------------------------------------------------------------*/ +#define CDNS3_EP_BUF_SIZE 2 /* KB */ +#define CDNS3_ALIGNED_BUF_SIZE 16384 /* Bytes */ +#define CDNS3_DESCMIS_BUF_SIZE 65536 /* Bytes */ +/*-------------------------------------------------------------------------*/ +/* Used structs */ + +struct cdns3_device; + +/** + * struct cdns3_endpoint - extended device side representation of USB endpoint. + * @endpoint: usb endpoint + * @request_list: list of request for this endpoint + * @trb_pool: transfer ring - array of transaction buffers + * @trb_pool_dma: dma address of transfer ring + * @cdns3_dev: device associated with this endpoint + * @name: a human readable name e.g. ep1out + * @flags: specify the current state of endpoint + * @descmis_req: internal transfer object used for getting data from on-chip + * buffer. It can happen only if function driver doesn't send usb_request + * object on time. + * @descmis_pending: flag specify that internal buffer was used for DMA to + * take data from shared on-chip buffers to avoid blocking transfer to other + * endpoints. It indicate that is still in progress. + * @descmis_finished: flag specify that transfer has armed on descriptor + * missing event has been completed. If function driver requests + * the transfer then controller driver can just return this data. + * @aligned_buff: aligned to 8 bytes data buffer. Buffer address used in + * TRB shall be aligned to 8. + * @aligned_dma_addr: dma address of aligned_buff + * @dir: endpoint direction + * @num: endpoint number (1 - 15) + * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK + * @free_trbs: number of free TRBs in transfer ring + * @pcs: producer cycle state + * @ccs: consumer cycle state + * @enqueue: enqueue index in transfer ring + * @dequeue: dequeue index in transfer ring + */ +struct cdns3_endpoint { + struct usb_ep endpoint; + struct list_head request_list; + + struct cdns3_trb *trb_pool; + dma_addr_t trb_pool_dma; + + struct cdns3_device *cdns3_dev; + char name[20]; + +#define EP_ENABLED BIT(0) +#define EP_STALL BIT(1) +#define EP_WEDGE BIT(2) +#define EP_TRANSFER_STARTED BIT(3) +#define EP_UPDATE_EP_TRBADDR BIT(4) +#define EP_PENDING_REQUEST BIT(5) +#define EP_RING_FULL BIT(6) +#define EP_CLAIMED BIT(5) + u32 flags; + + struct cdns3_request *descmis_req; + u32 descmis_pending:1; + u32 descmis_finished:1; + + void *aligned_buff; + dma_addr_t aligned_dma_addr; + u8 dir; + u8 num; + u8 type; + + int free_trbs; + u8 pcs; + u8 ccs; + int enqueue; + int dequeue; +}; + +/** + * struct cdns3_request - extended device side representation of usb_request + * object . + * @request: generic usb_request object describing single I/O request. + * @priv_ep: extended representation of usb_ep object + * @trb: the first TRB association with this request + * @start_trb: number of the first TRB in transfer ring + * @end_trb: number of the last TRB in transfer ring + * @flags: flag specifying special usage of request + */ +struct cdns3_request { + struct usb_request request; + struct cdns3_endpoint *priv_ep; + struct cdns3_trb *trb; + int start_trb; + int end_trb; +#define REQUEST_PENDING BIT(0) +#define REQUEST_INTERNAL BIT(1) +#define REQUEST_ZLP BIT(2) + u32 flags; +}; + +#define to_cdns3_request(r) (container_of(r, struct cdns3_request, request)) + +/** + * struct cdns3_device - represent USB device. + * @dev: pointer to device structure associated whit this controller + * @sysdev: pointer to the DMA capable device + * @gadget: device side representation of the peripheral controller + * @gadget_driver: pointer to the gadget driver + * @lock: for synchronizing + * @regs: base address for device side registers + * @setup_buf: used while processing usb control requests + * @setup_dma: dma address for setup_buf + * @ep0_trb: TRB used for control transfer + * @ep0_trb_dma: dma address of ep0_trb + * @zlp_buf - zlp buffer + * @ep0_request: dummy request used while handling USB control request + * @ep0_data_dir: direction for control transfer + * @eps: array of pointers to all endpoints with exclusion ep0 + * @ep_nums: number of endpoints in eps + * @isoch_delay: value from Set Isoch Delay request. Only valid on SS/SSP. + * @u1_allowed: allow device transition to u1 state + * @u2_allowed: allow device transition to u2 state + * @is_selfpowered: device is self powered + * @setup_pending: setup packet is processing by gadget driver + * @hw_configured_flag: hardware endpoint configuration was set. + * @wake_up_flag: allow device to remote up the host + * @status_completion_no_call: indicate that driver is waiting for status s + * stage completion. It's used in deferred SET_CONFIGURATION request. + * @onchip_mem_allocated_size: actual size of on-chip memory assigned + * to endpoints + * @pending_status_wq: workqueue handling status stage for deferred requests. + * @pending_status_request: request for which status stage was deferred + */ +struct cdns3_device { + struct device *dev; + struct device *sysdev; + + struct usb_gadget gadget; + struct usb_gadget_driver *gadget_driver; + + /* generic spin-lock for drivers */ + spinlock_t lock; + + struct cdns3_usb_regs __iomem *regs; + + struct usb_ctrlrequest *setup_buf; + dma_addr_t setup_dma; + struct cdns3_trb *ep0_trb; + dma_addr_t ep0_trb_dma; + void *zlp_buf; + struct usb_request *ep0_request; + int ep0_data_dir; + + struct cdns3_endpoint *eps[CDNS3_ENDPOINTS_MAX_COUNT]; + int ep_nums; + + u32 selected_ep; + u16 isoch_delay; + + unsigned u1_allowed:1; + unsigned u2_allowed:1; + unsigned is_selfpowered:1; + unsigned setup_pending:1; + int hw_configured_flag:1; + int wake_up_flag:1; + unsigned status_completion_no_call:1; + + struct work_struct pending_status_wq; + struct usb_request *pending_status_request; + + /*in KB */ + int onchip_mem_allocated_size; +}; + +int cdns3_handshake(void __iomem *ptr, u32 mask, u32 done, int usec); +void cdns3_set_register_bit(void __iomem *ptr, u32 mask); +dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, + struct cdns3_trb *trb); +enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev); +void cdns3_pending_setup_status_handler(struct work_struct *work); +void cdns3_gadget_unconfig(struct cdns3_device *priv_dev); +void cdns3_set_hw_configuration(struct cdns3_device *priv_dev); +void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep); +void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable); +struct usb_request *cdns3_next_request(struct list_head *list); +int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, + struct usb_request *request); +u8 cdns3_ep_addr_to_index(u8 ep_addr); +int cdns3_gadget_ep_set_wedge(struct usb_ep *ep); +int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value); +struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags); +void cdns3_gadget_ep_free_request(struct usb_ep *ep, + struct usb_request *request); +int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request); +void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, + struct cdns3_request *priv_req, + int status); + +int cdns3_init_ep0(struct cdns3_device *priv_dev); +void cdns3_ep0_config(struct cdns3_device *priv_dev); +void cdns3_ep_config(struct cdns3_endpoint *priv_ep); +void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir); + +#endif /* __LINUX_CDNS3_GADGET */ diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h new file mode 100644 index 000000000000..b498a170b7e8 --- /dev/null +++ b/drivers/usb/cdns3/host-export.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence USBSS DRD Driver - Host Export APIs + * + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + */ +#ifndef __LINUX_CDNS3_HOST_EXPORT +#define __LINUX_CDNS3_HOST_EXPORT + +#ifdef CONFIG_USB_CDNS3_HOST + +int cdns3_host_init(struct cdns3 *cdns); +void cdns3_host_exit(struct cdns3 *cdns); + +#else + +static inline int cdns3_host_init(struct cdns3 *cdns) +{ + return -ENXIO; +} + +static inline void cdns3_host_exit(struct cdns3 *cdns) { } + +#endif /* CONFIG_USB_CDNS3_HOST */ + +#endif /* __LINUX_CDNS3_HOST_EXPORT */ diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c new file mode 100644 index 000000000000..e16175e0328a --- /dev/null +++ b/drivers/usb/cdns3/host.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence USBSS DRD Driver - host side + * + * Copyright (C) 2018 Cadence Design Systems. + * Copyright (C) 2017-2018 NXP + * + * Authors: Peter Chen + * Pawel Laszczak + */ + +#include +#include "core.h" + +static int __cdns3_host_init(struct cdns3 *cdns) +{ + struct platform_device *xhci; + int ret; + + xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); + if (!xhci) { + dev_err(cdns->dev, "couldn't allocate xHCI device\n"); + return -ENOMEM; + } + + xhci->dev.parent = cdns->dev; + cdns->host_dev = xhci; + + ret = platform_device_add_resources(xhci, cdns->xhci_res, + CDNS3_XHCI_RESOURCES_NUM); + if (ret) { + dev_err(cdns->dev, "couldn't add resources to xHCI device\n"); + goto err1; + } + + ret = platform_device_add(xhci); + if (ret) { + dev_err(cdns->dev, "failed to register xHCI device\n"); + goto err1; + } + + return 0; +err1: + platform_device_put(xhci); + return ret; +} + +static void cdns3_host_exit(struct cdns3 *cdns) +{ + platform_device_unregister(cdns->host_dev); + cdns->host_dev = NULL; +} + +int cdns3_host_init(struct cdns3 *cdns) +{ + struct cdns3_role_driver *rdrv; + + rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = __cdns3_host_init; + rdrv->stop = cdns3_host_exit; + rdrv->state = CDNS3_ROLE_STATE_INACTIVE; +#if CONFIG_PM + rdrv->suspend = NULL; + rdrv->resume = NULL; +#endif /* CONFIG_PM */ + rdrv->name = "host"; + + cdns->roles[CDNS3_ROLE_HOST] = rdrv; + + return 0; +} diff --git a/drivers/usb/cdns3/trace.c b/drivers/usb/cdns3/trace.c new file mode 100644 index 000000000000..587ae08e019d --- /dev/null +++ b/drivers/usb/cdns3/trace.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USBSS device controller driver Trace Support + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/cdns3/trace.h b/drivers/usb/cdns3/trace.h new file mode 100644 index 000000000000..a5c8b2a756b4 --- /dev/null +++ b/drivers/usb/cdns3/trace.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USBSS device controller driver. + * Trace support header file. + * + * Copyright (C) 2018 Cadence. + * + * Author: Pawel Laszczak + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cdns3 + +#if !defined(__LINUX_CDNS3_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __LINUX_CDNS3_TRACE + +#include +#include +#include +#include "core.h" +#include "gadget.h" +#include "debug.h" + +#define CDNS3_MSG_MAX 500 + +DECLARE_EVENT_CLASS(cdns3_log_doorbell, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name), + TP_STRUCT__entry( + __field(const char *, ep_name) + ), + TP_fast_assign( + __entry->ep_name = ep_name; + ), + TP_printk("//Ding Dong %s", __entry->ep_name) +); + +DEFINE_EVENT(cdns3_log_doorbell, cdns3_doorbell_ep0, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name) +); + +DEFINE_EVENT(cdns3_log_doorbell, cdns3_doorbell_epx, + TP_PROTO(const char *ep_name), + TP_ARGS(ep_name) +); + +DECLARE_EVENT_CLASS(cdns3_log_usb_irq, + TP_PROTO(struct cdns3_device *priv_dev, u32 usb_ists), + TP_ARGS(priv_dev, usb_ists), + TP_STRUCT__entry( + __field(struct cdns3_device *, priv_dev) + __field(u32, usb_ists) + ), + TP_fast_assign( + __entry->priv_dev = priv_dev; + __entry->usb_ists = usb_ists; + ), + TP_printk("%s", cdns3_decode_usb_irq(__entry->priv_dev, + __entry->usb_ists)) +); + +DEFINE_EVENT(cdns3_log_usb_irq, cdns3_usb_irq, + TP_PROTO(struct cdns3_device *priv_dev, u32 usb_ists), + TP_ARGS(priv_dev, usb_ists) +); + +DECLARE_EVENT_CLASS(cdns3_log_epx_irq, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __field(struct cdns3_endpoint *, priv_ep) + ), + TP_fast_assign( + __entry->priv_ep = priv_ep; + ), + TP_printk("%s", cdns3_decode_epx_irq(__entry->priv_ep)) +); + +DEFINE_EVENT(cdns3_log_epx_irq, cdns3_epx_irq, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DECLARE_EVENT_CLASS(cdns3_log_ep0_irq, + TP_PROTO(struct cdns3_device *priv_dev), + TP_ARGS(priv_dev), + TP_STRUCT__entry( + __field(struct cdns3_device *, priv_dev) + ), + TP_fast_assign( + __entry->priv_dev = priv_dev; + ), + TP_printk("%s", cdns3_decode_ep0_irq(__entry->priv_dev)) +); + +DEFINE_EVENT(cdns3_log_ep0_irq, cdns3_ep0_irq, + TP_PROTO(struct cdns3_device *priv_dev), + TP_ARGS(priv_dev) +); + +DECLARE_EVENT_CLASS(cdns3_log_ctrl, + TP_PROTO(struct usb_ctrlrequest *ctrl), + TP_ARGS(ctrl), + TP_STRUCT__entry( + __field(u8, bRequestType) + __field(u8, bRequest) + __field(u16, wValue) + __field(u16, wIndex) + __field(u16, wLength) + __dynamic_array(char, str, CDNS3_MSG_MAX) + ), + TP_fast_assign( + __entry->bRequestType = ctrl->bRequestType; + __entry->bRequest = ctrl->bRequest; + __entry->wValue = le16_to_cpu(ctrl->wValue); + __entry->wIndex = le16_to_cpu(ctrl->wIndex); + __entry->wLength = le16_to_cpu(ctrl->wLength); + ), + TP_printk("%s", cdns3_decode_ctrl(__get_str(str), __entry->bRequestType, + __entry->bRequest, __entry->wValue, + __entry->wIndex, __entry->wLength) + ) +); + +DEFINE_EVENT(cdns3_log_ctrl, cdns3_ctrl_req, + TP_PROTO(struct usb_ctrlrequest *ctrl), + TP_ARGS(ctrl) +); + +DECLARE_EVENT_CLASS(cdns3_log_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req), + TP_STRUCT__entry( + __string(name, req->priv_ep->name) + __field(struct cdns3_request *, req) + __field(unsigned int, actual) + __field(unsigned int, length) + __field(int, status) + __field(int, zero) + __field(int, short_not_ok) + __field(int, no_interrupt) + __field(int, start_trb) + __field(int, end_trb) + __field(struct cdns3_trb *, start_trb_addr) + __field(int, flags) + ), + TP_fast_assign( + __assign_str(name, req->priv_ep->name); + __entry->req = req; + __entry->actual = req->request.actual; + __entry->length = req->request.length; + __entry->status = req->request.status; + __entry->zero = req->request.zero; + __entry->short_not_ok = req->request.short_not_ok; + __entry->no_interrupt = req->request.no_interrupt; + __entry->start_trb = req->start_trb; + __entry->end_trb = req->end_trb; + __entry->start_trb_addr = req->trb; + __entry->flags = req->flags; + ), + TP_printk("%s: req: %p, length: %u/%u %s%s%s, status: %d," + " trb: [start:%d, end:%d: virt addr %pa], flags:%x ", + __get_str(name), __entry->req, __entry->actual, __entry->length, + __entry->zero ? "zero | " : "", + __entry->short_not_ok ? "short | " : "", + __entry->no_interrupt ? "no int" : "", + __entry->status, + __entry->start_trb, + __entry->end_trb, + __entry->start_trb_addr, + __entry->flags + ) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_alloc_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_free_request, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_ep_queue, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_ep_dequeue, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(cdns3_log_request, cdns3_gadget_giveback, + TP_PROTO(struct cdns3_request *req), + TP_ARGS(req) +); + +DECLARE_EVENT_CLASS(cdns3_log_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb), + TP_STRUCT__entry( + __string(name, priv_ep->name) + __field(struct cdns3_trb *, trb) + __field(u32, buffer) + __field(u32, length) + __field(u32, control) + __field(u32, type) + ), + TP_fast_assign( + __assign_str(name, priv_ep->name); + __entry->trb = trb; + __entry->buffer = trb->buffer; + __entry->length = trb->length; + __entry->control = trb->control; + __entry->type = usb_endpoint_type(priv_ep->endpoint.desc); + ), + TP_printk("%s: trb 0x%pa, dma buf: 0x%08x, size: %ld, ctrl: 0x%08x (%s%s%s%s%s%s%s)", + __get_str(name), __entry->trb, __entry->buffer, + TRB_LEN(__entry->length), __entry->control, + __entry->control & TRB_CYCLE ? "C=1, " : "C=0, ", + __entry->control & TRB_TOGGLE ? "T=1, " : "T=0, ", + __entry->control & TRB_ISP ? "ISP, " : "", + __entry->control & TRB_FIFO_MODE ? "FIFO, " : "", + __entry->control & TRB_CHAIN ? "CHAIN, " : "", + __entry->control & TRB_IOC ? "IOC, " : "", + TRB_FIELD_TO_TYPE(__entry->control) == TRB_NORMAL ? "Normal" : "LINK" + ) +); + +DEFINE_EVENT(cdns3_log_trb, cdns3_prepare_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb) +); + +DEFINE_EVENT(cdns3_log_trb, cdns3_complete_trb, + TP_PROTO(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb), + TP_ARGS(priv_ep, trb) +); + +DECLARE_EVENT_CLASS(cdns3_log_ring, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __field(struct cdns3_endpoint *, priv_ep) + __field(int, free_trbs) + __field(u8, pcs) + __field(u8, ccs) + __field(int, enqueue) + __field(int, dequeue) + __dynamic_array(u32, ring, TRB_RING_SIZE) + __dynamic_array(char, buffer, + (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX) + ), + TP_fast_assign( + __entry->priv_ep = priv_ep; + __entry->free_trbs = priv_ep->free_trbs; + __entry->pcs = priv_ep->pcs; + __entry->ccs = priv_ep->ccs; + __entry->enqueue = priv_ep->enqueue; + __entry->dequeue = priv_ep->dequeue; + memcpy(__get_dynamic_array(ring), priv_ep->trb_pool, + TRB_RING_SIZE); + ), + + TP_printk("%s", + cdns3_dbg_ring(__entry->priv_ep, __entry->free_trbs, + __entry->pcs, __entry->ccs, + __entry->enqueue, __entry->dequeue, + (struct cdns3_trb *)__get_str(ring), + __get_str(buffer))) +); + +DEFINE_EVENT(cdns3_log_ring, cdns3_ring, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DECLARE_EVENT_CLASS(cdns3_log_ep, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep), + TP_STRUCT__entry( + __string(name, priv_ep->name) + __field(unsigned int, maxpacket) + __field(unsigned int, maxpacket_limit) + __field(unsigned int, max_streams) + __field(unsigned int, maxburst) + __field(unsigned int, flags) + __field(unsigned int, dir) + __field(u8, enqueue) + __field(u8, dequeue) + ), + TP_fast_assign( + __assign_str(name, priv_ep->name); + __entry->maxpacket = priv_ep->endpoint.maxpacket; + __entry->maxpacket_limit = priv_ep->endpoint.maxpacket_limit; + __entry->max_streams = priv_ep->endpoint.max_streams; + __entry->maxburst = priv_ep->endpoint.maxburst; + __entry->flags = priv_ep->flags; + __entry->dir = priv_ep->dir; + __entry->enqueue = priv_ep->enqueue; + __entry->dequeue = priv_ep->dequeue; + ), + TP_printk("%s: mps: %d/%d. streams: %d, burst: %d, enq idx: %d, " + "deq idx: %d, flags %s%s%s%s%s%s%s%s, dir: %s", + __get_str(name), __entry->maxpacket, + __entry->maxpacket_limit, __entry->max_streams, + __entry->maxburst, __entry->enqueue, + __entry->dequeue, + __entry->flags & EP_ENABLED ? "EN | " : "", + __entry->flags & EP_STALL ? "STALL | " : "", + __entry->flags & EP_WEDGE ? "WEDGE | " : "", + __entry->flags & EP_TRANSFER_STARTED ? "STARTED | " : "", + __entry->flags & EP_UPDATE_EP_TRBADDR ? "UPD TRB | " : "", + __entry->flags & EP_PENDING_REQUEST ? "REQ PEN | " : "", + __entry->flags & EP_RING_FULL ? "RING FULL |" : "", + __entry->flags & EP_CLAIMED ? "CLAIMED " : "", + __entry->dir ? "IN" : "OUT" + ) +); + +DEFINE_EVENT(cdns3_log_ep, cdns3_gadget_ep_enable, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); + +DEFINE_EVENT(cdns3_log_ep, cdns3_gadget_ep_disable, + TP_PROTO(struct cdns3_endpoint *priv_ep), + TP_ARGS(priv_ep) +); +#endif /* __LINUX_CDNS3_TRACE */ + +/* this part must be outside header guard */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include -- 2.17.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [v1,2/2] usb:cdns3 Add Cadence USB3 DRD Driver From: Pawel Laszczak Message-Id: <1544445555-17325-3-git-send-email-pawell@cadence.com> Date: Mon, 10 Dec 2018 12:39:15 +0000 To: devicetree@vger.kernel.org Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, balbi@kernel.org, rogerq@ti.com, linux-kernel@vger.kernel.org, adouglas@cadence.com, jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com, sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com, kurahul@cadence.com, Pawel Laszczak List-ID: VGhpcyBwYXRjaCBpbnRyb2R1Y2UgbmV3IENhZGVuY2UgVVNCU1MgRFJEIGRyaXZlcgp0byBsaW51 eCBrZXJuZWwuCgpUaGUgQ2FkZW5jZSBVU0JTUyBEUkQgRHJpdmVyIGlzIGEgaGlnaGx5CmNvbmZp Z3VyYWJsZSBJUCBDb3JlIHdoaWNoIGNhbiBiZQppbnN0YW50aWF0ZWQgYXMgRHVhbC1Sb2xlIERl dmljZSAoRFJEKSwKUGVyaXBoZXJhbCBPbmx5IGFuZCBIb3N0IE9ubHkgKFhIQ0kpCmNvbmZpZ3Vy YXRpb25zLgoKVGhlIGN1cnJlbnQgZHJpdmVyIGhhcyBiZWVuIHZhbGlkYXRlZCB3aXRoCkZQR0Eg YnVybmVkLiBXZSBoYXZlIHN1cHBvcnQgZm9yIFBDSWUKYnVzLCB3aGljaCBpcyB1c2VkIG9uIEZQ R0EgcHJvdG90eXBpbmcuCgpUaGUgaG9zdCBzaWRlIG9mIFVTQlNTLURSRCBjb250cm9sbGVyIGlz IGNvbXBsaWFuY2UKd2l0aCBYSENJIHNwZWNpZmljYXRpb24sIHNvIGl0IHdvcmtzIHdpdGgKc3Rh bmRhcmQgWEhDSSBsaW51eCBkcml2ZXIuCgpTaWduZWQtb2ZmLWJ5OiBQYXdlbCBMYXN6Y3phayA8 cGF3ZWxsQGNhZGVuY2UuY29tPgotLS0KIGRyaXZlcnMvdXNiL0tjb25maWcgICAgICAgICAgICAg ICAgfCAgICAyICsKIGRyaXZlcnMvdXNiL01ha2VmaWxlICAgICAgICAgICAgICAgfCAgICAyICsK IGRyaXZlcnMvdXNiL2NkbnMzL0tjb25maWcgICAgICAgICAgfCAgIDQ0ICsKIGRyaXZlcnMvdXNi L2NkbnMzL01ha2VmaWxlICAgICAgICAgfCAgIDE2ICsKIGRyaXZlcnMvdXNiL2NkbnMzL2NkbnMz LXBjaS13cmFwLmMgfCAgMTU3ICsrKwogZHJpdmVycy91c2IvY2RuczMvY29yZS5jICAgICAgICAg ICB8ICA0NTEgKysrKysrKwogZHJpdmVycy91c2IvY2RuczMvY29yZS5oICAgICAgICAgICB8ICAx MDggKysKIGRyaXZlcnMvdXNiL2NkbnMzL2RlYnVnLmggICAgICAgICAgfCAgMzQ2ICsrKysrKwog ZHJpdmVycy91c2IvY2RuczMvZGVidWdmcy5jICAgICAgICB8ICAxNjggKysrCiBkcml2ZXJzL3Vz Yi9jZG5zMy9kcmQuYyAgICAgICAgICAgIHwgIDMxNSArKysrKwogZHJpdmVycy91c2IvY2RuczMv ZHJkLmggICAgICAgICAgICB8ICAxMjkgKysKIGRyaXZlcnMvdXNiL2NkbnMzL2VwMC5jICAgICAg ICAgICAgfCAgODY0ICsrKysrKysrKysrKysKIGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1leHBv cnQuaCAgfCAgIDI4ICsKIGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jICAgICAgICAgfCAxODAy ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysKIGRyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5o ICAgICAgICAgfCAxMTc3ICsrKysrKysrKysrKysrKysrKwogZHJpdmVycy91c2IvY2RuczMvaG9z dC1leHBvcnQuaCAgICB8ICAgMjggKwogZHJpdmVycy91c2IvY2RuczMvaG9zdC5jICAgICAgICAg ICB8ICAgNzQgKysKIGRyaXZlcnMvdXNiL2NkbnMzL3RyYWNlLmMgICAgICAgICAgfCAgIDExICsK IGRyaXZlcnMvdXNiL2NkbnMzL3RyYWNlLmggICAgICAgICAgfCAgMzQzICsrKysrKwogMTkgZmls ZXMgY2hhbmdlZCwgNjA2NSBpbnNlcnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVy cy91c2IvY2RuczMvS2NvbmZpZwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMz L01ha2VmaWxlCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvY2RuczMtcGNp LXdyYXAuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2NvcmUuYwogY3Jl YXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2NvcmUuaAogY3JlYXRlIG1vZGUgMTAw NjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2RlYnVnLmgKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJz L3VzYi9jZG5zMy9kZWJ1Z2ZzLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9jZG5z My9kcmQuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2RyZC5oCiBjcmVh dGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvZXAwLmMKIGNyZWF0ZSBtb2RlIDEwMDY0 NCBkcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQtZXhwb3J0LmgKIGNyZWF0ZSBtb2RlIDEwMDY0NCBk cml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNi L2NkbnMzL2dhZGdldC5oCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy91c2IvY2RuczMvaG9z dC1leHBvcnQuaAogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL2hvc3QuYwog Y3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvdXNiL2NkbnMzL3RyYWNlLmMKIGNyZWF0ZSBtb2Rl IDEwMDY0NCBkcml2ZXJzL3VzYi9jZG5zMy90cmFjZS5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy91 c2IvS2NvbmZpZyBiL2RyaXZlcnMvdXNiL0tjb25maWcKaW5kZXggOTg3ZmM1YmE2MzIxLi41Zjkz MzQwMTlkMDQgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvdXNiL0tjb25maWcKKysrIGIvZHJpdmVycy91 c2IvS2NvbmZpZwpAQCAtMTEyLDYgKzExMiw4IEBAIHNvdXJjZSAiZHJpdmVycy91c2IvdXNiaXAv S2NvbmZpZyIKIAogZW5kaWYKIAorc291cmNlICJkcml2ZXJzL3VzYi9jZG5zMy9LY29uZmlnIgor CiBzb3VyY2UgImRyaXZlcnMvdXNiL210dTMvS2NvbmZpZyIKIAogc291cmNlICJkcml2ZXJzL3Vz Yi9tdXNiL0tjb25maWciCmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9NYWtlZmlsZSBiL2RyaXZl cnMvdXNiL01ha2VmaWxlCmluZGV4IDdkMWI4YzgyYjIwOC4uYWIxMjViOTY2Y2FjIDEwMDY0NAot LS0gYS9kcml2ZXJzL3VzYi9NYWtlZmlsZQorKysgYi9kcml2ZXJzL3VzYi9NYWtlZmlsZQpAQCAt MTIsNiArMTIsOCBAQCBvYmotJChDT05GSUdfVVNCX0RXQzMpCQkrPSBkd2MzLwogb2JqLSQoQ09O RklHX1VTQl9EV0MyKQkJKz0gZHdjMi8KIG9iai0kKENPTkZJR19VU0JfSVNQMTc2MCkJKz0gaXNw MTc2MC8KIAorb2JqLSQoQ09ORklHX1VTQl9DRE5TMykJCSs9IGNkbnMzLworCiBvYmotJChDT05G SUdfVVNCX01PTikJCSs9IG1vbi8KIG9iai0kKENPTkZJR19VU0JfTVRVMykJCSs9IG10dTMvCiAK ZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL0tjb25maWcgYi9kcml2ZXJzL3VzYi9jZG5z My9LY29uZmlnCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uNGFkZmQ4 NzgxMWU4Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy91c2IvY2RuczMvS2NvbmZpZwpAQCAt MCwwICsxLDQ0IEBACitjb25maWcgVVNCX0NETlMzCisJdHJpc3RhdGUgIkNhZGVuY2UgVVNCMyBE dWFsLVJvbGUgQ29udHJvbGxlciIKKwlkZXBlbmRzIG9uIFVTQl9TVVBQT1JUICYmIChVU0IgfHwg VVNCX0dBREdFVCkgJiYgSEFTX0RNQQorCWhlbHAKKwkgIFNheSBZIGhlcmUgaWYgeW91ciBzeXN0 ZW0gaGFzIGEgY2FkZW5jZSBVU0IzIGR1YWwtcm9sZSBjb250cm9sbGVyLgorCSAgSXQgc3VwcG9y dHM6IGR1YWwtcm9sZSBzd2l0Y2gsIEhvc3Qtb25seSwgYW5kIFBlcmlwaGVyYWwtb25seS4KKwor CSAgSWYgeW91IGNob29zZSB0byBidWlsZCB0aGlzIGRyaXZlciBpcyBhIGR5bmFtaWNhbGx5IGxp bmtlZAorCSAgbW9kdWxlLCB0aGUgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGNkbnMzLmtvLgorCitp ZiBVU0JfQ0ROUzMKKworY29uZmlnIFVTQl9DRE5TM19HQURHRVQKKyAgICAgICAgYm9vbCAiQ2Fk ZW5jZSBVU0IzIGRldmljZSBjb250cm9sbGVyIgorICAgICAgICBkZXBlbmRzIG9uIFVTQl9HQURH RVQKKyAgICAgICAgaGVscAorICAgICAgICAgIFNheSBZIGhlcmUgdG8gZW5hYmxlIGRldmljZSBj b250cm9sbGVyIGZ1bmN0aW9uYWxpdHkgb2YgdGhlCisgICAgICAgICAgY2FkZW5jZSBVU0JTUy1E RVYgZHJpdmVyLgorCisgICAgICAgICAgVGhpcyBjb250cm9sbGVyIHN1cHBvcnRzIEZGLCBIUyBh bmQgU1MgbW9kZS4gSXQgZG9lc24ndCBzdXBwb3J0CisgICAgICAgICAgTFMgYW5kIFNTUCBtb2Rl CisKK2NvbmZpZyBVU0JfQ0ROUzNfSE9TVAorICAgICAgICBib29sICJDYWRlbmNlIFVTQjMgaG9z dCBjb250cm9sbGVyIgorICAgICAgICBkZXBlbmRzIG9uIFVTQl9YSENJX0hDRAorICAgICAgICBo ZWxwCisgICAgICAgICAgU2F5IFkgaGVyZSB0byBlbmFibGUgaG9zdCBjb250cm9sbGVyIGZ1bmN0 aW9uYWxpdHkgb2YgdGhlCisgICAgICAgICAgY2FkZW5jZSBkcml2ZXIuCisKKyAgICAgICAgICBI b3N0IGNvbnRyb2xsZXIgaXMgY29tcGxpYW5jZSB3aXRoIFhIQ0kgc28gaXQgd2lsbCB1c2UKKyAg ICAgICAgICBzdGFuZGFyZCBYSENJIGRyaXZlci4KKworY29uZmlnIFVTQl9DRE5TM19QQ0lfV1JB UAorCXRyaXN0YXRlICJDYWRlbmNlIFVTQjMgc3VwcG9ydCBvbiBQQ0llLWJhc2VkIHBsYXRmb3Jt cyIKKwlkZXBlbmRzIG9uIFVTQl9QQ0kgJiYgQUNQSQorCWRlZmF1bHQgVVNCX0NETlMzCisJaGVs cAorCSAgSWYgeW91J3JlIHVzaW5nIHRoZSBVU0JTUyBDb3JlIElQIHdpdGggYSBQQ0llLCBwbGVh c2Ugc2F5CisJICAnWScgb3IgJ00nIGhlcmUuCisKKwkgIElmIHlvdSBjaG9vc2UgdG8gYnVpbGQg dGhpcyBkcml2ZXIgYXMgbW9kdWxlIGl0IHdpbGwKKwkgIGJlIGR5bmFtaWNhbGx5IGxpbmtlZCBh bmQgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGNkbnMzLXBjaS5rbworCitlbmRpZgpkaWZmIC0tZ2l0 IGEvZHJpdmVycy91c2IvY2RuczMvTWFrZWZpbGUgYi9kcml2ZXJzL3VzYi9jZG5zMy9NYWtlZmls ZQpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLjNmNjNiYWEyNDI5NAot LS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL01ha2VmaWxlCkBAIC0wLDAgKzEs MTYgQEAKKyMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKyMgZGVmaW5lX3RyYWNl LmggbmVlZHMgdG8ga25vdyBob3cgdG8gZmluZCBvdXIgaGVhZGVyCitDRkxBR1NfdHJhY2UubwkJ CQk6PSAtSSQoc3JjKQorCitvYmotJChDT05GSUdfVVNCX0NETlMzKQkJCSs9IGNkbnMzLm8KK29i ai0kKENPTkZJR19VU0JfQ0ROUzNfUENJX1dSQVApCSs9IGNkbnMzLXBjaS5vCisKK2NkbnMzLXkJ CQkJCTo9IGNvcmUubyBkcmQubyB0cmFjZS5vCisKK2lmbmVxICgkKENPTkZJR19ERUJVR19GUyks KQorCWNkbnMzLXkJCQkJKz0gZGVidWdmcy5vCitlbmRpZgorCitjZG5zMy0kKENPTkZJR19VU0Jf Q0ROUzNfR0FER0VUKQkrPSBnYWRnZXQubyBlcDAubworY2RuczMtJChDT05GSUdfVVNCX0NETlMz X0hPU1QpCQkrPSBob3N0Lm8KK2NkbnMzLXBjaS15CQkgCQk6PSBjZG5zMy1wY2ktd3JhcC5vCmRp ZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9jZG5zMy1wY2ktd3JhcC5jIGIvZHJpdmVycy91 c2IvY2RuczMvY2RuczMtcGNpLXdyYXAuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAw MDAwMDAwMDAuLmU5MzE3OWM0NWVjZQotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvdXNiL2Nk bnMzL2NkbnMzLXBjaS13cmFwLmMKQEAgLTAsMCArMSwxNTcgQEAKKy8vIFNQRFgtTGljZW5zZS1J ZGVudGlmaWVyOiBHUEwtMi4wCisvKgorICogQ2FkZW5jZSBVU0JTUyBQQ0kgR2x1ZSBkcml2ZXIK KyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5jZS4KKyAqCisgKiBBdXRob3I6IFBhd2Vs IExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+CisgKi8KKworI2luY2x1ZGUgPGxpbnV4L2tl cm5lbC5oPgorI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgorI2luY2x1ZGUgPGxpbnV4L3BjaS5o PgorI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPgorI2luY2x1ZGUgPGxpbnV4L2Rt YS1tYXBwaW5nLmg+CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgorCitzdHJ1Y3QgY2RuczNfd3Jh cCB7CisJc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGxhdF9kZXY7CisJc3RydWN0IHBjaV9kZXYg KmhnX2RldjsKKwlzdHJ1Y3QgcmVzb3VyY2UgZGV2X3Jlc1s0XTsKK307CisKK3N0cnVjdCBjZG5z M193cmFwIHdyYXA7CisKKyNkZWZpbmUgUkVTX0lSUV9JRAkJMAorI2RlZmluZSBSRVNfSE9TVF9J RAkJMQorI2RlZmluZSBSRVNfREVWX0lECQkyCisjZGVmaW5lIFJFU19EUkRfSUQJCTMKKworI2Rl ZmluZSBQQ0lfQkFSX0hPU1QJCTAKKyNkZWZpbmUgUENJX0JBUl9ERVYJCTIKKyNkZWZpbmUgUENJ X0JBUl9PVEcJCTQKKworI2RlZmluZSBQQ0lfREVWX0ZOX0hPU1RfREVWSUNFCTAKKyNkZWZpbmUg UENJX0RFVl9GTl9PVEcJCTEKKworI2RlZmluZSBQQ0lfRFJJVkVSX05BTUUJCSJjZG5zMy1wY2kt dXNic3MiCisjZGVmaW5lIFBMQVRfRFJJVkVSX05BTUUJImNkbnMtdXNiMyIKKworI2RlZmluZSBD RE5TX1ZFTkRPUl9JRCAweDE3Y2QKKyNkZWZpbmUgQ0ROU19ERVZJQ0VfSUQgMHgwMTAwCisKKy8q KgorICogY2RuczNfcGNpX3Byb2JlIC0gUHJvYmUgZnVuY3Rpb24gZm9yIENhZGVuY2UgVVNCIHdy YXBwZXIgZHJpdmVyCisgKiBAcGRldjogcGxhdGZvcm0gZGV2aWNlIG9iamVjdAorICogQGlkOiBw Y2kgZGV2aWNlIGlkCisgKgorICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0 aXZlIGVycm5vCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfcGNpX3Byb2JlKHN0cnVjdCBwY2lfZGV2 ICpwZGV2LAorCQkJICAgY29uc3Qgc3RydWN0IHBjaV9kZXZpY2VfaWQgKmlkKQoreworCXN0cnVj dCBwbGF0Zm9ybV9kZXZpY2VfaW5mbyBwbGF0X2luZm87CisJc3RydWN0IGNkbnMzX3dyYXAgKndy YXA7CisJc3RydWN0IHJlc291cmNlICpyZXM7CisJaW50IGVycjsKKworCS8qCisJICogZm9yIEdB REdFVC9IT1NUIFBDSSAoZGV2Zm4pIGZ1bmN0aW9uIG51bWJlciBpcyAwLAorCSAqIGZvciBPVEcg UENJIChkZXZmbikgZnVuY3Rpb24gbnVtYmVyIGlzIDEKKwkgKi8KKwlpZiAoIWlkIHx8IHBkZXYt PmRldmZuICE9IFBDSV9ERVZfRk5fSE9TVF9ERVZJQ0UpCisJCXJldHVybiAtRUlOVkFMOworCisJ ZXJyID0gcGNpbV9lbmFibGVfZGV2aWNlKHBkZXYpOworCWlmIChlcnIpIHsKKwkJZGV2X2Vycigm cGRldi0+ZGV2LCAiRW5hYmxpbmcgUENJIGRldmljZSBoYXMgZmFpbGVkICVkXG4iLCBlcnIpOwor CQlyZXR1cm4gZXJyOworCX0KKworCXBjaV9zZXRfbWFzdGVyKHBkZXYpOworCXdyYXAgPSBkZXZt X2t6YWxsb2MoJnBkZXYtPmRldiwgc2l6ZW9mKCp3cmFwKSwgR0ZQX0tFUk5FTCk7CisJaWYgKCF3 cmFwKSB7CisJCWRldl9lcnIoJnBkZXYtPmRldiwgIkZhaWxlZCB0byBhbGxvY2F0ZSBtZW1vcnlc biIpOworCQlyZXR1cm4gLUVOT01FTTsKKwl9CisKKwkvKiBmdW5jdGlvbiAwOiBob3N0KEJBUl8w KSArIGRldmljZShCQVJfMSkgKyBvdGcoQkFSXzIpKS4gKi8KKwltZW1zZXQod3JhcC0+ZGV2X3Jl cywgMHgwMCwKKwkgICAgICAgc2l6ZW9mKHN0cnVjdCByZXNvdXJjZSkgKiBBUlJBWV9TSVpFKHdy YXAtPmRldl9yZXMpKTsKKwlkZXZfZGJnKCZwZGV2LT5kZXYsICJJbml0aWFsaXplIERldmljZSBy ZXNvdXJjZXNcbiIpOworCXJlcyA9IHdyYXAtPmRldl9yZXM7CisKKwlyZXNbUkVTX0RFVl9JRF0u c3RhcnQgPSBwY2lfcmVzb3VyY2Vfc3RhcnQocGRldiwgUENJX0JBUl9ERVYpOworCXJlc1tSRVNf REVWX0lEXS5lbmQgPSAgIHBjaV9yZXNvdXJjZV9lbmQocGRldiwgUENJX0JBUl9ERVYpOworCXJl c1tSRVNfREVWX0lEXS5uYW1lID0gImNkbnMzLWRldi1yZWdzIjsKKwlyZXNbUkVTX0RFVl9JRF0u ZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKKwlkZXZfZGJnKCZwZGV2LT5kZXYsICJVU0JTUy1ERVYg cGh5c2ljYWwgYmFzZSBhZGRyOiAlcGFcbiIsCisJCSZyZXNbUkVTX0RFVl9JRF0uc3RhcnQpOwor CisJcmVzW1JFU19IT1NUX0lEXS5zdGFydCA9IHBjaV9yZXNvdXJjZV9zdGFydChwZGV2LCBQQ0lf QkFSX0hPU1QpOworCXJlc1tSRVNfSE9TVF9JRF0uZW5kID0gcGNpX3Jlc291cmNlX2VuZChwZGV2 LCBQQ0lfQkFSX0hPU1QpOworCXJlc1tSRVNfSE9TVF9JRF0ubmFtZSA9ICJjZG5zMy14aGNpLXJl Z3MiOworCXJlc1tSRVNfSE9TVF9JRF0uZmxhZ3MgPSBJT1JFU09VUkNFX01FTTsKKwlkZXZfZGJn KCZwZGV2LT5kZXYsICJVU0JTUy1YSENJIHBoeXNpY2FsIGJhc2UgYWRkcjogJXBhXG4iLAorCQkm cmVzW1JFU19IT1NUX0lEXS5zdGFydCk7CisKKwlyZXNbUkVTX0RSRF9JRF0uc3RhcnQgPSBwY2lf cmVzb3VyY2Vfc3RhcnQocGRldiwgUENJX0JBUl9PVEcpOworCXJlc1tSRVNfRFJEX0lEXS5lbmQg PSAgIHBjaV9yZXNvdXJjZV9lbmQocGRldiwgUENJX0JBUl9PVEcpOworCXJlc1tSRVNfRFJEX0lE XS5uYW1lID0gImNkbnMzLW90ZyI7CisJcmVzW1JFU19EUkRfSURdLmZsYWdzID0gSU9SRVNPVVJD RV9NRU07CisJZGV2X2RiZygmcGRldi0+ZGV2LCAiVVNCU1MtRFJEIHBoeXNpY2FsIGJhc2UgYWRk cjogJXBhXG4iLAorCQkmcmVzW1JFU19EUkRfSURdLnN0YXJ0KTsKKworCS8qIEludGVycnVwdCBj b21tb24gZm9yIGJvdGggZGV2aWNlIGFuZCBYSENJICovCisJd3JhcC0+ZGV2X3Jlc1tSRVNfSVJR X0lEXS5zdGFydCA9IHBkZXYtPmlycTsKKwl3cmFwLT5kZXZfcmVzW1JFU19JUlFfSURdLm5hbWUg PSAiY2RuczMtaXJxIjsKKwl3cmFwLT5kZXZfcmVzW1JFU19JUlFfSURdLmZsYWdzID0gSU9SRVNP VVJDRV9JUlE7CisKKwkvKiBzZXQgdXAgcGxhdGZvcm0gZGV2aWNlIGluZm8gKi8KKwltZW1zZXQo JnBsYXRfaW5mbywgMCwgc2l6ZW9mKHBsYXRfaW5mbykpOworCXBsYXRfaW5mby5wYXJlbnQgPSAm cGRldi0+ZGV2OworCXBsYXRfaW5mby5md25vZGUgPSBwZGV2LT5kZXYuZndub2RlOworCXBsYXRf aW5mby5uYW1lID0gUExBVF9EUklWRVJfTkFNRTsKKwlwbGF0X2luZm8uaWQgPSBwZGV2LT5kZXZm bjsKKwlwbGF0X2luZm8ucmVzID0gd3JhcC0+ZGV2X3JlczsKKwlwbGF0X2luZm8ubnVtX3JlcyA9 IEFSUkFZX1NJWkUod3JhcC0+ZGV2X3Jlcyk7CisJcGxhdF9pbmZvLmRtYV9tYXNrID0gcGRldi0+ ZG1hX21hc2s7CisKKwkvKiByZWdpc3RlciBwbGF0Zm9ybSBkZXZpY2UgKi8KKwl3cmFwLT5wbGF0 X2RldiA9IHBsYXRmb3JtX2RldmljZV9yZWdpc3Rlcl9mdWxsKCZwbGF0X2luZm8pOworCWlmIChJ U19FUlIod3JhcC0+cGxhdF9kZXYpKSB7CisJCWVyciA9IFBUUl9FUlIod3JhcC0+cGxhdF9kZXYp OworCQlyZXR1cm4gZXJyOworCX0KKworCXBjaV9zZXRfZHJ2ZGF0YShwZGV2LCB3cmFwKTsKKwor CXJldHVybiBlcnI7Cit9CisKK3ZvaWQgY2RuczNfcGNpX3JlbW92ZShzdHJ1Y3QgcGNpX2RldiAq cGRldikKK3sKKwlzdHJ1Y3QgY2RuczNfd3JhcCAqd3JhcCA9IChzdHJ1Y3QgY2RuczNfd3JhcCAq KXBjaV9nZXRfZHJ2ZGF0YShwZGV2KTsKKworCXBsYXRmb3JtX2RldmljZV91bnJlZ2lzdGVyKHdy YXAtPnBsYXRfZGV2KTsKK30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBwY2lfZGV2aWNlX2lkIGNk bnMzX3BjaV9pZHNbXSA9IHsKKwl7IFBDSV9ERVZJQ0UoQ0ROU19WRU5ET1JfSUQsIENETlNfREVW SUNFX0lEKSwgfSwKKwl7IDAsIH0KK307CisKK3N0YXRpYyBzdHJ1Y3QgcGNpX2RyaXZlciBjZG5z M19wY2lfZHJpdmVyID0geworCS5uYW1lID0gUENJX0RSSVZFUl9OQU1FLAorCS5pZF90YWJsZSA9 IGNkbnMzX3BjaV9pZHMsCisJLnByb2JlID0gY2RuczNfcGNpX3Byb2JlLAorCS5yZW1vdmUgPSBj ZG5zM19wY2lfcmVtb3ZlLAorfTsKKworbW9kdWxlX3BjaV9kcml2ZXIoY2RuczNfcGNpX2RyaXZl cik7CitNT0RVTEVfREVWSUNFX1RBQkxFKHBjaSwgY2RuczNfcGNpX2lkcyk7CisKK01PRFVMRV9B VVRIT1IoIlBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+Iik7CitNT0RVTEVfTElD RU5TRSgiR1BMIHYyIik7CitNT0RVTEVfREVTQ1JJUFRJT04oIkNhZGVuY2UgVVNCU1MgUENJIHdy YXBwZXJyIik7CisKZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL2NvcmUuYyBiL2RyaXZl cnMvdXNiL2NkbnMzL2NvcmUuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAw MDAuLmI5M2UzNzg4YmQzMwotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2Nv cmUuYwpAQCAtMCwwICsxLDQ1MSBAQAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0y LjAKKy8qCisgKiBDYWRlbmNlIFVTQlNTIERSRCBEcml2ZXIuCisgKgorICogQ29weXJpZ2h0IChD KSAyMDE4IENhZGVuY2UuCisgKiBDb3B5cmlnaHQgKEMpIDIwMTctMjAxOCBOWFAKKyAqCisgKiBB dXRob3I6IFBldGVyIENoZW4gPHBldGVyLmNoZW5AbnhwLmNvbT4KKyAqICAgICAgICAgUGF3ZWwg TGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KKyAqLworCisjaW5jbHVkZSA8bGludXgvbW9k dWxlLmg+CisjaW5jbHVkZSA8bGludXgva2VybmVsLmg+CisjaW5jbHVkZSA8bGludXgvcGxhdGZv cm1fZGV2aWNlLmg+CisjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+CisjaW5jbHVkZSA8bGlu dXgvaW8uaD4KKyNpbmNsdWRlIDxsaW51eC9wbV9ydW50aW1lLmg+CisKKyNpbmNsdWRlICJnYWRn ZXQuaCIKKyNpbmNsdWRlICJjb3JlLmgiCisjaW5jbHVkZSAiaG9zdC1leHBvcnQuaCIKKyNpbmNs dWRlICJnYWRnZXQtZXhwb3J0LmgiCisjaW5jbHVkZSAiZHJkLmgiCisjaW5jbHVkZSAiZGVidWcu aCIKKworc3RhdGljIGlubGluZQorc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyICpjZG5zM19nZXRf Y3VycmVudF9yb2xlX2RyaXZlcihzdHJ1Y3QgY2RuczMgKmNkbnMpCit7CisJV0FSTl9PTihjZG5z LT5yb2xlID49IENETlMzX1JPTEVfRU5EIHx8ICFjZG5zLT5yb2xlc1tjZG5zLT5yb2xlXSk7CisJ cmV0dXJuIGNkbnMtPnJvbGVzW2NkbnMtPnJvbGVdOworfQorCitzdGF0aWMgaW5saW5lIGludCBj ZG5zM19yb2xlX3N0YXJ0KHN0cnVjdCBjZG5zMyAqY2RucywgZW51bSBjZG5zM19yb2xlcyByb2xl KQoreworCWludCByZXQ7CisKKwlpZiAoV0FSTl9PTihyb2xlID49IENETlMzX1JPTEVfRU5EKSkK KwkJcmV0dXJuIDA7CisKKwlpZiAoIWNkbnMtPnJvbGVzW3JvbGVdKQorCQlyZXR1cm4gLUVOWElP OworCisJaWYgKGNkbnMtPnJvbGVzW3JvbGVdLT5zdGF0ZSA9PSBDRE5TM19ST0xFX1NUQVRFX0FD VElWRSkKKwkJcmV0dXJuIDA7CisKKwltdXRleF9sb2NrKCZjZG5zLT5tdXRleCk7CisJY2Rucy0+ cm9sZSA9IHJvbGU7CisJcmV0ID0gY2Rucy0+cm9sZXNbcm9sZV0tPnN0YXJ0KGNkbnMpOworCWlm ICghcmV0KQorCQljZG5zLT5yb2xlc1tyb2xlXS0+c3RhdGUgPSBDRE5TM19ST0xFX1NUQVRFX0FD VElWRTsKKwltdXRleF91bmxvY2soJmNkbnMtPm11dGV4KTsKKwlyZXR1cm4gcmV0OworfQorCit2 b2lkIGNkbnMzX3JvbGVfc3RvcChzdHJ1Y3QgY2RuczMgKmNkbnMpCit7CisJZW51bSBjZG5zM19y b2xlcyByb2xlID0gY2Rucy0+cm9sZTsKKworCWlmIChyb2xlID49IENETlMzX1JPTEVfRU5EKSB7 CisJCVdBUk5fT04ocm9sZSA+IENETlMzX1JPTEVfRU5EKTsKKwkJcmV0dXJuOworCX0KKworCWlm IChjZG5zLT5yb2xlc1tyb2xlXS0+c3RhdGUgPT0gQ0ROUzNfUk9MRV9TVEFURV9JTkFDVElWRSkK KwkJcmV0dXJuOworCisJbXV0ZXhfbG9jaygmY2Rucy0+bXV0ZXgpOworCWNkbnMtPnJvbGVzW3Jv bGVdLT5zdG9wKGNkbnMpOworCWNkbnMtPnJvbGVzW3JvbGVdLT5zdGF0ZSA9IENETlMzX1JPTEVf U1RBVEVfSU5BQ1RJVkU7CisJbXV0ZXhfdW5sb2NrKCZjZG5zLT5tdXRleCk7Cit9CisKKy8qCisg KiBjZG5zLT5yb2xlIGdldHMgZnJvbSBjZG5zM19nZXRfaW5pdGlhbF9yb2xlLCBhbmQgdGhpcyBB UEkgdGVsbHMgcm9sZSBhdCB0aGUKKyAqIHJ1bnRpbWUuCisgKiBJZiBib3RoIHJvbGVzIGFyZSBz dXBwb3J0ZWQsIHRoZSByb2xlIGlzIHNlbGVjdGVkIGJhc2VkIG9uIHZidXMvaWQuCisgKiBJdCBj b3VsZCBiZSByZWFkIGZyb20gT1RHIHJlZ2lzdGVyIG9yIGV4dGVybmFsIGNvbm5lY3Rvci4KKyAq IElmIG9ubHkgc2luZ2xlIHJvbGUgaXMgc3VwcG9ydGVkLCBvbmx5IG9uZSByb2xlIHN0cnVjdHVy ZQorICogaXMgYWxsb2NhdGVkLCBjZG5zLT5yb2xlc1tDRE5TM19ST0xFX0hPU1RdIG9yIGNkbnMt PnJvbGVzW0NETlMzX1JPTEVfR0FER0VUXS4KKyAqLworc3RhdGljIGVudW0gY2RuczNfcm9sZXMg Y2RuczNfZ2V0X2luaXRpYWxfcm9sZShzdHJ1Y3QgY2RuczMgKmNkbnMpCit7CisJaWYgKGNkbnMt PnJvbGVzW0NETlMzX1JPTEVfSE9TVF0gJiYgY2Rucy0+cm9sZXNbQ0ROUzNfUk9MRV9HQURHRVRd KSB7CisJCWlmIChjZG5zM19pc19ob3N0KGNkbnMpKQorCQkJcmV0dXJuIENETlMzX1JPTEVfSE9T VDsKKwkJaWYgKGNkbnMzX2lzX2RldmljZShjZG5zKSkKKwkJCXJldHVybiBDRE5TM19ST0xFX0dB REdFVDsKKwl9CisJcmV0dXJuIGNkbnMtPnJvbGVzW0NETlMzX1JPTEVfSE9TVF0KKwkJPyBDRE5T M19ST0xFX0hPU1QKKwkJOiBDRE5TM19ST0xFX0dBREdFVDsKK30KKworc3RhdGljIHZvaWQgY2Ru czNfZXhpdF9yb2xlcyhzdHJ1Y3QgY2RuczMgKmNkbnMpCit7CisJY2RuczNfcm9sZV9zdG9wKGNk bnMpOworCWNkbnMzX2RyZF9leGl0KGNkbnMpOworfQorCisvKioKKyAqIGNkbnMzX2NvcmVfaW5p dF9yb2xlIC0gaW5pdGlhbGl6ZSByb2xlIG9mIG9wZXJhdGlvbgorICogQGNkbnM6IFBvaW50ZXIg dG8gY2RuczMgc3RydWN0dXJlCisgKgorICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNl IG5lZ2F0aXZlIGVycm5vCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfY29yZV9pbml0X3JvbGUoc3Ry dWN0IGNkbnMzICpjZG5zKQoreworCXN0cnVjdCBkZXZpY2UgKmRldiA9IGNkbnMtPmRldjsKKwll bnVtIHVzYl9kcl9tb2RlIGJlc3RfZHJfbW9kZTsKKwllbnVtIHVzYl9kcl9tb2RlIGRyX21vZGU7 CisJaW50IHJldCA9IDA7CisKKwlkcl9tb2RlID0gdXNiX2dldF9kcl9tb2RlKGRldik7CisJY2Ru cy0+cm9sZSA9IENETlMzX1JPTEVfRU5EOworCisJLyoKKwkgKiBJZiBkcml2ZXIgY2FuJ3QgcmVh ZCBtb2RlIGJ5IG1lYW5zIG9mIHVzYl9nZXRfZHJfbWRvZSBmdW5jdGlvbiB0aGVuCisJICogY2hv b3NlcyBtb2RlIGFjY29yZGluZyB3aXRoIEtlcm5lbCBjb25maWd1cmF0aW9uLiBUaGlzIHNldHRp bmcKKwkgKiBjYW4gYmUgcmVzdHJpY3RlZCBsYXRlciBkZXBlbmRpbmcgb24gc3RyYXAgcGluIGNv bmZpZ3VyYXRpb24uCisJICovCisJaWYgKGRyX21vZGUgPT0gVVNCX0RSX01PREVfVU5LTk9XTikg eworCQlpZiAoSVNfRU5BQkxFRChDT05GSUdfVVNCX0NETlMzX0hPU1QpICYmCisJCSAgICBJU19F TkFCTEVEKENPTkZJR19VU0JfQ0ROUzNfR0FER0VUKSkKKwkJCWRyX21vZGUgPSBVU0JfRFJfTU9E RV9PVEc7CisJCWVsc2UgaWYgKElTX0VOQUJMRUQoQ09ORklHX1VTQl9DRE5TM19IT1NUKSkKKwkJ CWRyX21vZGUgPSBVU0JfRFJfTU9ERV9IT1NUOworCQllbHNlIGlmIChJU19FTkFCTEVEKENPTkZJ R19VU0JfQ0ROUzNfR0FER0VUKSkKKwkJCWRyX21vZGUgPSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFM OworCX0KKworCWJlc3RfZHJfbW9kZSA9IFVTQl9EUl9NT0RFX09URzsKKworCWlmIChkcl9tb2Rl ID09IFVTQl9EUl9NT0RFX09URykgeworCQliZXN0X2RyX21vZGUgPSBjZG5zLT5kcl9tb2RlOwor CX0gZWxzZSBpZiAoY2Rucy0+ZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9PVEcpIHsKKwkJYmVzdF9k cl9tb2RlID0gZHJfbW9kZTsKKwl9IGVsc2UgaWYgKGNkbnMtPmRyX21vZGUgIT0gZHJfbW9kZSkg eworCQlkZXZfZXJyKGRldiwgIkluY29ycmVjdCBEUkQgY29uZmlndXJhdGlvblxuIik7CisJCXJl dHVybiAtRUlOVkFMOworCX0KKworCWRyX21vZGUgPSBiZXN0X2RyX21vZGU7CisKKwlpZiAoZHJf bW9kZSA9PSBVU0JfRFJfTU9ERV9PVEcgfHwgZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9IT1NUKSB7 CisJCXJldCA9IGNkbnMzX2hvc3RfaW5pdChjZG5zKTsKKwkJaWYgKHJldCkgeworCQkJZGV2X2Vy cihkZXYsICJIb3N0IGluaXRpYWxpemF0aW9uIGZhaWxlZCB3aXRoICVkXG4iLAorCQkJCXJldCk7 CisJCQlnb3RvIGVycjsKKwkJfQorCX0KKworCWlmIChkcl9tb2RlID09IFVTQl9EUl9NT0RFX09U RyB8fCBkcl9tb2RlID09IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwpIHsKKwkJcmV0ID0gY2RuczNf Z2FkZ2V0X2luaXQoY2Rucyk7CisJCWlmIChyZXQpIHsKKwkJCWRldl9lcnIoZGV2LCAiRGV2aWNl IGluaXRpYWxpemF0aW9uIGZhaWxlZCB3aXRoICVkXG4iLAorCQkJCXJldCk7CisJCQlnb3RvIGVy cjsKKwkJfQorCX0KKworCWNkbnMtPmRlc2lyZWRfZHJfbW9kZSA9IGRyX21vZGU7CisJY2Rucy0+ ZHJfbW9kZSA9IGRyX21vZGU7CisJLyoKKwkgKiBkcl9tb2RlIGNvdWxkIGJlIGNoYW5nZSBzbyBE UkQgbXVzdCB1cGRhdGUgY29udHJvbGxlcgorCSAqIGNvbmZpZ3VyYXRpb24KKwkgKi8KKwlyZXQg PSBjZG5zM19kcmRfdXBkYXRlX21vZGUoY2Rucyk7CisKKwljZG5zLT5yb2xlID0gY2RuczNfZ2V0 X2luaXRpYWxfcm9sZShjZG5zKTsKKworCXJldCA9IGNkbnMzX3JvbGVfc3RhcnQoY2RucywgY2Ru cy0+cm9sZSk7CisJaWYgKHJldCkgeworCQlkZXZfZXJyKGRldiwgImNhbid0IHN0YXJ0ICVzIHJv bGVcbiIsCisJCQljZG5zM19nZXRfY3VycmVudF9yb2xlX2RyaXZlcihjZG5zKS0+bmFtZSk7CisJ CWdvdG8gZXJyOworCX0KKworCXJldHVybiByZXQ7CitlcnI6CisJY2RuczNfZXhpdF9yb2xlcyhj ZG5zKTsKKwlyZXR1cm4gcmV0OworfQorCisvKioKKyAqIGNkc24zX2dldF9yZWFsX3JvbGUgLSBn ZXQgcmVhbCByb2xlIG9mIGNvbnRyb2xsZXIgYmFzZWQgb24gaGFyZHdhcmUgc2V0dGluZ3MuCisg KiBAY2RuczogUG9pbnRlciB0byBjZG5zMyBzdHJ1Y3R1cmUKKyAqCisgKiBSZXR1cm5zIHJvbGUK KyAqLworZW51bSBjZG5zM19yb2xlcyBjZHNuM19nZXRfcmVhbF9yb2xlKHN0cnVjdCBjZG5zMyAq Y2RucykKK3sKKwllbnVtIGNkbnMzX3JvbGVzIHJvbGUgPSBDRE5TM19ST0xFX0VORDsKKworCWlm IChjZG5zLT5jdXJyZW50X2RyX21vZGUgPT0gVVNCX0RSX01PREVfT1RHKSB7CisJCWlmIChjZG5z M19nZXRfaWQoY2RucykpCisJCQlyb2xlID0gQ0ROUzNfUk9MRV9HQURHRVQ7CisJCWVsc2UKKwkJ CXJvbGUgPSBDRE5TM19ST0xFX0hPU1Q7CisJfSBlbHNlIHsKKwkJaWYgKGNkbnMzX2lzX2hvc3Qo Y2RucykpCisJCQlyb2xlID0gQ0ROUzNfUk9MRV9IT1NUOworCQlpZiAoY2RuczNfaXNfZGV2aWNl KGNkbnMpKQorCQkJcm9sZSA9IENETlMzX1JPTEVfR0FER0VUOworCX0KKworCXJldHVybiByb2xl OworfQorCisvKioKKyAqIGNkbnMzX3JvbGVfc3dpdGNoIC0gd29yayBxdWV1ZSBoYW5kbGVyIGZv ciByb2xlIHN3aXRjaAorICoKKyAqIEB3b3JrOiB3b3JrIHF1ZXVlIGl0ZW0gc3RydWN0dXJlCisg KgorICogSGFuZGxlcyBiZWxvdyBldmVudHM6CisgKiAtIFJvbGUgc3dpdGNoIGZvciBkdWFsLXJv bGUgZGV2aWNlcworICogLSBDRE5TM19ST0xFX0dBREdFVCA8LS0+IENETlMzX1JPTEVfRU5EIGZv ciBwZXJpcGhlcmFsLW9ubHkgZGV2aWNlcworICovCitzdGF0aWMgdm9pZCBjZG5zM19yb2xlX3N3 aXRjaChzdHJ1Y3Qgd29ya19zdHJ1Y3QgKndvcmspCit7CisJZW51bSBjZG5zM19yb2xlcyByb2xl ID0gQ0ROUzNfUk9MRV9FTkQ7CisJc3RydWN0IGNkbnMzX3JvbGVfZHJpdmVyICpyb2xlX2RydjsK KwllbnVtIGNkbnMzX3JvbGVzIGN1cnJlbnRfcm9sZTsKKwlzdHJ1Y3QgY2RuczMgKmNkbnM7CisJ aW50IHJldCA9IDA7CisKKwljZG5zID0gY29udGFpbmVyX29mKHdvcmssIHN0cnVjdCBjZG5zMywg cm9sZV9zd2l0Y2hfd3EpOworCisJLyogRHVyaW5nIHN3aXRjaGluZyBjZG5zLT5yb2xlIGNhbiBi ZSBkaWZmZXJlbnQgdGhlbiByb2xlICovCisJcm9sZSA9IGNkc24zX2dldF9yZWFsX3JvbGUoY2Ru cyk7CisKKwlyb2xlX2RydiA9IGNkbnMzX2dldF9jdXJyZW50X3JvbGVfZHJpdmVyKGNkbnMpOwor CisJcG1fcnVudGltZV9nZXRfc3luYyhjZG5zLT5kZXYpOworCisJLyogRGlzYWJsZSBjdXJyZW50 IHJvbGUuIFRoaXMgc3RhdGUgY2FuIGJlIGZvcmNlZCBmcm9tIHVzZXIgc3BhY2UuICovCisJaWYg KGNkbnMtPmRlYnVnX2Rpc2FibGUgJiYgcm9sZV9kcnYtPnN0YXRlID09IENETlMzX1JPTEVfU1RB VEVfQUNUSVZFKSB7CisJCWNkbnMzX3JvbGVfc3RvcChjZG5zKTsKKwkJZ290byBleGl0OworCX0K KworCS8qIERvIG5vdGhpbmcgaWYgbm90aGluZyBjaGFuZ2VkICovCisJaWYgKGNkbnMtPnJvbGUg PT0gcm9sZSAmJiByb2xlX2Rydi0+c3RhdGUgPT0gQ0ROUzNfUk9MRV9TVEFURV9BQ1RJVkUpCisJ CWdvdG8gZXhpdDsKKworCWNkbnMzX3JvbGVfc3RvcChjZG5zKTsKKworCXJvbGUgPSBjZHNuM19n ZXRfcmVhbF9yb2xlKGNkbnMpOworCisJY3VycmVudF9yb2xlID0gY2Rucy0+cm9sZTsKKwlkZXZf ZGJnKGNkbnMtPmRldiwgIlN3aXRjaGluZyByb2xlIik7CisKKwlyZXQgPSBjZG5zM19yb2xlX3N0 YXJ0KGNkbnMsIHJvbGUpOworCisJaWYgKHJldCkgeworCQkvKiBCYWNrIHRvIGN1cnJlbnQgcm9s ZSAqLworCQlkZXZfZXJyKGNkbnMtPmRldiwgInNldCAlZCBoYXMgZmFpbGVkLCBiYWNrIHRvICVk XG4iLAorCQkJcm9sZSwgY3VycmVudF9yb2xlKTsKKwkJY2RuczNfcm9sZV9zdGFydChjZG5zLCBj dXJyZW50X3JvbGUpOworCX0KK2V4aXQ6CisJcG1fcnVudGltZV9wdXRfc3luYyhjZG5zLT5kZXYp OworfQorCisvKioKKyAqIGNkbnMzX3Byb2JlIC0gcHJvYmUgZm9yIGNkbnMzIGNvcmUgZGV2aWNl CisgKiBAcGRldjogUG9pbnRlciB0byBjZG5zMyBjb3JlIHBsYXRmb3JtIGRldmljZQorICoKKyAq IFJldHVybnMgMCBvbiBzdWNjZXNzIG90aGVyd2lzZSBuZWdhdGl2ZSBlcnJubworICovCitzdGF0 aWMgaW50IGNkbnMzX3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCit7CisJc3Ry dWN0IGRldmljZSAqZGV2ID0gJnBkZXYtPmRldjsKKwlzdHJ1Y3QgcmVzb3VyY2UJKnJlczsKKwlz dHJ1Y3QgY2RuczMgKmNkbnM7CisJdm9pZCBfX2lvbWVtICpyZWdzOworCWludCByZXQ7CisKKwlj ZG5zID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpjZG5zKSwgR0ZQX0tFUk5FTCk7CisJaWYg KCFjZG5zKQorCQlyZXR1cm4gLUVOT01FTTsKKworCWNkbnMtPmRldiA9IGRldjsKKworCXBsYXRm b3JtX3NldF9kcnZkYXRhKHBkZXYsIGNkbnMpOworCisJcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291 cmNlKHBkZXYsIElPUkVTT1VSQ0VfSVJRLCAwKTsKKwlpZiAoIXJlcykgeworCQlkZXZfZXJyKGRl diwgIm1pc3NpbmcgSVJRXG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCWNkbnMtPmlycSA9 IHJlcy0+c3RhcnQ7CisKKwljZG5zLT54aGNpX3Jlc1swXSA9ICpyZXM7CisKKwkvKgorCSAqIFJl cXVlc3QgbWVtb3J5IHJlZ2lvbgorCSAqIHJlZ2lvbi0wOiB4SENJCisJICogcmVnaW9uLTE6IFBl cmlwaGVyYWwKKwkgKiByZWdpb24tMjogT1RHIHJlZ2lzdGVycworCSAqLworCXJlcyA9IHBsYXRm b3JtX2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7CisJY2Rucy0+eGhjaV9y ZXNbMV0gPSAqcmVzOworCisJcmVzID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlKHBkZXYsIElPUkVT T1VSQ0VfTUVNLCAxKTsKKwlyZWdzID0gZGV2bV9pb3JlbWFwX3Jlc291cmNlKGRldiwgcmVzKTsK KwlpZiAoSVNfRVJSKHJlZ3MpKQorCQlyZXR1cm4gUFRSX0VSUihyZWdzKTsKKwljZG5zLT5kZXZf cmVncwk9IHJlZ3M7CisKKwlyZXMgPSBwbGF0Zm9ybV9nZXRfcmVzb3VyY2UocGRldiwgSU9SRVNP VVJDRV9NRU0sIDIpOworCXJlZ3MgPSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoZGV2LCByZXMpOwor CWlmIChJU19FUlIocmVncykpCisJCXJldHVybiBQVFJfRVJSKHJlZ3MpOworCWNkbnMtPm90Z19y ZWdzID0gcmVnczsKKworCW11dGV4X2luaXQoJmNkbnMtPm11dGV4KTsKKworCWNkbnMtPnBoeSA9 IGRldm1fcGh5X2dldChkZXYsICJjZG5zMyx1c2JwaHkiKTsKKwlpZiAoSVNfRVJSKGNkbnMtPnBo eSkpIHsKKwkJcmV0ID0gUFRSX0VSUihjZG5zLT5waHkpOworCQlpZiAocmV0ID09IC1FTk9TWVMg fHwgcmV0ID09IC1FTk9ERVYpIHsKKwkJCWNkbnMtPnBoeSA9IE5VTEw7CisJCX0gZWxzZSBpZiAo cmV0ID09IC1FUFJPQkVfREVGRVIpIHsKKwkJCXJldHVybiByZXQ7CisJCX0gZWxzZSB7CisJCQlk ZXZfZXJyKGRldiwgIm5vIHBoeSBmb3VuZFxuIik7CisJCQlnb3RvIGVycjA7CisJCX0KKwl9CisK KwlwaHlfaW5pdChjZG5zLT5waHkpOworCisJSU5JVF9XT1JLKCZjZG5zLT5yb2xlX3N3aXRjaF93 cSwgY2RuczNfcm9sZV9zd2l0Y2gpOworCisJcmV0ID0gY2RuczNfZHJkX2luaXQoY2Rucyk7CisJ aWYgKHJldCkKKwkJZ290byBlcnIxOworCisJcmV0ID0gY2RuczNfY29yZV9pbml0X3JvbGUoY2Ru cyk7CisJaWYgKHJldCkKKwkJZ290byBlcnIxOworCisJY2RuczNfZGVidWdmc19pbml0KGNkbnMp OworCWRldmljZV9zZXRfd2FrZXVwX2NhcGFibGUoZGV2LCB0cnVlKTsKKwlwbV9ydW50aW1lX3Nl dF9hY3RpdmUoZGV2KTsKKwlwbV9ydW50aW1lX2VuYWJsZShkZXYpOworCisJLyoKKwkgKiBUaGUg Y29udHJvbGxlciBuZWVkcyBsZXNzIHRpbWUgYmV0d2VlbiBidXMgYW5kIGNvbnRyb2xsZXIgc3Vz cGVuZCwKKwkgKiBhbmQgd2UgYWxzbyBuZWVkcyBhIHNtYWxsIGRlbGF5IHRvIGF2b2lkIGZyZXF1 ZW50bHkgZW50ZXJpbmcgbG93CisJICogcG93ZXIgbW9kZS4KKwkgKi8KKwlwbV9ydW50aW1lX3Nl dF9hdXRvc3VzcGVuZF9kZWxheShkZXYsIDIwKTsKKwlwbV9ydW50aW1lX21hcmtfbGFzdF9idXN5 KGRldik7CisJcG1fcnVudGltZV91c2VfYXV0b3N1c3BlbmQoZGV2KTsKKwlkZXZfZGJnKGRldiwg IkNhZGVuY2UgVVNCMyBjb3JlOiBwcm9iZSBzdWNjZWVkXG4iKTsKKworCXJldHVybiAwOworCitl cnIxOgorCXBoeV9leGl0KGNkbnMtPnBoeSk7CitlcnIwOgorCXJldHVybiByZXQ7Cit9CisKKy8q KgorICogY2RuczNfcmVtb3ZlIC0gdW5iaW5kIGRyZCBkcml2ZXIgYW5kIGNsZWFuIHVwCisgKiBA cGRldjogUG9pbnRlciB0byBMaW51eCBwbGF0Zm9ybSBkZXZpY2UKKyAqCisgKiBSZXR1cm5zIDAg b24gc3VjY2VzcyBvdGhlcndpc2UgbmVnYXRpdmUgZXJybm8KKyAqLworc3RhdGljIGludCBjZG5z M19yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikKK3sKKwlzdHJ1Y3QgY2RuczMg KmNkbnMgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsKKworCXBtX3J1bnRpbWVfZ2V0X3N5 bmMoJnBkZXYtPmRldik7CisJcG1fcnVudGltZV9kaXNhYmxlKCZwZGV2LT5kZXYpOworCXBtX3J1 bnRpbWVfcHV0X25vaWRsZSgmcGRldi0+ZGV2KTsKKwljZG5zM19kZWJ1Z2ZzX2V4aXQoY2Rucyk7 CisJY2RuczNfZXhpdF9yb2xlcyhjZG5zKTsKKwlwaHlfZXhpdChjZG5zLT5waHkpOworCXJldHVy biAwOworfQorCisjaWZkZWYgQ09ORklHX09GCitzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2Rldmlj ZV9pZCBvZl9jZG5zM19tYXRjaFtdID0geworCXsgLmNvbXBhdGlibGUgPSAiY2Rucyx1c2IzIiB9 LAorCXsgfSwKK307CitNT0RVTEVfREVWSUNFX1RBQkxFKG9mLCBvZl9jZG5zM19tYXRjaCk7Cisj ZW5kaWYKKworI2lmZGVmIENPTkZJR19QTQorCisjaWZkZWYgQ09ORklHX1BNX1NMRUVQCitzdGF0 aWMgaW50IGNkbnMzX3N1c3BlbmQoc3RydWN0IGRldmljZSAqZGV2KQoreworCS8qIFRPRE86IElt cGxlbWVudHMgdGhpcyBmdW5jdGlvbi4gKi8KKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBj ZG5zM19yZXN1bWUoc3RydWN0IGRldmljZSAqZGV2KQoreworCS8qIFRPRE86IEltcGxlbWVudHMg dGhpcyBmdW5jdGlvbi4gKi8KKwlyZXR1cm4gMDsKK30KKyNlbmRpZiAvKiBDT05GSUdfUE1fU0xF RVAgKi8KK3N0YXRpYyBpbnQgY2RuczNfcnVudGltZV9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRl dikKK3sJLyogVE9ETzogSW1wbGVtZW50cyB0aGlzIGZ1bmN0aW9uLiAqLworCXJldHVybiAwOwor fQorCitzdGF0aWMgaW50IGNkbnMzX3J1bnRpbWVfcmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikK K3sKKwkvKiBUT0RPOiBJbXBsZW1lbnRzIHRoaXMgZnVuY3Rpb24uICovCisJcmV0dXJuIDA7Cit9 CisjZW5kaWYgLyogQ09ORklHX1BNICovCisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29w cyBjZG5zM19wbV9vcHMgPSB7CisJU0VUX1NZU1RFTV9TTEVFUF9QTV9PUFMoY2RuczNfc3VzcGVu ZCwgY2RuczNfcmVzdW1lKQorCVNFVF9SVU5USU1FX1BNX09QUyhjZG5zM19ydW50aW1lX3N1c3Bl bmQsIGNkbnMzX3J1bnRpbWVfcmVzdW1lLCBOVUxMKQorfTsKKworc3RhdGljIHN0cnVjdCBwbGF0 Zm9ybV9kcml2ZXIgY2RuczNfZHJpdmVyID0geworCS5wcm9iZQkJPSBjZG5zM19wcm9iZSwKKwku cmVtb3ZlCQk9IGNkbnMzX3JlbW92ZSwKKwkuZHJpdmVyCQk9IHsKKwkJLm5hbWUJPSAiY2Rucy11 c2IzIiwKKwkJLm9mX21hdGNoX3RhYmxlCT0gb2ZfbWF0Y2hfcHRyKG9mX2NkbnMzX21hdGNoKSwK KwkJLnBtCT0gJmNkbnMzX3BtX29wcywKKwl9LAorfTsKKworc3RhdGljIGludCBfX2luaXQgY2Ru czNfZHJpdmVyX3BsYXRmb3JtX3JlZ2lzdGVyKHZvaWQpCit7CisJcmV0dXJuIHBsYXRmb3JtX2Ry aXZlcl9yZWdpc3RlcigmY2RuczNfZHJpdmVyKTsKK30KK21vZHVsZV9pbml0KGNkbnMzX2RyaXZl cl9wbGF0Zm9ybV9yZWdpc3Rlcik7CisKK3N0YXRpYyB2b2lkIF9fZXhpdCBjZG5zM19kcml2ZXJf cGxhdGZvcm1fdW5yZWdpc3Rlcih2b2lkKQoreworCXBsYXRmb3JtX2RyaXZlcl91bnJlZ2lzdGVy KCZjZG5zM19kcml2ZXIpOworfQorbW9kdWxlX2V4aXQoY2RuczNfZHJpdmVyX3BsYXRmb3JtX3Vu cmVnaXN0ZXIpOworCitNT0RVTEVfQUxJQVMoInBsYXRmb3JtOmNkbnMzIik7CitNT0RVTEVfQVVU SE9SKCJQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPiIpOworTU9EVUxFX0xJQ0VO U0UoIkdQTCB2MiIpOworTU9EVUxFX0RFU0NSSVBUSU9OKCJDYWRlbmNlIFVTQjMgRFJEIENvbnRy b2xsZXIgRHJpdmVyIik7CmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9jb3JlLmggYi9k cml2ZXJzL3VzYi9jZG5zMy9jb3JlLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAw MDAwMDAwLi5mZmQxOTcxZmY4OTMKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL3VzYi9jZG5z My9jb3JlLmgKQEAgLTAsMCArMSwxMDggQEAKKy8qIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBH UEwtMi4wICovCisvKgorICogQ2FkZW5jZSBVU0JTUyBEUkQgSGVhZGVyIEZpbGUuCisgKgorICog Q29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCisgKiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5j ZS4KKyAqCisgKiBBdXRob3JzOiBQZXRlciBDaGVuIDxwZXRlci5jaGVuQG54cC5jb20+CisgKiAg ICAgICAgICBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICovCisjaW5jbHVk ZSA8bGludXgvdXNiL290Zy5oPgorCisjaWZuZGVmIF9fTElOVVhfQ0ROUzNfQ09SRV9ICisjZGVm aW5lIF9fTElOVVhfQ0ROUzNfQ09SRV9ICisKK3N0cnVjdCBjZG5zMzsKK2VudW0gY2RuczNfcm9s ZXMgeworCUNETlMzX1JPTEVfSE9TVCA9IDAsCisJQ0ROUzNfUk9MRV9HQURHRVQsCisJQ0ROUzNf Uk9MRV9FTkQsCit9OworCisvKioKKyAqIHN0cnVjdCBjZG5zM19yb2xlX2RyaXZlciAtIGhvc3Qv Z2FkZ2V0IHJvbGUgZHJpdmVyCisgKiBAc3RhcnQ6IHN0YXJ0IHRoaXMgcm9sZQorICogQHN0b3A6 IHN0b3AgdGhpcyByb2xlCisgKiBAc3VzcGVuZDogc3VzcGVuZCBjYWxsYmFjayBmb3IgdGhpcyBy b2xlCisgKiBAcmVzdW1lOiByZXN1bWUgY2FsbGJhY2sgZm9yIHRoaXMgcm9sZQorICogQGlycTog aXJxIGhhbmRsZXIgZm9yIHRoaXMgcm9sZQorICogQG5hbWU6IHJvbGUgbmFtZSBzdHJpbmcgKGhv c3QvZ2FkZ2V0KQorICogQHN0YXRlOiBjdXJyZW50IHN0YXRlCisgKi8KK3N0cnVjdCBjZG5zM19y b2xlX2RyaXZlciB7CisJaW50ICgqc3RhcnQpKHN0cnVjdCBjZG5zMyAqY2Rucyk7CisJdm9pZCAo KnN0b3ApKHN0cnVjdCBjZG5zMyAqY2Rucyk7CisJaW50ICgqc3VzcGVuZCkoc3RydWN0IGNkbnMz ICpjZG5zLCBib29sIGRvX3dha2V1cCk7CisJaW50ICgqcmVzdW1lKShzdHJ1Y3QgY2RuczMgKmNk bnMsIGJvb2wgaGliZXJuYXRlZCk7CisJY29uc3QgY2hhciAqbmFtZTsKKyNkZWZpbmUgQ0ROUzNf Uk9MRV9TVEFURV9JTkFDVElWRQkwCisjZGVmaW5lIENETlMzX1JPTEVfU1RBVEVfQUNUSVZFCQkx CisJaW50IHN0YXRlOworfTsKKworI2RlZmluZSBDRE5TM19YSENJX1JFU09VUkNFU19OVU0JMgor LyoqCisgKiBzdHJ1Y3QgY2RuczMgLSBSZXByZXNlbnRhdGlvbiBvZiBDYWRlbmNlIFVTQjMgRFJE IGNvbnRyb2xsZXIuCisgKiBAZGV2OiBwb2ludGVyIHRvIENhZGVuY2UgZGV2aWNlIHN0cnVjdAor ICogQHhoY2lfcmVnczogcG9pbnRlciB0byBiYXNlIG9mIHhoY2kgcmVnaXN0ZXJzCisgKiBAeGhj aV9yZXM6IHRoZSByZXNvdXJjZSBmb3IgeGhjaQorICogQGRldl9yZWdzOiBwb2ludGVyIHRvIGJh c2Ugb2YgZGV2IHJlZ2lzdGVycworICogQG90Z19yZWdzOiBwb2ludGVyIHRvIGJhc2Ugb2Ygb3Rn IHJlZ2lzdGVycworICogQGlycTogaXJxIG51bWJlciBmb3IgY29udHJvbGxlcgorICogQHJvbGVz OiBhcnJheSBvZiBzdXBwb3J0ZWQgcm9sZXMgZm9yIHRoaXMgY29udHJvbGxlcgorICogQHJvbGU6 IGN1cnJlbnQgcm9sZQorICogQGhvc3RfZGV2OiB0aGUgY2hpbGQgaG9zdCBkZXZpY2UgcG9pbnRl ciBmb3IgY2RuczMgY29yZQorICogQGdhZGdldF9kZXY6IHRoZSBjaGlsZCBnYWRnZXQgZGV2aWNl IHBvaW50ZXIgZm9yIGNkbnMzIGNvcmUKKyAqIEB1c2I6IHBoeSBmb3IgdGhpcyBjb250cm9sbGVy CisgKiBAcm9sZV9zd2l0Y2hfd3E6IHdvcmsgcXVldWUgaXRlbSBmb3Igcm9sZSBzd2l0Y2gKKyAq IEBpbl9scG06IHRoZSBjb250cm9sbGVyIGluIGxvdyBwb3dlciBtb2RlCisgKiBAd2FrZXVwX2lu dDogdGhlIHdha2V1cCBpbnRlcnJ1cHQKKyAqIEBtdXRleDogdGhlIG11dGV4IGZvciBjb25jdXJy ZW50IGNvZGUgYXQgZHJpdmVyCisgKiBAZHJfbW9kZTogc3VwcG9ydGVkIG1vZGUgb2Ygb3BlcmF0 aW9uIGl0IGNhbiBiZSBvbmx5IEhvc3QsIG9ubHkgRGV2aWNlCisgKiAgICAgICAgICAgb3IgT1RH IG1vZGUgdGhhdCBhbGxvdyB0byBzd2l0Y2ggYmV0d2VlbiBEZXZpY2UgYW5kIEhvc3QgbW9kZS4K KyAqICAgICAgICAgICBUaGlzIGZpZWxkIGJhc2VkIG9uIGZpcm13YXJlIHNldHRpbmcsIGtlcm5l bCBjb25maWd1cmF0aW9uCisgKiAgICAgICAgICAgYW5kIGhhcmR3YXJlIGNvbmZpZ3VyYXRpb24u CisgKiBAY3VycmVudF9kcl9tb2RlOiBjdXJyZW50IG1vZGUgb2Ygb3BlcmF0aW9uIHdoZW4gaW4g ZHVhbC1yb2xlIG1vZGUKKyAqIEBkZXNpcmVkX2RyX21vZGU6IGRlc2lyZWQgbW9kZSBvZiBvcGVy YXRpb24gd2hlbiBpbiBkdWFsLXJvbGUgbW9kZS4KKyAqICAgICAgICAgICBUaGlzIHZhbHVlIGNh biBiZSBjaGFuZ2VkIGR1cmluZyBydW50aW1lLgorICogICAgICAgICAgIEF2YWlsYWJsZSBvcHRp b25zIGRlcGVuZHMgb24gIGRyX21vZGU6CisgKiAgICAgICAgICAgZHJfbW9kZSAgICAgICAgICAg ICAgICAgfCAgZGVzaXJlZF9kcl9tb2RlIGFuZCBjdXJyZW50X2RyX21vZGUKKyAqICAgICAgICAg ICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tCisgKiAgICAgICAgICAgVVNCX0RSX01PREVfSE9TVCAgICAgICAgfCBvbmx5IFVT Ql9EUl9NT0RFX0hPU1QKKyAqICAgICAgICAgICBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMICB8IG9u bHkgVVNCX0RSX01PREVfUEVSSVBIRVJBTAorICogICAgICAgICAgIFVTQl9EUl9NT0RFX09URyAg ICAgICAgIHwgb25seSBVU0JfRFJfTU9ERV9IT1NUCisgKiAgICAgICAgICAgVVNCX0RSX01PREVf T1RHICAgICAgICAgfCBvbmx5IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwKKyAqICAgICAgICAgICBV U0JfRFJfTU9ERV9PVEcgICAgICAgICB8IFVTQl9EUl9NT0RFX09URworICoKKyAqICAgICAgICAg ICBEZXNpcmVkX2RyX3JvbGUgY2FuIGJlIGNoYW5nZWQgYnkgbWVhbnMgb2YgZGVidWdmcy4KKyAq IEByb290OiBkZWJ1Z2ZzIHJvb3QgZm9sZGVyIHBvaW50ZXIKKyAqIEBkZWJ1Z19kaXNhYmxlOgor ICovCitzdHJ1Y3QgY2RuczMgeworCXN0cnVjdCBkZXZpY2UJCQkqZGV2OworCXZvaWQgX19pb21l bQkJCSp4aGNpX3JlZ3M7CisJc3RydWN0IHJlc291cmNlCQkJeGhjaV9yZXNbQ0ROUzNfWEhDSV9S RVNPVVJDRVNfTlVNXTsKKwlzdHJ1Y3QgY2RuczNfdXNiX3JlZ3MgX19pb21lbQkqZGV2X3JlZ3M7 CisJc3RydWN0IGNkbnMzX290Z19yZWdzCQkqb3RnX3JlZ3M7CisJaW50IGlycTsKKwlzdHJ1Y3Qg Y2RuczNfcm9sZV9kcml2ZXIJKnJvbGVzW0NETlMzX1JPTEVfRU5EXTsKKwllbnVtIGNkbnMzX3Jv bGVzCQlyb2xlOworCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UJCSpob3N0X2RldjsKKwlzdHJ1Y3Qg Y2RuczNfZGV2aWNlCQkqZ2FkZ2V0X2RldjsKKwlzdHJ1Y3QgcGh5CQkJKnBoeTsKKwlzdHJ1Y3Qg d29ya19zdHJ1Y3QJCXJvbGVfc3dpdGNoX3dxOworCWludAkJCQlpbl9scG06MTsKKwlpbnQJCQkJ d2FrZXVwX2ludDoxOworCS8qIG11dGV4dCB1c2VkIGluIHdvcmtxdWV1ZSovCisJc3RydWN0IG11 dGV4CQkJbXV0ZXg7CisJZW51bSB1c2JfZHJfbW9kZQkJZHJfbW9kZTsKKwllbnVtIHVzYl9kcl9t b2RlCQljdXJyZW50X2RyX21vZGU7CisJZW51bSB1c2JfZHJfbW9kZQkJZGVzaXJlZF9kcl9tb2Rl OworCXN0cnVjdCBkZW50cnkJCQkqcm9vdDsKKwlpbnQJCQkJZGVidWdfZGlzYWJsZToxOworfTsK Kwordm9pZCBjZG5zM19yb2xlX3N0b3Aoc3RydWN0IGNkbnMzICpjZG5zKTsKKworI2VuZGlmIC8q IF9fTElOVVhfQ0ROUzNfQ09SRV9IICovCmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9k ZWJ1Zy5oIGIvZHJpdmVycy91c2IvY2RuczMvZGVidWcuaApuZXcgZmlsZSBtb2RlIDEwMDY0NApp bmRleCAwMDAwMDAwMDAwMDAuLmFmYjgxZDIyNDcxOAotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZl cnMvdXNiL2NkbnMzL2RlYnVnLmgKQEAgLTAsMCArMSwzNDYgQEAKKy8qIFNQRFgtTGljZW5zZS1J ZGVudGlmaWVyOiBHUEwtMi4wICovCisvKgorICogQ2FkZW5jZSBVU0JTUyBEUkQgRHJpdmVyLgor ICogRGVidWcgaGVhZGVyIGZpbGUuCisgKgorICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2Uu CisgKgorICogQXV0aG9yOiBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICov CisjaWZuZGVmIF9fTElOVVhfQ0ROUzNfREVCVUcKKyNkZWZpbmUgX19MSU5VWF9DRE5TM19ERUJV RworI2luY2x1ZGUgImdhZGdldC5oIgorCitzdGF0aWMgaW5saW5lIHZvaWQgY2RuczNfZGVjb2Rl X2dldF9zdGF0dXModTggYlJlcXVlc3RUeXBlLCB1MTYgd0luZGV4LAorCQkJCQkgICB1MTYgd0xl bmd0aCwgY2hhciAqc3RyKQoreworCXN3aXRjaCAoYlJlcXVlc3RUeXBlICYgVVNCX1JFQ0lQX01B U0spIHsKKwljYXNlIFVTQl9SRUNJUF9JTlRFUkZBQ0U6CisJCXNwcmludGYoc3RyLCAiR2V0IElu dGVyZmFjZSBTdGF0dXMgSW50ZiA9ICVkLCBMOiA9ICVkIiwKKwkJCXdJbmRleCwgd0xlbmd0aCk7 CisJCWJyZWFrOworCWNhc2UgVVNCX1JFQ0lQX0VORFBPSU5UOgorCQlzcHJpbnRmKHN0ciwgIkdl dCBFbmRwb2ludCBTdGF0dXMgZXAlZCVzIiwKKwkJCXdJbmRleCAmIH5VU0JfRElSX0lOLAorCQkJ d0luZGV4ICYgVVNCX0RJUl9JTiA/ICJpbiIgOiAib3V0Iik7CisJCWJyZWFrOworCX0KK30KKwor c3RhdGljIGlubGluZSBjb25zdCBjaGFyICpjZG5zM19kZWNvZGVfZGV2aWNlX2ZlYXR1cmUodTE2 IHdWYWx1ZSkKK3sKKwlzd2l0Y2ggKHdWYWx1ZSkgeworCWNhc2UgVVNCX0RFVklDRV9TRUxGX1BP V0VSRUQ6CisJCXJldHVybiAiU2VsZiBQb3dlcmVkIjsKKwljYXNlIFVTQl9ERVZJQ0VfUkVNT1RF X1dBS0VVUDoKKwkJcmV0dXJuICJSZW1vdGUgV2FrZXVwIjsKKwljYXNlIFVTQl9ERVZJQ0VfVEVT VF9NT0RFOgorCQlyZXR1cm4gIlRlc3QgTW9kZSI7CisJY2FzZSBVU0JfREVWSUNFX1UxX0VOQUJM RToKKwkJcmV0dXJuICJVMSBFbmFibGUiOworCWNhc2UgVVNCX0RFVklDRV9VMl9FTkFCTEU6CisJ CXJldHVybiAiVTIgRW5hYmxlIjsKKwljYXNlIFVTQl9ERVZJQ0VfTFRNX0VOQUJMRToKKwkJcmV0 dXJuICJMVE0gRW5hYmxlIjsKKwlkZWZhdWx0OgorCQlyZXR1cm4gIlVOS05PV04iOworCX0KK30K Kworc3RhdGljIGlubGluZSBjb25zdCBjaGFyICpjZG5zM19kZWNvZGVfdGVzdF9tb2RlKHUxNiB3 SW5kZXgpCit7CisJc3dpdGNoICh3SW5kZXgpIHsKKwljYXNlIFRFU1RfSjoKKwkJcmV0dXJuICI6 IFRFU1RfSiI7CisJY2FzZSBURVNUX0s6CisJCXJldHVybiAiOiBURVNUX0siOworCWNhc2UgVEVT VF9TRTBfTkFLOgorCQlyZXR1cm4gIjogVEVTVF9TRTBfTkFLIjsKKwljYXNlIFRFU1RfUEFDS0VU OgorCQlyZXR1cm4gIjogVEVTVF9QQUNLRVQiOworCWNhc2UgVEVTVF9GT1JDRV9FTjoKKwkJcmV0 dXJuICI6IFRFU1RfRk9SQ0VfRU4iOworCWRlZmF1bHQ6CisJCXJldHVybiAiOiBVTktOT1dOIjsK Kwl9Cit9CisKK3N0YXRpYyBpbmxpbmUgdm9pZCBjZG5zM19kZWNvZGVfc2V0X2NsZWFyX2ZlYXR1 cmUodTggYlJlcXVlc3RUeXBlLCB1OCBiUmVxdWVzdCwKKwkJCQkJCSAgdTE2IHdWYWx1ZSwgdTE2 IHdJbmRleCwKKwkJCQkJCSAgY2hhciAqc3RyKQoreworCXN3aXRjaCAoYlJlcXVlc3RUeXBlICYg VVNCX1JFQ0lQX01BU0spIHsKKwljYXNlIFVTQl9SRUNJUF9ERVZJQ0U6CisJCXNwcmludGYoc3Ry LCAiJXMgRGV2aWNlIEZlYXR1cmUoJXMlcykiLAorCQkJYlJlcXVlc3QgPT0gVVNCX1JFUV9DTEVB Ul9GRUFUVVJFID8gIkNsZWFyIiA6ICJTZXQiLAorCQkJY2RuczNfZGVjb2RlX2RldmljZV9mZWF0 dXJlKHdWYWx1ZSksCisJCQl3VmFsdWUgPT0gVVNCX0RFVklDRV9URVNUX01PREUgPworCQkJY2Ru czNfZGVjb2RlX3Rlc3RfbW9kZSh3SW5kZXgpIDogIiIpOworCQlicmVhazsKKwljYXNlIFVTQl9S RUNJUF9JTlRFUkZBQ0U6CisJCXNwcmludGYoc3RyLCAiJXMgSW50ZXJmYWNlIEZlYXR1cmUoJXMp IiwKKwkJCWJSZXF1ZXN0ID09IFVTQl9SRVFfQ0xFQVJfRkVBVFVSRSA/ICJDbGVhciIgOiAiU2V0 IiwKKwkJCXdJbmRleCA9PSBVU0JfSU5UUkZfRlVOQ19TVVNQRU5EID8KKwkJCSJGdW5jdGlvbiBT dXNwZW5kIiA6ICJVTktOT1dOIik7CisJCWJyZWFrOworCWNhc2UgVVNCX1JFQ0lQX0VORFBPSU5U OgorCQlzcHJpbnRmKHN0ciwgIiVzIEVuZHBvaW50IEZlYXR1cmUoJXMgZXAlZCVzKSIsCisJCQli UmVxdWVzdCA9PSBVU0JfUkVRX0NMRUFSX0ZFQVRVUkUgPyAiQ2xlYXIiIDogIlNldCIsCisJCQkg ICAgd0luZGV4ID09IFVTQl9FTkRQT0lOVF9IQUxUID8gIkhhbHQiIDogIlVOS05PV04iLAorCQkJ d0luZGV4ICYgflVTQl9ESVJfSU4sCisJCQl3SW5kZXggJiBVU0JfRElSX0lOID8gImluIiA6ICJv dXQiKTsKKwkJYnJlYWs7CisJfQorfQorCitzdGF0aWMgaW5saW5lIGNvbnN0IGNoYXIgKmNkbnMz X2RlY29kZV9kZXNjcmlwdG9yKHUxNiB3VmFsdWUpCit7CisJc3dpdGNoICh3VmFsdWUgPj4gOCkg eworCWNhc2UgVVNCX0RUX0RFVklDRToKKwkJcmV0dXJuICJEZXZpY2UiOworCWNhc2UgVVNCX0RU X0NPTkZJRzoKKwkJcmV0dXJuICJDb25maWd1cmF0aW9uIjsKKwljYXNlIFVTQl9EVF9TVFJJTkc6 CisJCXJldHVybiAiU3RyaW5nIjsKKwljYXNlIFVTQl9EVF9JTlRFUkZBQ0U6CisJCXJldHVybiAi SW50ZXJmYWNlIjsKKwljYXNlIFVTQl9EVF9FTkRQT0lOVDoKKwkJcmV0dXJuICJFbmRwb2ludCI7 CisJY2FzZSBVU0JfRFRfREVWSUNFX1FVQUxJRklFUjoKKwkJcmV0dXJuICJEZXZpY2UgUXVhbGlm aWVyIjsKKwljYXNlIFVTQl9EVF9PVEhFUl9TUEVFRF9DT05GSUc6CisJCXJldHVybiAiT3RoZXIg U3BlZWQgQ29uZmlnIjsKKwljYXNlIFVTQl9EVF9JTlRFUkZBQ0VfUE9XRVI6CisJCXJldHVybiAi SW50ZXJmYWNlIFBvd2VyIjsKKwljYXNlIFVTQl9EVF9PVEc6CisJCXJldHVybiAiT1RHIjsKKwlj YXNlIFVTQl9EVF9ERUJVRzoKKwkJcmV0dXJuICJEZWJ1ZyI7CisJY2FzZSBVU0JfRFRfSU5URVJG QUNFX0FTU09DSUFUSU9OOgorCQlyZXR1cm4gIkludGVyZmFjZSBBc3NvY2lhdGlvbiI7CisJY2Fz ZSBVU0JfRFRfQk9TOgorCQlyZXR1cm4gIkJPUyI7CisJY2FzZSBVU0JfRFRfREVWSUNFX0NBUEFC SUxJVFk6CisJCXJldHVybiAiRGV2aWNlIENhcGFiaWxpdHkiOworCWNhc2UgVVNCX0RUX1NTX0VO RFBPSU5UX0NPTVA6CisJCXJldHVybiAiU1MgRW5kcG9pbnQgQ29tcGFuaW9uIjsKKwljYXNlIFVT Ql9EVF9TU1BfSVNPQ19FTkRQT0lOVF9DT01QOgorCQlyZXR1cm4gIlNTUCBJc29jaHJvbm91cyBF bmRwb2ludCBDb21wYW5pb24iOworCWRlZmF1bHQ6CisJCXJldHVybiAiVU5LTk9XTiI7CisJfQor fQorCisvKioKKyAqIGNkbnMzX2RlY29kZV9jdHJsIC0gcmV0dXJucyBhIHN0cmluZyByZXByZXNl dGlvbiBvZiBjdHJsIHJlcXVlc3QKKyAqLworc3RhdGljIGlubGluZSBjb25zdCBjaGFyICpjZG5z M19kZWNvZGVfY3RybChjaGFyICpzdHIsIHU4IGJSZXF1ZXN0VHlwZSwKKwkJCQkJICAgIHU4IGJS ZXF1ZXN0LCB1MTYgd1ZhbHVlLAorCQkJCQkgICAgdTE2IHdJbmRleCwgdTE2IHdMZW5ndGgpCit7 CisJc3dpdGNoIChiUmVxdWVzdCkgeworCWNhc2UgVVNCX1JFUV9HRVRfU1RBVFVTOgorCQljZG5z M19kZWNvZGVfZ2V0X3N0YXR1cyhiUmVxdWVzdFR5cGUsIHdJbmRleCwKKwkJCQkJd0xlbmd0aCwg c3RyKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX0NMRUFSX0ZFQVRVUkU6CisJY2FzZSBVU0Jf UkVRX1NFVF9GRUFUVVJFOgorCQljZG5zM19kZWNvZGVfc2V0X2NsZWFyX2ZlYXR1cmUoYlJlcXVl c3RUeXBlLCBiUmVxdWVzdCwKKwkJCQkJICAgICAgIHdWYWx1ZSwgd0luZGV4LCBzdHIpOworCQli cmVhazsKKwljYXNlIFVTQl9SRVFfU0VUX0FERFJFU1M6CisJCXNwcmludGYoc3RyLCAiU2V0IEFk ZHJlc3MgQWRkcjogJTAyeCIsIHdWYWx1ZSk7CisJCWJyZWFrOworCWNhc2UgVVNCX1JFUV9HRVRf REVTQ1JJUFRPUjoKKwkJc3ByaW50ZihzdHIsICJHRVQgJXMgRGVzY3JpcHRvciBJOiAlZCwgTDog JWQiLAorCQkJY2RuczNfZGVjb2RlX2Rlc2NyaXB0b3Iod1ZhbHVlKSwKKwkJCXdWYWx1ZSAmIDB4 ZmYsIHdMZW5ndGgpOworCQlicmVhazsKKwljYXNlIFVTQl9SRVFfU0VUX0RFU0NSSVBUT1I6CisJ CXNwcmludGYoc3RyLCAiU0VUICVzIERlc2NyaXB0b3IgSTogJWQsIEw6ICVkIiwKKwkJCWNkbnMz X2RlY29kZV9kZXNjcmlwdG9yKHdWYWx1ZSksCisJCQl3VmFsdWUgJiAweGZmLCB3TGVuZ3RoKTsK KwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX0dFVF9DT05GSUdVUkFUSU9OOgorCQlzcHJpbnRmKHN0 ciwgIkdldCBDb25maWd1cmF0aW9uIEw6ICVkIiwgd0xlbmd0aCk7CisJCWJyZWFrOworCWNhc2Ug VVNCX1JFUV9TRVRfQ09ORklHVVJBVElPTjoKKwkJc3ByaW50ZihzdHIsICJTZXQgQ29uZmlndXJh dGlvbiBDb25maWc6ICVkICIsIHdWYWx1ZSk7CisJCWJyZWFrOworCWNhc2UgVVNCX1JFUV9HRVRf SU5URVJGQUNFOgorCQlzcHJpbnRmKHN0ciwgIkdldCBJbnRlcmZhY2UgSW50ZjogJWQsIEw6ICVk Iiwgd0luZGV4LCB3TGVuZ3RoKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX1NFVF9JTlRFUkZB Q0U6CisJCXNwcmludGYoc3RyLCAiU2V0IEludGVyZmFjZSBJbnRmOiAlZCwgQWx0OiAlZCIsIHdJ bmRleCwgd1ZhbHVlKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX1NZTkNIX0ZSQU1FOgorCQlz cHJpbnRmKHN0ciwgIlN5bmNoIEZyYW1lIEVwOiAlZCwgTDogJWQiLCB3SW5kZXgsIHdMZW5ndGgp OworCQlicmVhazsKKwljYXNlIFVTQl9SRVFfU0VUX1NFTDoKKwkJc3ByaW50ZihzdHIsICJTZXQg U0VMIEw6ICVkIiwgd0xlbmd0aCk7CisJCWJyZWFrOworCWNhc2UgVVNCX1JFUV9TRVRfSVNPQ0hf REVMQVk6CisJCXNwcmludGYoc3RyLCAiU2V0IElzb2Nocm9ub3VzIERlbGF5IERlbGF5OiAlZCBu cyIsIHdWYWx1ZSk7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXNwcmludGYoc3RyLAorCQkJIlNF VFVQIEJSVDogJTAyeCBCUjogJTAyeCBWOiAlMDR4IEk6ICUwNHggTDogJTA0eFxuIiwKKwkJCWJS ZXF1ZXN0VHlwZSwgYlJlcXVlc3QsCisJCQl3VmFsdWUsIHdJbmRleCwgd0xlbmd0aCk7CisJfQor CisJcmV0dXJuIHN0cjsKK30KKworc3RhdGljIGlubGluZSBjaGFyICpjZG5zM19kZWNvZGVfdXNi X2lycShzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiwKKwkJCQkJIHUzMiB1c2JfaXN0cykK K3sKKwlzdGF0aWMgY2hhciBzdHJbMjU2XTsKKwlpbnQgcmV0OworCisJcmV0ID0gc3ByaW50Zihz dHIsICJJUlEgJTA4eCA9ICIsIHVzYl9pc3RzKTsKKworCWlmICh1c2JfaXN0cyAmIChVU0JfSVNU U19DT04ySSB8IFVTQl9JU1RTX0NPTkkpKSB7CisJCXUzMiBzcGVlZCA9IGNkbnMzX2dldF9zcGVl ZChwcml2X2Rldik7CisKKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiQ29ubmVjdGlvbiAl c1xuIiwKKwkJCSAgICAgICB1c2Jfc3BlZWRfc3RyaW5nKHNwZWVkKSk7CisJfQorCWlmICh1c2Jf aXN0cyAmIFVTQl9JU1RTX0NPTjJJIHx8IHVzYl9pc3RzICYgVVNCX0lTVFNfQ09OSSkKKwkJcmV0 ICs9IHNwcmludGYoc3RyICsgcmV0LCAiRGlzY29ubmVjdGlvbiAiKTsKKwlpZiAodXNiX2lzdHMg JiBVU0JfSVNUU19MMkVOVEkpCisJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgInN1c3BlbmRl ZCAiKTsKKworCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RTX0wyRVhUSSkKKwkJcmV0ICs9IHNwcmlu dGYoc3RyICsgcmV0LCAiTDIgZXhpdCAiKTsKKwlpZiAodXNiX2lzdHMgJiBVU0JfSVNUU19VM0VY VEkpCisJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgIlUzIGV4aXQgIik7CisJaWYgKHVzYl9p c3RzICYgVVNCX0lTVFNfVVdSRVNJKQorCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJXYXJt IFJlc2V0ICIpOworCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RTX1VIUkVTSSkKKwkJcmV0ICs9IHNw cmludGYoc3RyICsgcmV0LCAiSG90IFJlc2V0ICIpOworCWlmICh1c2JfaXN0cyAmIFVTQl9JU1RT X1UyUkVTSSkKKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiUmVzZXQiKTsKKworCXJldHVy biBzdHI7Cit9CisKK3N0YXRpYyBpbmxpbmUgIGNoYXIgKmNkbnMzX2RlY29kZV9lcF9pcnEodTMy IGVwX3N0cywgY29uc3QgY2hhciAqZXBfbmFtZSkKK3sKKwlzdGF0aWMgY2hhciBzdHJbMjU2XTsK KwlpbnQgcmV0OworCisJcmV0ID0gc3ByaW50ZihzdHIsICJJUlEgZm9yICVzOiAlMDh4ICIsIGVw X25hbWUsIGVwX3N0cyk7CisKKwlpZiAoZXBfc3RzICYgRVBfU1RTX1NFVFVQKQorCQlyZXQgKz0g c3ByaW50ZihzdHIgKyByZXQsICJTRVRVUCAiKTsKKwlpZiAoZXBfc3RzICYgRVBfU1RTX0lPQykK KwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiSU9DICIpOworCWlmIChlcF9zdHMgJiBFUF9T VFNfSVNQKQorCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJJU1AgIik7CisJaWYgKGVwX3N0 cyAmIEVQX1NUU19ERVNDTUlTKQorCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQsICJERVNDTUlT ICIpOworCWlmIChlcF9zdHMgJiBFUF9TVFNfU1RSRUFNUikKKwkJcmV0ICs9IHNwcmludGYoc3Ry ICsgcmV0LCAiU1RSRUFNUiAiKTsKKwlpZiAoZXBfc3RzICYgRVBfU1RTX01EX0VYSVQpCisJCXJl dCArPSBzcHJpbnRmKHN0ciArIHJldCwgIk1EX0VYSVQgIik7CisJaWYgKGVwX3N0cyAmIEVQX1NU U19UUkJFUlIpCisJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgIlRSQkVSUiAiKTsKKwlpZiAo ZXBfc3RzICYgRVBfU1RTX05SRFkpCisJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgIk5SRFkg Iik7CisJaWYgKGVwX3N0cyAmIEVQX1NUU19QUklNRSkKKwkJcmV0ICs9IHNwcmludGYoc3RyICsg cmV0LCAiUFJJTUUgIik7CisJaWYgKGVwX3N0cyAmIEVQX1NUU19TSURFUlIpCisJCXJldCArPSBz cHJpbnRmKHN0ciArIHJldCwgIlNJREVSUlQgIik7CisJaWYgKGVwX3N0cyAmIEVQX1NUU19PVVRT TU0pCisJCXJldCArPSBzcHJpbnRmKHN0ciArIHJldCwgIk9VVFNNTSAiKTsKKwlpZiAoZXBfc3Rz ICYgRVBfU1RTX0lTT0VSUikKKwkJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LCAiSVNPRVJSICIp OworCWlmIChlcF9zdHMgJiBFUF9TVFNfSU9UKQorCQlyZXQgKz0gc3ByaW50ZihzdHIgKyByZXQs ICJJT1QgIik7CisKKwlyZXR1cm4gc3RyOworfQorCitzdGF0aWMgaW5saW5lIGNoYXIgKmNkbnMz X2RlY29kZV9lcHhfaXJxKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCkKK3sKKwlzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKworCXJldHVy biBjZG5zM19kZWNvZGVfZXBfaXJxKHJlYWRsKCZwcml2X2Rldi0+cmVncy0+ZXBfc3RzKSwKKwkJ CQkgICBwcml2X2VwLT5uYW1lKTsKK30KKworc3RhdGljIGlubGluZSBjaGFyICpjZG5zM19kZWNv ZGVfZXAwX2lycShzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldikKK3sKKwlpZiAocHJpdl9k ZXYtPmVwMF9kYXRhX2RpcikKKwkJcmV0dXJuIGNkbnMzX2RlY29kZV9lcF9pcnEocmVhZGwoJnBy aXZfZGV2LT5yZWdzLT5lcF9zdHMpLAorCQkJCQkgICAiZXAwSU4iKTsKKwllbHNlCisJCXJldHVy biBjZG5zM19kZWNvZGVfZXBfaXJxKHJlYWRsKCZwcml2X2Rldi0+cmVncy0+ZXBfc3RzKSwKKwkJ CQkJICAgImVwME9VVCIpOworfQorCisvKioKKyAqIERlYnVnIGEgdHJhbnNmZXIgcmluZy4KKyAq CisgKiBQcmludHMgb3V0IGFsbCBUUkJzIGluIHRoZSBlbmRwb2ludCByaW5nLCBldmVuIHRob3Nl IGFmdGVyIHRoZSBMaW5rIFRSQi4KKyAqLgorICovCitzdGF0aWMgaW5saW5lIGNoYXIgKmNkbnMz X2RiZ19yaW5nKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCwKKwkJCQkgICBpbnQgZnJl ZV90cmJzLCB1OCBwY3MsIHU4IGNjcywKKwkJCQkgICBpbnQgZW5xdWV1ZSwgaW50IGRlcXVldWUs CisJCQkJICAgc3RydWN0IGNkbnMzX3RyYiAqcmluZywgY2hhciAqc3RyKQoreworCXU2NCBhZGRy ID0gcHJpdl9lcC0+dHJiX3Bvb2xfZG1hOworCXN0cnVjdCBjZG5zM190cmIgKnRyYjsKKwlpbnQg cmV0ID0gMDsKKwlpbnQgaTsKKworCXRyYiA9ICZyaW5nW3ByaXZfZXAtPmRlcXVldWVdOworCXJl dCArPSBzcHJpbnRmKHN0ciArIHJldCwgIlxuXHRcdFJpbmcgY29udGVudHMgZm9yICVzOiIsIHBy aXZfZXAtPm5hbWUpOworCisJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LAorCQkgICAgICAgIlxu XHRcdFJpbmcgZGVxIGluZGV4OiAlZCwgdHJiOiAlcCAodmlydCksIDB4JWxseCAoZG1hKVxuIiwK KwkJICAgICAgIGRlcXVldWUsIHRyYiwKKwkJICAgICAgICh1bnNpZ25lZCBsb25nIGxvbmcpY2Ru czNfdHJiX3ZpcnRfdG9fZG1hKHByaXZfZXAsIHRyYikpOworCisJdHJiID0gJnJpbmdbcHJpdl9l cC0+ZW5xdWV1ZV07CisJcmV0ICs9IHNwcmludGYoc3RyICsgcmV0LAorCQkgICAgICAgIlx0XHRS aW5nIGVucSBpbmRleDogJWQsIHRyYjogJXAgKHZpcnQpLCAweCVsbHggKGRtYSlcbiIsCisJCSAg ICAgICBlbnF1ZXVlLCB0cmIsCisJCSAgICAgICAodW5zaWduZWQgbG9uZyBsb25nKWNkbnMzX3Ry Yl92aXJ0X3RvX2RtYShwcml2X2VwLCB0cmIpKTsKKworCXJldCArPSBzcHJpbnRmKHN0ciArIHJl dCwKKwkJICAgICAgICJcdFx0ZnJlZSB0cmJzOiAlZCwgQ0NTPSVkLCBQQ1M9JWRcbiIsIGZyZWVf dHJicywgY2NzLAorCQkgICAgICAgcGNzKTsKKworCWlmIChUUkJTX1BFUl9TRUdNRU5UID4gNjQp IHsKKwkJc3ByaW50ZihzdHIgKyByZXQsICJcdFx0VG8gYmlnIHRyYW5zZmVyIHJpbmcgJWRcbiIs CisJCQlUUkJTX1BFUl9TRUdNRU5UKTsKKwkJcmV0dXJuIHN0cjsKKwl9CisKKwlmb3IgKGkgPSAw OyBpIDwgVFJCU19QRVJfU0VHTUVOVDsgKytpKSB7CisJCXRyYiA9ICZyaW5nW2ldOworCQlyZXQg Kz0gc3ByaW50ZihzdHIgKyByZXQsCisJCQkiXHRcdEAlMDE2bGx4ICUwOHggJTA4eCAlMDh4XG4i LCBhZGRyLAorCQkJbGUzMl90b19jcHUodHJiLT5idWZmZXIpLAorCQkJbGUzMl90b19jcHUodHJi LT5sZW5ndGgpLAorCQkJbGUzMl90b19jcHUodHJiLT5jb250cm9sKSk7CisJCWFkZHIgKz0gc2l6 ZW9mKCp0cmIpOworCX0KKworCXJldHVybiBzdHI7Cit9CisKKyNpZmRlZiBDT05GSUdfREVCVUdf RlMKK3ZvaWQgY2RuczNfZGVidWdmc19pbml0KHN0cnVjdCBjZG5zMyAqY2Rucyk7Cit2b2lkIGNk bnMzX2RlYnVnZnNfZXhpdChzdHJ1Y3QgY2RuczMgKmNkbnMpOworI2Vsc2UKK3ZvaWQgY2RuczNf ZGVidWdmc19pbml0KHN0cnVjdCBjZG5zMyAqY2Rucyk7Cit7ICB9Cit2b2lkIGNkbnMzX2RlYnVn ZnNfZXhpdChzdHJ1Y3QgY2RuczMgKmNkbnMpOworeyAgfQorI2VuZGlmCisKKyNlbmRpZiAvKl9f TElOVVhfQ0ROUzNfREVCVUcqLwpkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvY2RuczMvZGVidWdm cy5jIGIvZHJpdmVycy91c2IvY2RuczMvZGVidWdmcy5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0Cmlu ZGV4IDAwMDAwMDAwMDAwMC4uZDc5MTlmNWMxZDkwCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVy cy91c2IvY2RuczMvZGVidWdmcy5jCkBAIC0wLDAgKzEsMTY4IEBACisvLyBTUERYLUxpY2Vuc2Ut SWRlbnRpZmllcjogR1BMLTIuMAorLyoKKyAqIENhZGVuY2UgVVNCU1MgRFJEIENvbnRyb2xsZXIg RGVidWdGUyBmaWxlci4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5jZS4KKyAqCisg KiBBdXRob3I6IFBhd2VsIExhc3pjemFrIDxwYXdlbGxAY2FkZW5jZS5jb20+CisgKi8KKworI2lu Y2x1ZGUgPGxpbnV4L3R5cGVzLmg+CisjaW5jbHVkZSA8bGludXgvZGVidWdmcy5oPgorI2luY2x1 ZGUgPGxpbnV4L3NlcV9maWxlLmg+CisjaW5jbHVkZSA8bGludXgvdWFjY2Vzcy5oPgorCisjaW5j bHVkZSAiY29yZS5oIgorI2luY2x1ZGUgImdhZGdldC5oIgorI2luY2x1ZGUgImRyZC5oIgorCitz dGF0aWMgaW50IGNkbnMzX21vZGVfc2hvdyhzdHJ1Y3Qgc2VxX2ZpbGUgKnMsIHZvaWQgKnVudXNl ZCkKK3sKKwlzdHJ1Y3QgY2RuczMgKmNkbnMgPSBzLT5wcml2YXRlOworCisJc3dpdGNoIChjZG5z LT5jdXJyZW50X2RyX21vZGUpIHsKKwljYXNlIFVTQl9EUl9NT0RFX0hPU1Q6CisJCXNlcV9wdXRz KHMsICJob3N0XG4iKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMOgor CQlzZXFfcHV0cyhzLCAiZGV2aWNlXG4iKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfRFJfTU9ERV9P VEc6CisJCXNlcV9wdXRzKHMsICJvdGdcbiIpOworCQlicmVhazsKKwlkZWZhdWx0OgorCQlzZXFf cHV0cyhzLCAiVU5LTk9XTiBtb2RlXG4iKTsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGludCBjZG5zM19tb2RlX29wZW4oc3RydWN0IGlub2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZp bGUpCit7CisJcmV0dXJuIHNpbmdsZV9vcGVuKGZpbGUsIGNkbnMzX21vZGVfc2hvdywgaW5vZGUt PmlfcHJpdmF0ZSk7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGNkbnMzX21vZGVfd3JpdGUoc3RydWN0 IGZpbGUgKmZpbGUsCisJCQkJY29uc3QgY2hhciBfX3VzZXIgKnVidWYsCisJCQkJc2l6ZV90IGNv dW50LCBsb2ZmX3QgKnBwb3MpCit7CisJc3RydWN0IHNlcV9maWxlCSAqcyA9IGZpbGUtPnByaXZh dGVfZGF0YTsKKwlzdHJ1Y3QgY2RuczMgKmNkbnMgPSBzLT5wcml2YXRlOworCXUzMiBtb2RlID0g VVNCX0RSX01PREVfVU5LTk9XTjsKKwljaGFyIGJ1ZlszMl07CisKKwlpZiAoY29weV9mcm9tX3Vz ZXIoJmJ1ZiwgdWJ1ZiwgbWluX3Qoc2l6ZV90LCBzaXplb2YoYnVmKSAtIDEsIGNvdW50KSkpCisJ CXJldHVybiAtRUZBVUxUOworCisJaWYgKCFzdHJuY21wKGJ1ZiwgImhvc3QiLCA0KSkgeworCQlp ZiAoY2Rucy0+ZHJfbW9kZSA9PSBVU0JfRFJfTU9ERV9IT1NUIHx8CisJCSAgICBjZG5zLT5kcl9t b2RlID09IFVTQl9EUl9NT0RFX09URykgeworCQkJbW9kZSA9IFVTQl9EUl9NT0RFX0hPU1Q7CisJ CX0KKwl9CisKKwlpZiAoIXN0cm5jbXAoYnVmLCAiZGV2aWNlIiwgNikpCisJCWlmIChjZG5zLT5k cl9tb2RlID09IFVTQl9EUl9NT0RFX1BFUklQSEVSQUwgfHwKKwkJICAgIGNkbnMtPmRyX21vZGUg PT0gVVNCX0RSX01PREVfT1RHKQorCQkJbW9kZSA9IFVTQl9EUl9NT0RFX1BFUklQSEVSQUw7CisK KwlpZiAoIXN0cm5jbXAoYnVmLCAib3RnIiwgMykgJiYgY2Rucy0+ZHJfbW9kZSA9PSBVU0JfRFJf TU9ERV9PVEcpCisJCW1vZGUgPSBVU0JfRFJfTU9ERV9PVEc7CisKKwlpZiAobW9kZSA9PSBVU0Jf RFJfTU9ERV9VTktOT1dOKSB7CisJCWRldl9lcnIoY2Rucy0+ZGV2LCAiRmFpbGVkOiBpbmNvcnJl Y3QgbW9kZSBzZXR0aW5nXG4iKTsKKwkJcmV0dXJuIC1FRkFVTFQ7CisJfQorCisJaWYgKGNkbnMt PmN1cnJlbnRfZHJfbW9kZSAhPSBtb2RlKSB7CisJCWNkbnMtPmRlc2lyZWRfZHJfbW9kZSA9IG1v ZGU7CisJCWNkbnMtPmRlYnVnX2Rpc2FibGUgPSAwOworCQljZG5zM19yb2xlX3N0b3AoY2Rucyk7 CisJCWNkbnMzX2RyZF91cGRhdGVfbW9kZShjZG5zKTsKKwkJcXVldWVfd29yayhzeXN0ZW1fZnJl ZXphYmxlX3dxLCAmY2Rucy0+cm9sZV9zd2l0Y2hfd3EpOworCX0KKworCXJldHVybiBjb3VudDsK K30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBmaWxlX29wZXJhdGlvbnMgY2RuczNfbW9kZV9mb3Bz ID0geworCS5vcGVuCQkJPSBjZG5zM19tb2RlX29wZW4sCisJLndyaXRlCQkJPSBjZG5zM19tb2Rl X3dyaXRlLAorCS5yZWFkCQkJPSBzZXFfcmVhZCwKKwkubGxzZWVrCQkJPSBzZXFfbHNlZWssCisJ LnJlbGVhc2UJCT0gc2luZ2xlX3JlbGVhc2UsCit9OworCitzdGF0aWMgaW50IGNkbnMzX2Rpc2Fi bGVfc2hvdyhzdHJ1Y3Qgc2VxX2ZpbGUgKnMsIHZvaWQgKnVudXNlZCkKK3sKKwlzdHJ1Y3QgY2Ru czMgKmNkbnMgPSBzLT5wcml2YXRlOworCisJaWYgKCFjZG5zLT5kZWJ1Z19kaXNhYmxlKQorCQlz ZXFfcHV0cyhzLCAiMFxuIik7CisJZWxzZQorCQlzZXFfcHV0cyhzLCAiMVxuIik7CisKKwlyZXR1 cm4gMDsKK30KKworc3RhdGljIHNzaXplX3QgY2RuczNfZGlzYWJsZV93cml0ZShzdHJ1Y3QgZmls ZSAqZmlsZSwKKwkJCQkgICBjb25zdCBjaGFyIF9fdXNlciAqdWJ1ZiwKKwkJCQkgICBzaXplX3Qg Y291bnQsIGxvZmZfdCAqcHBvcykKK3sKKwlzdHJ1Y3Qgc2VxX2ZpbGUJICpzID0gZmlsZS0+cHJp dmF0ZV9kYXRhOworCXN0cnVjdCBjZG5zMyAqY2RucyA9IHMtPnByaXZhdGU7CisJaW50IGRpc2Fi bGU7CisJY2hhciBidWZbMzJdOworCisJaWYgKGNvcHlfZnJvbV91c2VyKCZidWYsIHVidWYsIG1p bl90KHNpemVfdCwgc2l6ZW9mKGJ1ZikgLSAxLCBjb3VudCkpKQorCQlyZXR1cm4gLUVGQVVMVDsK KworCWlmICghc3RybmNtcChidWYsICIxIiwgMSkgfHwgIXN0cm5jbXAoYnVmLCAieWVzIiwgMykp IHsKKwkJZGlzYWJsZSA9IDE7CisJfSBlbHNlIGlmICghc3RybmNtcChidWYsICIwIiwgMSkgfHwg IXN0cm5jbXAoYnVmLCAibm8iLCAyKSkgeworCQlkaXNhYmxlID0gMDsKKwl9IGVsc2UgeworCQlk ZXZfZXJyKGNkbnMtPmRldiwgIkZhaWxlZDogaW5jb3JyZWN0IGRpc2FibGUgc2V0dGluZ1xuIik7 CisJCXJldHVybiAtRUZBVUxUOworCX0KKworCWlmIChkaXNhYmxlICE9IGNkbnMtPmRlYnVnX2Rp c2FibGUpIHsKKwkJY2Rucy0+ZGVidWdfZGlzYWJsZSA9IGRpc2FibGU7CisJCXF1ZXVlX3dvcmso c3lzdGVtX2ZyZWV6YWJsZV93cSwgJmNkbnMtPnJvbGVfc3dpdGNoX3dxKTsKKwl9CisKKwlyZXR1 cm4gY291bnQ7Cit9CisKK3N0YXRpYyBpbnQgY2RuczNfZGlzYWJsZV9vcGVuKHN0cnVjdCBpbm9k ZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpmaWxlKQoreworCXJldHVybiBzaW5nbGVfb3BlbihmaWxl LCBjZG5zM19kaXNhYmxlX3Nob3csIGlub2RlLT5pX3ByaXZhdGUpOworfQorCitzdGF0aWMgY29u c3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9ucyBjZG5zM19kaXNhYmxlX2ZvcHMgPSB7CisJLm9wZW4J CQk9IGNkbnMzX2Rpc2FibGVfb3BlbiwKKwkud3JpdGUJCQk9IGNkbnMzX2Rpc2FibGVfd3JpdGUs CisJLnJlYWQJCQk9IHNlcV9yZWFkLAorCS5sbHNlZWsJCQk9IHNlcV9sc2VlaywKKwkucmVsZWFz ZQkJPSBzaW5nbGVfcmVsZWFzZSwKK307CisKK3ZvaWQgY2RuczNfZGVidWdmc19pbml0KHN0cnVj dCBjZG5zMyAqY2RucykKK3sKKwlzdHJ1Y3QgZGVudHJ5ICpyb290OworCisJcm9vdCA9IGRlYnVn ZnNfY3JlYXRlX2RpcihkZXZfbmFtZShjZG5zLT5kZXYpLCBOVUxMKTsKKwljZG5zLT5yb290ID0g cm9vdDsKKwlpZiAoSVNfRU5BQkxFRChDT05GSUdfVVNCX0NETlMzX0dBREdFVCkgJiYKKwkgICAg SVNfRU5BQkxFRChDT05GSUdfVVNCX0NETlMzX0hPU1QpKQorCQlkZWJ1Z2ZzX2NyZWF0ZV9maWxl KCJtb2RlIiwgMDY0NCwgcm9vdCwgY2RucywKKwkJCQkgICAgJmNkbnMzX21vZGVfZm9wcyk7CisK KwlkZWJ1Z2ZzX2NyZWF0ZV9maWxlKCJkaXNhYmxlIiwgMDY0NCwgcm9vdCwgY2RucywKKwkJCSAg ICAmY2RuczNfZGlzYWJsZV9mb3BzKTsKK30KKwordm9pZCBjZG5zM19kZWJ1Z2ZzX2V4aXQoc3Ry dWN0IGNkbnMzICpjZG5zKQoreworCWRlYnVnZnNfcmVtb3ZlX3JlY3Vyc2l2ZShjZG5zLT5yb290 KTsKK30KZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL2RyZC5jIGIvZHJpdmVycy91c2Iv Y2RuczMvZHJkLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi40NTU3 MzQyN2JhODMKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9kcmQuYwpAQCAt MCwwICsxLDMxNSBAQAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKy8qCisg KiBDYWRlbmNlIFVTQlNTIERSRCBEcml2ZXIuCisgKgorICogQ29weXJpZ2h0IChDKSAyMDE4IENh ZGVuY2UuCisgKgorICogQXV0aG9yOiBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29t CisgKgorICovCisjaW5jbHVkZSA8bGludXgva2VybmVsLmg+CisjaW5jbHVkZSA8bGludXgvaW50 ZXJydXB0Lmg+CisjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4KKyNpbmNsdWRlIDxsaW51eC91c2Iv b3RnLmg+CisKKyNpbmNsdWRlICJnYWRnZXQuaCIKKyNpbmNsdWRlICJkcmQuaCIKKyNpbmNsdWRl ICJjb3JlLmgiCisKK3N0YXRpYyBpbnQgY2RuczNfZHJkX3N3aXRjaF9nYWRnZXQoc3RydWN0IGNk bnMzICpjZG5zLCBpbnQgb24pOworc3RhdGljIGludCBjZG5zM19kcmRfc3dpdGNoX2hvc3Qoc3Ry dWN0IGNkbnMzICpjZG5zLCBpbnQgb24pOworCisvKioKKyAqIGNkbnMzX3NldF9tb2RlIC0gY2hh bmdlIG1vZGUgb2YgT1RHIENvcmUKKyAqIEBjZG5zOiBwb2ludGVyIHRvIGNvbnRleHQgc3RydWN0 dXJlCisgKiBAbW9kZTogc2VsZWN0ZWQgbW9kZSBmcm9tIGNkbnNfcm9sZQorICovCit2b2lkIGNk bnMzX3NldF9tb2RlKHN0cnVjdCBjZG5zMyAqY2RucywgZW51bSB1c2JfZHJfbW9kZSBtb2RlKQor eworCXUzMiByZWc7CisKKwljZG5zLT5jdXJyZW50X2RyX21vZGUgPSBtb2RlOworCisJc3dpdGNo IChtb2RlKSB7CisJY2FzZSBVU0JfRFJfTU9ERV9QRVJJUEhFUkFMOgorCQlkZXZfaW5mbyhjZG5z LT5kZXYsICJTZXQgY29udHJvbGxlciB0byBHYWRnZXQgbW9kZVxuIik7CisJCWNkbnMzX2RyZF9z d2l0Y2hfZ2FkZ2V0KGNkbnMsIDEpOworCQlicmVhazsKKwljYXNlIFVTQl9EUl9NT0RFX0hPU1Q6 CisJCWRldl9pbmZvKGNkbnMtPmRldiwgIlNldCBjb250cm9sbGVyIHRvIEhvc3QgbW9kZVxuIik7 CisJCWNkbnMzX2RyZF9zd2l0Y2hfaG9zdChjZG5zLCAxKTsKKwkJYnJlYWs7CisJY2FzZSBVU0Jf RFJfTU9ERV9PVEc6CisJCWRldl9pbmZvKGNkbnMtPmRldiwgIlNldCBjb250cm9sbGVyIHRvIE9U RyBtb2RlXG4iKTsKKwkJcmVnID0gcmVhZGwoJmNkbnMtPm90Z19yZWdzLT5vdmVycmlkZSk7CisJ CXJlZyB8PSBPVkVSUklERV9JRFBVTExVUDsKKwkJd3JpdGVsKHJlZywgJmNkbnMtPm90Z19yZWdz LT5vdmVycmlkZSk7CisKKwkJLyoKKwkJICogSGFyZHdhcmUgc3BlY2lmaWNhdGlvbiBzYXlzOiAi SURfVkFMVUUgbXVzdCBiZSB2YWxpZCB3aXRoaW4KKwkJICogNTBtcyBhZnRlciBpZHB1bGx1cCBp cyBzZXQgdG8gJzEiIHNvIGRyaXZlciBtdXN0IHdhaXQKKwkJICogNTBtcyBiZWZvcmUgcmVhZGlu ZyB0aGlzIHBpbi4KKwkJICovCisJCXVzbGVlcF9yYW5nZSg1MDAwMCwgNjAwMDApOworCQlicmVh azsKKwlkZWZhdWx0OgorCQljZG5zLT5jdXJyZW50X2RyX21vZGUgPSBVU0JfRFJfTU9ERV9VTktO T1dOOworCQlkZXZfZXJyKGNkbnMtPmRldiwgIlVuc3VwcG9ydGVkIG1vZGUgb2Ygb3BlcmF0aW9u ICVkXG4iLCBtb2RlKTsKKwkJcmV0dXJuOworCX0KK30KKworaW50IGNkbnMzX2dldF9pZChzdHJ1 Y3QgY2RuczMgKmNkbnMpCit7CisJaW50IGlkOworCisJaWQgPSByZWFkbCgmY2Rucy0+b3RnX3Jl Z3MtPnN0cykgJiBPVEdTVFNfSURfVkFMVUU7CisJZGV2X2RiZyhjZG5zLT5kZXYsICJPVEcgSUQ6 ICVkIiwgaWQpOworCXJldHVybiAgaWQ7Cit9CisKK2ludCBjZG5zM19pc19ob3N0KHN0cnVjdCBj ZG5zMyAqY2RucykKK3sKKwlpZiAoY2Rucy0+Y3VycmVudF9kcl9tb2RlID09IFVTQl9EUl9NT0RF X0hPU1QpCisJCXJldHVybiAxOworCWVsc2UgaWYgKCFjZG5zM19nZXRfaWQoY2RucykpCisJCXJl dHVybiAxOworCisJcmV0dXJuIDA7Cit9CisKK2ludCBjZG5zM19pc19kZXZpY2Uoc3RydWN0IGNk bnMzICpjZG5zKQoreworCWlmIChjZG5zLT5jdXJyZW50X2RyX21vZGUgPT0gVVNCX0RSX01PREVf UEVSSVBIRVJBTCkKKwkJcmV0dXJuIDE7CisJZWxzZSBpZiAoY2Rucy0+Y3VycmVudF9kcl9tb2Rl ID09IFVTQl9EUl9NT0RFX09URykKKwkJaWYgKGNkbnMzX2dldF9pZChjZG5zKSkKKwkJCXJldHVy biAxOworCisJcmV0dXJuIDA7Cit9CisKKy8qKgorICogY2RuczNfb3RnX2Rpc2FibGVfaXJxIC0g RGlzYWJsZSBhbGwgT1RHIGludGVycnVwdHMKKyAqIEBjZG5zOiBQb2ludGVyIHRvIGNvbnRyb2xs ZXIgY29udGV4dCBzdHJ1Y3R1cmUKKyAqLworc3RhdGljIHZvaWQgY2RuczNfb3RnX2Rpc2FibGVf aXJxKHN0cnVjdCBjZG5zMyAqY2RucykKK3sKKwl3cml0ZWwoMCwgJmNkbnMtPm90Z19yZWdzLT5p ZW4pOworfQorCisvKioKKyAqIGNkbnMzX290Z19lbmFibGVfaXJxIC0gZW5hYmxlIGlkIGFuZCBz ZXNzX3ZhbGlkIGludGVycnVwdHMKKyAqIEBjZG5zOiBQb2ludGVyIHRvIGNvbnRyb2xsZXIgY29u dGV4dCBzdHJ1Y3R1cmUKKyAqLworc3RhdGljIHZvaWQgY2RuczNfb3RnX2VuYWJsZV9pcnEoc3Ry dWN0IGNkbnMzICpjZG5zKQoreworCXdyaXRlbChPVEdJRU5fSURfQ0hBTkdFX0lOVCB8IE9UR0lF Tl9WQlVTVkFMSURfUklTRV9JTlQgfAorCSAgICAgICBPVEdJRU5fVkJVU1ZBTElEX0ZBTExfSU5U LCAmY2Rucy0+b3RnX3JlZ3MtPmllbik7Cit9CisKKy8qKgorICogY2RuczNfZHJkX3N3aXRjaF9o b3N0IC0gc3RhcnQvc3RvcCBob3N0CisgKiBAY2RuczogUG9pbnRlciB0byBjb250cm9sbGVyIGNv bnRleHQgc3RydWN0dXJlCisgKiBAb246IDEgZm9yIHN0YXJ0LCAwIGZvciBzdG9wCisgKgorICog UmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCisgKi8KK3N0YXRp YyBpbnQgY2RuczNfZHJkX3N3aXRjaF9ob3N0KHN0cnVjdCBjZG5zMyAqY2RucywgaW50IG9uKQor eworCWludCByZXQ7CisJdTMyIHJlZyA9IE9UR0NNRF9PVEdfRElTOworCisJLyogc3dpdGNoIE9U RyBjb3JlICovCisJaWYgKG9uKSB7CisJCXdyaXRlbChPVEdDTURfSE9TVF9CVVNfUkVRIHwgcmVn LCAmY2Rucy0+b3RnX3JlZ3MtPmNtZCk7CisKKwkJZGV2X2RiZyhjZG5zLT5kZXYsICJXYWl0aW5n IGZvciBIb3N0IG1vZGUgaXMgdHVybmVkIG9uXG4iKTsKKwkJcmV0ID0gY2RuczNfaGFuZHNoYWtl KCZjZG5zLT5vdGdfcmVncy0+c3RzLCBPVEdTVFNfWEhDSV9SRUFEWSwKKwkJCQkgICAgICBPVEdT VFNfWEhDSV9SRUFEWSwgMTAwMDAwKTsKKworCQlpZiAocmV0KQorCQkJcmV0dXJuIHJldDsKKwl9 IGVsc2UgeworCQl1c2xlZXBfcmFuZ2UoMzAsIDQwKTsKKwkJd3JpdGVsKE9UR0NNRF9IT1NUX0JV U19EUk9QIHwgT1RHQ01EX0RFVl9CVVNfRFJPUCB8CisJCSAgICAgICBPVEdDTURfREVWX1BPV0VS X09GRiB8IE9UR0NNRF9IT1NUX1BPV0VSX09GRiwKKwkJICAgICAgICZjZG5zLT5vdGdfcmVncy0+ Y21kKTsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworLyoqCisgKiBjZG5zM19kcmRfc3dpdGNoX2dh ZGdldCAtIHN0YXJ0L3N0b3AgZ2FkZ2V0CisgKiBAY2RuczogUG9pbnRlciB0byBjb250cm9sbGVy IGNvbnRleHQgc3RydWN0dXJlCisgKiBAb246IDEgZm9yIHN0YXJ0LCAwIGZvciBzdG9wCisgKgor ICogUmV0dXJucyAwIG9uIHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCisgKi8KK3N0 YXRpYyBpbnQgY2RuczNfZHJkX3N3aXRjaF9nYWRnZXQoc3RydWN0IGNkbnMzICpjZG5zLCBpbnQg b24pCit7CisJaW50IHJldDsKKwl1MzIgcmVnID0gT1RHQ01EX09UR19ESVM7CisKKwkvKiBzd2l0 Y2ggT1RHIGNvcmUgKi8KKwlpZiAob24pIHsKKwkJd3JpdGVsKE9UR0NNRF9ERVZfQlVTX1JFUSB8 IHJlZywgJmNkbnMtPm90Z19yZWdzLT5jbWQpOworCisJCWRldl9kYmcoY2Rucy0+ZGV2LCAiV2Fp dGluZyBmb3IgRGV2aWNlIG1vZGUgaXMgdHVybmVkIG9uXG4iKTsKKworCQlyZXQgPSBjZG5zM19o YW5kc2hha2UoJmNkbnMtPm90Z19yZWdzLT5zdHMsIE9UR1NUU19ERVZfUkVBRFksCisJCQkJICAg ICAgT1RHU1RTX0RFVl9SRUFEWSwgMTAwMDAwKTsKKworCQlpZiAocmV0KQorCQkJcmV0dXJuIHJl dDsKKwl9IGVsc2UgeworCQkvKgorCQkgKiBkcml2ZXIgc2hvdWxkIHdhaXQgYXQgbGVhc3QgMTB1 cyBhZnRlciBkaXNhYmxpbmcgRGV2aWNlCisJCSAqIGJlZm9yZSB0dXJuaW5nLW9mZiBEZXZpY2Ug KERFVl9CVVNfRFJPUCkKKwkJICovCisJCXVzbGVlcF9yYW5nZSgyMCwgMzApOworCQl3cml0ZWwo T1RHQ01EX0hPU1RfQlVTX0RST1AgfCBPVEdDTURfREVWX0JVU19EUk9QIHwKKwkJICAgICAgIE9U R0NNRF9ERVZfUE9XRVJfT0ZGIHwgT1RHQ01EX0hPU1RfUE9XRVJfT0ZGLAorCQkgICAgICAgJmNk bnMtPm90Z19yZWdzLT5jbWQpOworCX0KKworCXJldHVybiAwOworfQorCisvKioKKyAqIGNkbnMz X2luaXRfb3RnX21vZGUgLSBpbml0aWFsaXplIGRyZCBjb250cm9sbGVyCisgKiBAY2RuczogUG9p bnRlciB0byBjb250cm9sbGVyIGNvbnRleHQgc3RydWN0dXJlCisgKgorICogUmV0dXJucyAwIG9u IHN1Y2Nlc3Mgb3RoZXJ3aXNlIG5lZ2F0aXZlIGVycm5vCisgKi8KK3N0YXRpYyB2b2lkIGNkbnMz X2luaXRfb3RnX21vZGUoc3RydWN0IGNkbnMzICpjZG5zKQoreworCWNkbnMzX290Z19kaXNhYmxl X2lycShjZG5zKTsKKwkvKiBjbGVhciBhbGwgaW50ZXJydXB0cyAqLworCXdyaXRlbCh+MCwgJmNk bnMtPm90Z19yZWdzLT5pdmVjdCk7CisKKwljZG5zM19zZXRfbW9kZShjZG5zLCBVU0JfRFJfTU9E RV9PVEcpOworCisJaWYgKGNkbnMzX2lzX2hvc3QoY2RucykpCisJCWNkbnMzX2RyZF9zd2l0Y2hf aG9zdChjZG5zLCAxKTsKKwllbHNlCisJCWNkbnMzX2RyZF9zd2l0Y2hfZ2FkZ2V0KGNkbnMsIDEp OworCisJY2RuczNfb3RnX2VuYWJsZV9pcnEoY2Rucyk7Cit9CisKKy8qKgorICogY2RuczNfZHJk X3VwZGF0ZV9tb2RlIC0gaW5pdGlhbGl6ZSBtb2RlIG9mIG9wZXJhdGlvbgorICogQGNkbnM6IFBv aW50ZXIgdG8gY29udHJvbGxlciBjb250ZXh0IHN0cnVjdHVyZQorICoKKyAqIFJldHVybnMgMCBv biBzdWNjZXNzIG90aGVyd2lzZSBuZWdhdGl2ZSBlcnJubworICovCitpbnQgY2RuczNfZHJkX3Vw ZGF0ZV9tb2RlKHN0cnVjdCBjZG5zMyAqY2RucykKK3sKKwlpbnQgcmV0ID0gMDsKKworCWlmIChj ZG5zLT5kZXNpcmVkX2RyX21vZGUgPT0gY2Rucy0+Y3VycmVudF9kcl9tb2RlKQorCQlyZXR1cm4g cmV0OworCisJY2RuczNfZHJkX3N3aXRjaF9nYWRnZXQoY2RucywgMCk7CisJY2RuczNfZHJkX3N3 aXRjaF9ob3N0KGNkbnMsIDApOworCisJc3dpdGNoIChjZG5zLT5kZXNpcmVkX2RyX21vZGUpIHsK KwljYXNlIFVTQl9EUl9NT0RFX1BFUklQSEVSQUw6CisJCWNkbnMzX3NldF9tb2RlKGNkbnMsIFVT Ql9EUl9NT0RFX1BFUklQSEVSQUwpOworCQlicmVhazsKKwljYXNlIFVTQl9EUl9NT0RFX0hPU1Q6 CisJCWNkbnMzX3NldF9tb2RlKGNkbnMsIFVTQl9EUl9NT0RFX0hPU1QpOworCQlicmVhazsKKwlj YXNlIFVTQl9EUl9NT0RFX09URzoKKwkJY2RuczNfaW5pdF9vdGdfbW9kZShjZG5zKTsKKwkJYnJl YWs7CisJZGVmYXVsdDoKKwkJZGV2X2VycihjZG5zLT5kZXYsICJVbnN1cHBvcnRlZCBtb2RlIG9m IG9wZXJhdGlvbiAlZFxuIiwKKwkJCWNkbnMtPmRyX21vZGUpOworCQlyZXR1cm4gLUVJTlZBTDsK Kwl9CisKKwlyZXR1cm4gcmV0OworfQorCisvKioKKyAqIGNkbnMzX2RyZF9pcnEgLSBpbnRlcnJ1 cHQgaGFuZGxlciBmb3IgT1RHIGV2ZW50cworICoKKyAqIEBpcnE6IGlycSBudW1iZXIgZm9yIGNk bnMzIGNvcmUgZGV2aWNlCisgKiBAZGF0YTogc3RydWN0dXJlIG9mIGNkbnMzCisgKgorICogUmV0 dXJucyBJUlFfSEFORExFRCBvciBJUlFfTk9ORQorICovCitzdGF0aWMgaXJxcmV0dXJuX3QgY2Ru czNfZHJkX2lycShpbnQgaXJxLCB2b2lkICpkYXRhKQoreworCWlycXJldHVybl90IHJldCA9IElS UV9OT05FOworCXN0cnVjdCBjZG5zMyAqY2RucyA9IGRhdGE7CisJdTMyIHJlZzsKKworCWlmIChj ZG5zLT5kcl9tb2RlICE9IFVTQl9EUl9NT0RFX09URykKKwkJcmV0dXJuIHJldDsKKworCXJlZyA9 IHJlYWRsKCZjZG5zLT5vdGdfcmVncy0+aXZlY3QpOworCWlmICghcmVnKQorCQlyZXR1cm4gcmV0 OworCisJaWYgKHJlZyAmIE9UR0lFTl9JRF9DSEFOR0VfSU5UKSB7CisJCWRldl9kYmcoY2Rucy0+ ZGV2LCAiT1RHIElSUTogbmV3IElEOiAlZFxuIiwKKwkJCWNkbnMzX2dldF9pZChjZG5zKSk7CisK KwkJcXVldWVfd29yayhzeXN0ZW1fZnJlZXphYmxlX3dxLCAmY2Rucy0+cm9sZV9zd2l0Y2hfd3Ep OworCisJCXJldCA9IElSUV9IQU5ETEVEOworCX0KKworCXdyaXRlbCh+MCwgJmNkbnMtPm90Z19y ZWdzLT5pdmVjdCk7CisJcmV0dXJuIHJldDsKK30KKworaW50IGNkbnMzX2RyZF9pbml0KHN0cnVj dCBjZG5zMyAqY2RucykKK3sKKwlpbnQgcmV0ID0gMDsKKwl1MzIgc3RhdGU7CisKKwlzdGF0ZSA9 IE9UR1NUU19TVFJBUChyZWFkbCgmY2Rucy0+b3RnX3JlZ3MtPnN0cykpOworCisJLyogVXBkYXRl IGRyX21vZGUgYWNjb3JkaW5nIHRvIFNUUkFQIGNvbmZpZ3VyYXRpb24uICovCisJY2Rucy0+ZHJf bW9kZSA9IFVTQl9EUl9NT0RFX09URzsKKwlpZiAoc3RhdGUgPT0gT1RHU1RTX1NUUkFQX0hPU1Qp IHsKKwkJZGV2X2luZm8oY2Rucy0+ZGV2LCAiQ29udHJvbGxlciBzdHJhcHBlZCB0byBIT1NUXG4i KTsKKwkJY2Rucy0+ZHJfbW9kZSA9IFVTQl9EUl9NT0RFX0hPU1Q7CisJfSBlbHNlIGlmIChzdGF0 ZSA9PSBPVEdTVFNfU1RSQVBfR0FER0VUKSB7CisJCWRldl9pbmZvKGNkbnMtPmRldiwgIkNvbnRy b2xsZXIgc3RyYXBwZWQgdG8gUEVSSVBIRVJBTFxuIik7CisJCWNkbnMtPmRyX21vZGUgPSBVU0Jf RFJfTU9ERV9QRVJJUEhFUkFMOworCX0KKworCWNkbnMtPmRlc2lyZWRfZHJfbW9kZSA9IGNkbnMt PmRyX21vZGU7CisJY2Rucy0+Y3VycmVudF9kcl9tb2RlID0gVVNCX0RSX01PREVfVU5LTk9XTjsK KworCXJldCA9IGRldm1fcmVxdWVzdF9pcnEoY2Rucy0+ZGV2LCBjZG5zLT5pcnEsIGNkbnMzX2Ry ZF9pcnEsIElSUUZfU0hBUkVELAorCQkJICAgICAgIGRldl9uYW1lKGNkbnMtPmRldiksIGNkbnMp OworCisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCXN0YXRlID0gcmVhZGwoJmNkbnMtPm90 Z19yZWdzLT5zdHMpOworCWlmIChPVEdTVFNfT1RHX05SRFkoc3RhdGUpICE9IDApIHsKKwkJZGV2 X2VycihjZG5zLT5kZXYsICJDYWRlbmNlIFVTQjMgT1RHIGRldmljZSBub3QgcmVhZHlcbiIpOwor CQlyZXR1cm4gLUVOT0RFVjsKKwl9CisKKwlyZXQgPSBjZG5zM19kcmRfdXBkYXRlX21vZGUoY2Ru cyk7CisKKwlkZXZfaW5mbyhjZG5zLT5kZXYsICJDb250cm9sbGVyIERldmljZSBJRDogJTA4bHgs IFJldmlzaW9uIElEOiAlMDhseFxuIiwKKwkJIENETlNfUklEKHJlYWRsKCZjZG5zLT5vdGdfcmVn cy0+cmlkKSksCisJCSBDRE5TX0RJRChyZWFkbCgmY2Rucy0+b3RnX3JlZ3MtPmRpZCkpKTsKKwor CXJldHVybiByZXQ7Cit9CisKK2ludCBjZG5zM19kcmRfZXhpdChzdHJ1Y3QgY2RuczMgKmNkbnMp Cit7CisJcmV0dXJuIGNkbnMzX2RyZF9zd2l0Y2hfaG9zdChjZG5zLCAwKTsKK30KZGlmZiAtLWdp dCBhL2RyaXZlcnMvdXNiL2NkbnMzL2RyZC5oIGIvZHJpdmVycy91c2IvY2RuczMvZHJkLmgKbmV3 IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi40MTU5ZTZlNjEyYWMKLS0tIC9k ZXYvbnVsbAorKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9kcmQuaApAQCAtMCwwICsxLDEyOSBAQAor LyogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAgKi8KKy8qCisgKiBDYWRlbmNlIFVT QjMgRFJEIGhlYWRlciBmaWxlLgorICoKKyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNlLgor ICoKKyAqIEF1dGhvcjogUGF3ZWwgTGFzemN6YWsgPHBhd2VsbEBjYWRlbmNlLmNvbT4KKyAqLwor I2lmbmRlZiBfX0xJTlVYX0NETlMzX0RSRAorI2RlZmluZSBfX0xJTlVYX0NETlMzX0RSRAorCisj aW5jbHVkZSA8bGludXgvdXNiL290Zy5oPgorI2luY2x1ZGUgPGxpbnV4L3BoeS9waHkuaD4KKyNp bmNsdWRlICJjb3JlLmgiCisKKy8qICBEUkQgcmVnaXN0ZXIgaW50ZXJmYWNlLiAqLworc3RydWN0 IGNkbnMzX290Z19yZWdzIHsKKwlfX2xlMzIgZGlkOworCV9fbGUzMiByaWQ7CisJX19sZTMyIGNh cGFiaWxpdGllczsKKwlfX2xlMzIgcmVzZXJ2ZWQxOworCV9fbGUzMiBjbWQ7CisJX19sZTMyIHN0 czsKKwlfX2xlMzIgc3RhdGU7CisJX19sZTMyIHJlc2VydmVkMjsKKwlfX2xlMzIgaWVuOworCV9f bGUzMiBpdmVjdDsKKwlfX2xlMzIgcmVmY2xrOworCV9fbGUzMiB0bXI7CisJX19sZTMyIHJlc2Vy dmVkM1s0XTsKKwlfX2xlMzIgc2ltdWxhdGU7CisJX19sZTMyIG92ZXJyaWRlOworCV9fbGUzMiBz dXNwX2N0cmw7CisJX19sZTMyIHJlc2VydmVkNDsKKwlfX2xlMzIgYW5hc3RzOworCV9fbGUzMiBh ZHBfcmFtcF90aW1lOworCV9fbGUzMiBjdHJsMTsKKwlfX2xlMzIgY3RybDI7Cit9OworCisvKiBD RE5TX1JJRCAtIGJpdG1hc2tzICovCisjZGVmaW5lIENETlNfUklEKHApCQkJKChwKSAmIEdFTk1B U0soMTUsIDApKQorCisvKiBDRE5TX1ZJRCAtIGJpdG1hc2tzICovCisjZGVmaW5lIENETlNfRElE KHApCQkJKChwKSAmIEdFTk1BU0soMzEsIDApKQorCisvKiBPVEdDTUQgLSBiaXRtYXNrcyAqLwor LyogIlJlcXVlc3QgdGhlIGJ1cyBmb3IgRGV2aWNlIG1vZGUuICovCisjZGVmaW5lIE9UR0NNRF9E RVZfQlVTX1JFUQkJQklUKDApCisvKiBSZXF1ZXN0IHRoZSBidXMgZm9yIEhvc3QgbW9kZSAqLwor I2RlZmluZSBPVEdDTURfSE9TVF9CVVNfUkVRCQlCSVQoMSkKKy8qIEVuYWJsZSBPVEcgbW9kZS4g Ki8KKyNkZWZpbmUgT1RHQ01EX09UR19FTgkJCUJJVCgyKQorLyogRGlzYWJsZSBPVEcgbW9kZSAq LworI2RlZmluZSBPVEdDTURfT1RHX0RJUwkJCUJJVCgzKQorLyoiQ29uZmlndXJlIE9URyBhcyBB LURldmljZS4gKi8KKyNkZWZpbmUgT1RHQ01EX0FfREVWX0VOCQkJQklUKDQpCisvKiJDb25maWd1 cmUgT1RHIGFzIEEtRGV2aWNlLiAqLworI2RlZmluZSBPVEdDTURfQV9ERVZfRElTCQlCSVQoNSkK Ky8qIERyb3AgdGhlIGJ1cyBmb3IgRGV2aWNlIG1vZAllLiAqLworI2RlZmluZSBPVEdDTURfREVW X0JVU19EUk9QCQlCSVQoOCkKKy8qIERyb3AgdGhlIGJ1cyBmb3IgSG9zdCBtb2RlKi8KKyNkZWZp bmUgT1RHQ01EX0hPU1RfQlVTX0RST1AJCUJJVCg5KQorLyogUG93ZXIgRG93biBVU0JTUy1ERVYu ICovCisjZGVmaW5lIE9UR0NNRF9ERVZfUE9XRVJfT0ZGCQlCSVQoMTEpCisvKiBQb3dlciBEb3du IENETlNYSENJLiAqLworI2RlZmluZSBPVEdDTURfSE9TVF9QT1dFUl9PRkYJCUJJVCgxMikKKwor LyogT1RHSUVOIC0gYml0bWFza3MgKi8KKy8qIElEIGNoYW5nZSBpbnRlcnJ1cHQgZW5hYmxlICov CisjZGVmaW5lIE9UR0lFTl9JRF9DSEFOR0VfSU5UCQlCSVQoMCkKKy8qIFZidXN2YWxpZCBmYWxs IGRldGVjdGVkIGludGVycnVwdCBlbmFibGUuKi8KKyNkZWZpbmUgT1RHSUVOX1ZCVVNWQUxJRF9S SVNFX0lOVAlCSVQoNCkKKy8qIFZidXN2YWxpZCBmYWxsIGRldGVjdGVkIGludGVycnVwdCBlbmFi bGUgKi8KKyNkZWZpbmUgT1RHSUVOX1ZCVVNWQUxJRF9GQUxMX0lOVAlCSVQoNSkKKworLyogT1RH U1RTIC0gYml0bWFza3MgKi8KKy8qCisgKiBDdXJyZW50IHZhbHVlIG9mIHRoZSBJRCBwaW4uIEl0 IGlzIG9ubHkgdmFsaWQgd2hlbiBpZHB1bGx1cCBpbgorICogIE9UR0NUUkwxX1RZUEUgcmVnaXN0 ZXIgaXMgc2V0IHRvICcxJy4KKyAqLworI2RlZmluZSBPVEdTVFNfSURfVkFMVUUJCQlCSVQoMCkK Ky8qIEN1cnJlbnQgdmFsdWUgb2YgdGhlIHZidXNfdmFsaWQgKi8KKyNkZWZpbmUgT1RHU1RTX1ZC VVNfVkFMSUQJCUJJVCgxKQorLyogQ3VycmVudCB2YWx1ZSBvZiB0aGUgYl9zZXNzX3ZsZCAqLwor I2RlZmluZSBPVEdTVFNfU0VTU0lPTl9WQUxJRAkJQklUKDIpCisvKkRldmljZSBtb2RlIGlzIGFj dGl2ZSovCisjZGVmaW5lIE9UR1NUU19ERVZfQUNUSVZFCQlCSVQoMykKKy8qIEhvc3QgbW9kZSBp cyBhY3RpdmUuICovCisjZGVmaW5lIE9UR1NUU19IT1NUX0FDVElWRQkJQklUKDQpCisvKiBPVEcg Q29udHJvbGxlciBub3QgcmVhZHkuICovCisjZGVmaW5lIE9UR1NUU19PVEdfTlJEWV9NQVNLCQlC SVQoMTEpCisjZGVmaW5lIE9UR1NUU19PVEdfTlJEWShwKQkJKChwKSAmIE9UR1NUU19PVEdfTlJE WV9NQVNLKQorLyoKKyAqIFZhbHVlIG9mIHRoZSBzdHJhcCBwaW5zLgorICogMDAwIC0gbm8gZGVm YXVsdCBjb25maWd1cmF0aW9uCisgKiAwMTAgLSBDb250cm9sbGVyIGluaXRpYWxsIGNvbmZpZ3Vy ZWQgYXMgSG9zdAorICogMTAwIC0gQ29udHJvbGxlciBpbml0aWFsbHkgY29uZmlndXJlZCBhcyBE ZXZpY2UKKyAqLworI2RlZmluZSBPVEdTVFNfU1RSQVAocCkJCQkoKChwKSAmIEdFTk1BU0soMTQs IDEyKSkgPj4gMTIpCisjZGVmaW5lIE9UR1NUU19TVFJBUF9OT19ERUZBVUxUX0NGRwkweDAwCisj ZGVmaW5lIE9UR1NUU19TVFJBUF9IT1NUX09URwkJMHgwMQorI2RlZmluZSBPVEdTVFNfU1RSQVBf SE9TVAkJMHgwMgorI2RlZmluZSBPVEdTVFNfU1RSQVBfR0FER0VUCQkweDA0CisvKiBIb3N0IG1v ZGUgaXMgdHVybmVkIG9uLiAqLworI2RlZmluZSBPVEdTVFNfWEhDSV9SRUFEWQkJQklUKDI2KQor LyogIkRldmljZSBtb2RlIGlzIHR1cm5lZCBvbiAuKi8KKyNkZWZpbmUgT1RHU1RTX0RFVl9SRUFE WQkJQklUKDI3KQorCisvKiBPVEdTVEFURS0gYml0bWFza3MgKi8KKyNkZWZpbmUgT1RHU1RBVEVf SE9TVF9TVEFURV9NQVNLCUdFTk1BU0soNSwgMykKKyNkZWZpbmUgT1RHU1RBVEVfSE9TVF9TVEFU RV9JRExFCTB4MAorI2RlZmluZSBPVEdTVEFURV9IT1NUX1NUQVRFX1ZCVVNfRkFMTCAgIDB4Nwor I2RlZmluZSBPVEdTVEFURV9IT1NUX1NUQVRFKHApCQkoKChwKSAmIE9UR1NUQVRFX0hPU1RfU1RB VEVfTUFTSykgPj4gMykKKworLyogT1RHUkVGQ0xLIC0gYml0bWFza3MgKi8KKyNkZWZpbmUgT1RH UkVGQ0xLX1NUQl9DTEtfU1dJVENIX0VOCUJJVCgzMSkKKworLyogT1ZFUlJJREUgLSBiaXRtYXNr cyAqLworI2RlZmluZSBPVkVSUklERV9JRFBVTExVUAkJQklUKDApCisKK2ludCBjZG5zM19pc19o b3N0KHN0cnVjdCBjZG5zMyAqY2Rucyk7CitpbnQgY2RuczNfaXNfZGV2aWNlKHN0cnVjdCBjZG5z MyAqY2Rucyk7CitpbnQgY2RuczNfZ2V0X2lkKHN0cnVjdCBjZG5zMyAqY2Rucyk7CitpbnQgY2Ru czNfZHJkX2luaXQoc3RydWN0IGNkbnMzICpjZG5zKTsKK2ludCBjZG5zM19kcmRfZXhpdChzdHJ1 Y3QgY2RuczMgKmNkbnMpOworaW50IGNkbnMzX2RyZF91cGRhdGVfbW9kZShzdHJ1Y3QgY2RuczMg KmNkbnMpOworCisjZW5kaWYgLyogX19MSU5VWF9DRE5TM19EUkQgKi8KZGlmZiAtLWdpdCBhL2Ry aXZlcnMvdXNiL2NkbnMzL2VwMC5jIGIvZHJpdmVycy91c2IvY2RuczMvZXAwLmMKbmV3IGZpbGUg bW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi4xZWYwZTlmNzNlM2UKLS0tIC9kZXYvbnVs bAorKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9lcDAuYwpAQCAtMCwwICsxLDg2NCBAQAorLy8gU1BE WC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKy8qCisgKiBDYWRlbmNlIFVTQlNTIERSRCBE cml2ZXIgLSBnYWRnZXQgc2lkZS4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5jZSBE ZXNpZ24gU3lzdGVtcy4KKyAqIENvcHlyaWdodCAoQykgMjAxNy0yMDE4IE5YUAorICoKKyAqIEF1 dGhvcnM6IFBhd2VsIEpleiA8cGplekBjYWRlbmNlLmNvbT4sCisgKiAgICAgICAgICBQYXdlbCBM YXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICoJICAgIFBldGVyIENoZW4gPHBldGVyLmNo ZW5AbnhwLmNvbT4KKyAqLworCisjaW5jbHVkZSA8bGludXgvdXNiL2NvbXBvc2l0ZS5oPgorCisj aW5jbHVkZSAiZ2FkZ2V0LmgiCisjaW5jbHVkZSAidHJhY2UuaCIKKworc3RhdGljIHN0cnVjdCB1 c2JfZW5kcG9pbnRfZGVzY3JpcHRvciBjZG5zM19nYWRnZXRfZXAwX2Rlc2MgPSB7CisJLmJMZW5n dGggPSBVU0JfRFRfRU5EUE9JTlRfU0laRSwKKwkuYkRlc2NyaXB0b3JUeXBlID0gVVNCX0RUX0VO RFBPSU5ULAorCS5ibUF0dHJpYnV0ZXMgPQlVU0JfRU5EUE9JTlRfWEZFUl9DT05UUk9MLAorfTsK KworLyoqCisgKiBjZG5zM19lcDBfcnVuX3RyYW5zZmVyIC0gRG8gdHJhbnNmZXIgb24gZGVmYXVs dCBlbmRwb2ludCBoYXJkd2FyZQorICogQHByaXZfZGV2OiBleHRlbmRlZCBnYWRnZXQgb2JqZWN0 CisgKiBAZG1hX2FkZHI6IHBoeXNpY2FsIGFkZHJlc3Mgd2hlcmUgZGF0YSBpcy93aWxsIGJlIHN0 b3JlZAorICogQGxlbmd0aDogZGF0YSBsZW5ndGgKKyAqIEBlcmR5OiBzZXQgaXQgdG8gMSB3aGVu IEVSRFkgcGFja2V0IHNob3VsZCBiZSBzZW50IC0KKyAqICAgICAgICBleGl0IGZyb20gZmxvdyBj b250cm9sIHN0YXRlCisgKi8KK3N0YXRpYyB2b2lkIGNkbnMzX2VwMF9ydW5fdHJhbnNmZXIoc3Ry dWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYsCisJCQkJICAgZG1hX2FkZHJfdCBkbWFfYWRkciwK KwkJCQkgICB1bnNpZ25lZCBpbnQgbGVuZ3RoLCBpbnQgZXJkeSkKK3sKKwlzdHJ1Y3QgY2RuczNf dXNiX3JlZ3MgX19pb21lbSAqcmVncyA9IHByaXZfZGV2LT5yZWdzOworCXN0cnVjdCBjZG5zM19l bmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKHByaXZfZGV2LT5nYWRnZXQuZXAwKTsK KworCXByaXZfZGV2LT5lcDBfdHJiLT5idWZmZXIgPSBUUkJfQlVGRkVSKGRtYV9hZGRyKTsKKwlw cml2X2Rldi0+ZXAwX3RyYi0+bGVuZ3RoID0gVFJCX0xFTihsZW5ndGgpOworCXByaXZfZGV2LT5l cDBfdHJiLT5jb250cm9sID0gVFJCX0NZQ0xFIHwgVFJCX0lPQyB8IFRSQl9UWVBFKFRSQl9OT1JN QUwpOworCisJdHJhY2VfY2RuczNfcHJlcGFyZV90cmIocHJpdl9lcCwgcHJpdl9kZXYtPmVwMF90 cmIpOworCisJY2RuczNfc2VsZWN0X2VwKHByaXZfZGV2LCBwcml2X2Rldi0+ZXAwX2RhdGFfZGly KTsKKworCXdyaXRlbChFUF9TVFNfVFJCRVJSLCAmcmVncy0+ZXBfc3RzKTsKKwl3cml0ZWwoRVBf VFJBRERSX1RSQUREUihwcml2X2Rldi0+ZXAwX3RyYl9kbWEpLCAmcmVncy0+ZXBfdHJhZGRyKTsK Kwl0cmFjZV9jZG5zM19kb29yYmVsbF9lcDAocHJpdl9kZXYtPmVwMF9kYXRhX2RpciA/ICJlcDBp biIgOiAiZXAwb3V0Iik7CisKKwkvKiBUUkIgc2hvdWxkIGJlIHByZXBhcmVkIGJlZm9yZSBzdGFy dGluZyB0cmFuc2ZlciAqLworCXdyaXRlbChFUF9DTURfRFJEWSwgJnJlZ3MtPmVwX2NtZCk7CisK KwlpZiAoZXJkeSkKKwkJd3JpdGVsKEVQX0NNRF9FUkRZLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX2Nt ZCk7Cit9CisKKy8qKgorICogY2RuczNfZXAwX2RlbGVnYXRlX3JlcSAtIFJldHVybnMgc3RhdHVz IG9mIGhhbmRsaW5nIHNldHVwIHBhY2tldAorICogU2V0dXAgaXMgaGFuZGxlZCBieSBnYWRnZXQg ZHJpdmVyCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBjdHJsX3Jl cTogcG9pbnRlciB0byByZWNlaXZlZCBzZXR1cCBwYWNrZXQKKyAqCisgKiBSZXR1cm5zIHplcm8g b24gc3VjY2VzcyBvciBuZWdhdGl2ZSB2YWx1ZSBvbiBmYWlsdXJlCisgKi8KK3N0YXRpYyBpbnQg Y2RuczNfZXAwX2RlbGVnYXRlX3JlcShzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiwKKwkJ CQkgIHN0cnVjdCB1c2JfY3RybHJlcXVlc3QgKmN0cmxfcmVxKQoreworCWludCByZXQ7CisKKwlz cGluX3VubG9jaygmcHJpdl9kZXYtPmxvY2spOworCXByaXZfZGV2LT5zZXR1cF9wZW5kaW5nID0g MTsKKwlyZXQgPSBwcml2X2Rldi0+Z2FkZ2V0X2RyaXZlci0+c2V0dXAoJnByaXZfZGV2LT5nYWRn ZXQsIGN0cmxfcmVxKTsKKwlwcml2X2Rldi0+c2V0dXBfcGVuZGluZyA9IDA7CisJc3Bpbl9sb2Nr KCZwcml2X2Rldi0+bG9jayk7CisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIHZvaWQgY2RuczNf cHJlcGFyZV9zZXR1cF9wYWNrZXQoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYpCit7CisJ cHJpdl9kZXYtPmVwMF9kYXRhX2RpciA9IDA7CisJY2RuczNfZXAwX3J1bl90cmFuc2Zlcihwcml2 X2RldiwgcHJpdl9kZXYtPnNldHVwX2RtYSwKKwkJCSAgICAgICBzaXplb2Yoc3RydWN0IHVzYl9j dHJscmVxdWVzdCksIDApOworfQorCisvKioKKyAqIGNkbnMzX3JlcV9lcDBfc2V0X2NvbmZpZ3Vy YXRpb24gLSBIYW5kbGluZyBvZiBTRVRfQ09ORklHIHN0YW5kYXJkIFVTQiByZXF1ZXN0CisgKiBA cHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBjdHJsX3JlcTogcG9pbnRlciB0 byByZWNlaXZlZCBzZXR1cCBwYWNrZXQKKyAqCisgKiBSZXR1cm5zIDAgaWYgc3VjY2VzcywgVVNC X0dBREdFVF9ERUxBWUVEX1NUQVRVUyBvbiBkZWZlcnJlZCBzdGF0dXMgc3RhZ2UsCisgKiBlcnJv ciBjb2RlIG9uIGVycm9yCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfcmVxX2VwMF9zZXRfY29uZmln dXJhdGlvbihzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiwKKwkJCQkJICAgc3RydWN0IHVz Yl9jdHJscmVxdWVzdCAqY3RybF9yZXEpCit7CisJZW51bSB1c2JfZGV2aWNlX3N0YXRlIGRldmlj ZV9zdGF0ZSA9IHByaXZfZGV2LT5nYWRnZXQuc3RhdGU7CisJc3RydWN0IGNkbnMzX2VuZHBvaW50 ICpwcml2X2VwOworCXUzMiBjb25maWcgPSBsZTE2X3RvX2NwdShjdHJsX3JlcS0+d1ZhbHVlKTsK KwlpbnQgcmVzdWx0ID0gMDsKKwlpbnQgaTsKKworCXN3aXRjaCAoZGV2aWNlX3N0YXRlKSB7CisJ Y2FzZSBVU0JfU1RBVEVfQUREUkVTUzoKKwkJLyogQ29uZmlndXJlIG5vbi1jb250cm9sIEVQcyAq LworCQlmb3IgKGkgPSAwOyBpIDwgQ0ROUzNfRU5EUE9JTlRTX01BWF9DT1VOVDsgaSsrKSB7CisJ CQlwcml2X2VwID0gcHJpdl9kZXYtPmVwc1tpXTsKKwkJCWlmICghcHJpdl9lcCkKKwkJCQljb250 aW51ZTsKKworCQkJaWYgKHByaXZfZXAtPmZsYWdzICYgRVBfQ0xBSU1FRCkKKwkJCQljZG5zM19l cF9jb25maWcocHJpdl9lcCk7CisJCX0KKworCQlyZXN1bHQgPSBjZG5zM19lcDBfZGVsZWdhdGVf cmVxKHByaXZfZGV2LCBjdHJsX3JlcSk7CisKKwkJaWYgKHJlc3VsdCkKKwkJCXJldHVybiByZXN1 bHQ7CisKKwkJaWYgKGNvbmZpZykgeworCQkJY2RuczNfc2V0X2h3X2NvbmZpZ3VyYXRpb24ocHJp dl9kZXYpOworCQl9IGVsc2UgeworCQkJY2RuczNfZ2FkZ2V0X3VuY29uZmlnKHByaXZfZGV2KTsK KwkJCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZwcml2X2Rldi0+Z2FkZ2V0LAorCQkJCQkgICAgIFVT Ql9TVEFURV9BRERSRVNTKTsKKwkJfQorCQlicmVhazsKKwljYXNlIFVTQl9TVEFURV9DT05GSUdV UkVEOgorCQlyZXN1bHQgPSBjZG5zM19lcDBfZGVsZWdhdGVfcmVxKHByaXZfZGV2LCBjdHJsX3Jl cSk7CisKKwkJaWYgKCFjb25maWcgJiYgIXJlc3VsdCkgeworCQkJY2RuczNfZ2FkZ2V0X3VuY29u ZmlnKHByaXZfZGV2KTsKKwkJCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZwcml2X2Rldi0+Z2FkZ2V0 LAorCQkJCQkgICAgIFVTQl9TVEFURV9BRERSRVNTKTsKKwkJfQorCQlicmVhazsKKwlkZWZhdWx0 OgorCQlyZXN1bHQgPSAtRUlOVkFMOworCX0KKworCXJldHVybiByZXN1bHQ7Cit9CisKKy8qKgor ICogY2RuczNfcmVxX2VwMF9zZXRfYWRkcmVzcyAtIEhhbmRsaW5nIG9mIFNFVF9BRERSRVNTIHN0 YW5kYXJkIFVTQiByZXF1ZXN0CisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmplY3QK KyAqIEBjdHJsX3JlcTogcG9pbnRlciB0byByZWNlaXZlZCBzZXR1cCBwYWNrZXQKKyAqCisgKiBS ZXR1cm5zIDAgaWYgc3VjY2VzcywgZXJyb3IgY29kZSBvbiBlcnJvcgorICovCitzdGF0aWMgaW50 IGNkbnMzX3JlcV9lcDBfc2V0X2FkZHJlc3Moc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYs CisJCQkJICAgICBzdHJ1Y3QgdXNiX2N0cmxyZXF1ZXN0ICpjdHJsX3JlcSkKK3sKKwllbnVtIHVz Yl9kZXZpY2Vfc3RhdGUgZGV2aWNlX3N0YXRlID0gcHJpdl9kZXYtPmdhZGdldC5zdGF0ZTsKKwl1 MzIgcmVnOworCXUzMiBhZGRyOworCisJYWRkciA9IGxlMTZfdG9fY3B1KGN0cmxfcmVxLT53VmFs dWUpOworCisJaWYgKGFkZHIgPiBVU0JfREVWSUNFX01BWF9BRERSRVNTKSB7CisJCWRldl9lcnIo cHJpdl9kZXYtPmRldiwKKwkJCSJEZXZpY2UgYWRkcmVzcyAoJWQpIGNhbm5vdCBiZSBncmVhdGVy IHRoYW4gJWRcbiIsCisJCQlhZGRyLCBVU0JfREVWSUNFX01BWF9BRERSRVNTKTsKKwkJcmV0dXJu IC1FSU5WQUw7CisJfQorCisJaWYgKGRldmljZV9zdGF0ZSA9PSBVU0JfU1RBVEVfQ09ORklHVVJF RCkgeworCQlkZXZfZXJyKHByaXZfZGV2LT5kZXYsCisJCQkiY2FuJ3Qgc2V0X2FkZHJlc3MgZnJv bSBjb25maWd1cmVkIHN0YXRlXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJcmVnID0g cmVhZGwoJnByaXZfZGV2LT5yZWdzLT51c2JfY21kKTsKKworCXdyaXRlbChyZWcgfCBVU0JfQ01E X0ZBRERSKGFkZHIpIHwgVVNCX0NNRF9TRVRfQUREUiwKKwkgICAgICAgJnByaXZfZGV2LT5yZWdz LT51c2JfY21kKTsKKworCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZwcml2X2Rldi0+Z2FkZ2V0LAor CQkJICAgICAoYWRkciA/IFVTQl9TVEFURV9BRERSRVNTIDogVVNCX1NUQVRFX0RFRkFVTFQpKTsK KworCWNkbnMzX3ByZXBhcmVfc2V0dXBfcGFja2V0KHByaXZfZGV2KTsKKworCXdyaXRlbChFUF9D TURfRVJEWSB8IEVQX0NNRF9SRVFfQ01QTCwgJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQpOworCisJ cmV0dXJuIDA7Cit9CisKKy8qKgorICogY2RuczNfcmVxX2VwMF9nZXRfc3RhdHVzIC0gSGFuZGxp bmcgb2YgR0VUX1NUQVRVUyBzdGFuZGFyZCBVU0IgcmVxdWVzdAorICogQHByaXZfZGV2OiBleHRl bmRlZCBnYWRnZXQgb2JqZWN0CisgKiBAY3RybF9yZXE6IHBvaW50ZXIgdG8gcmVjZWl2ZWQgc2V0 dXAgcGFja2V0CisgKgorICogUmV0dXJucyAwIGlmIHN1Y2Nlc3MsIGVycm9yIGNvZGUgb24gZXJy b3IKKyAqLworc3RhdGljIGludCBjZG5zM19yZXFfZXAwX2dldF9zdGF0dXMoc3RydWN0IGNkbnMz X2RldmljZSAqcHJpdl9kZXYsCisJCQkJICAgIHN0cnVjdCB1c2JfY3RybHJlcXVlc3QgKmN0cmwp Cit7CisJX19sZTE2ICpyZXNwb25zZV9wa3Q7CisJdTE2IHVzYl9zdGF0dXMgPSAwOworCXUzMiBy ZWNpcDsKKwl1MzIgcmVnOworCisJcmVjaXAgPSBjdHJsLT5iUmVxdWVzdFR5cGUgJiBVU0JfUkVD SVBfTUFTSzsKKworCXN3aXRjaCAocmVjaXApIHsKKwljYXNlIFVTQl9SRUNJUF9ERVZJQ0U6CisJ CS8qIHNlbGYgcG93ZXJlZCAqLworCQlpZiAocHJpdl9kZXYtPmlzX3NlbGZwb3dlcmVkKQorCQkJ dXNiX3N0YXR1cyA9IEJJVChVU0JfREVWSUNFX1NFTEZfUE9XRVJFRCk7CisKKwkJaWYgKHByaXZf ZGV2LT53YWtlX3VwX2ZsYWcpCisJCQl1c2Jfc3RhdHVzIHw9IEJJVChVU0JfREVWSUNFX1JFTU9U RV9XQUtFVVApOworCisJCWlmIChwcml2X2Rldi0+Z2FkZ2V0LnNwZWVkICE9IFVTQl9TUEVFRF9T VVBFUikKKwkJCWJyZWFrOworCisJCXJlZyA9IHJlYWRsKCZwcml2X2Rldi0+cmVncy0+dXNiX3N0 cyk7CisKKwkJaWYgKHByaXZfZGV2LT51MV9hbGxvd2VkKQorCQkJdXNiX3N0YXR1cyB8PSBCSVQo VVNCX0RFVl9TVEFUX1UxX0VOQUJMRUQpOworCisJCWlmIChwcml2X2Rldi0+dTJfYWxsb3dlZCkK KwkJCXVzYl9zdGF0dXMgfD0gQklUKFVTQl9ERVZfU1RBVF9VMl9FTkFCTEVEKTsKKworCQlicmVh azsKKwljYXNlIFVTQl9SRUNJUF9JTlRFUkZBQ0U6CisJCXJldHVybiBjZG5zM19lcDBfZGVsZWdh dGVfcmVxKHByaXZfZGV2LCBjdHJsKTsKKwljYXNlIFVTQl9SRUNJUF9FTkRQT0lOVDoKKwkJLyog Y2hlY2sgaWYgZW5kcG9pbnQgaXMgc3RhbGxlZCAqLworCQljZG5zM19zZWxlY3RfZXAocHJpdl9k ZXYsIGN0cmwtPndJbmRleCk7CisJCWlmIChFUF9TVFNfU1RBTEwocmVhZGwoJnByaXZfZGV2LT5y ZWdzLT5lcF9zdHMpKSkKKwkJCXVzYl9zdGF0dXMgPSAgQklUKFVTQl9FTkRQT0lOVF9IQUxUKTsK KwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJcmVzcG9uc2Vf cGt0ID0gKF9fbGUxNiAqKXByaXZfZGV2LT5zZXR1cF9idWY7CisJKnJlc3BvbnNlX3BrdCA9IGNw dV90b19sZTE2KHVzYl9zdGF0dXMpOworCisJY2RuczNfZXAwX3J1bl90cmFuc2Zlcihwcml2X2Rl diwgcHJpdl9kZXYtPnNldHVwX2RtYSwKKwkJCSAgICAgICBzaXplb2YoKnJlc3BvbnNlX3BrdCks IDEpOworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50IGNkbnMzX2VwMF9mZWF0dXJlX2hhbmRs ZV9kZXZpY2Uoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYsCisJCQkJCSAgIHN0cnVjdCB1 c2JfY3RybHJlcXVlc3QgKmN0cmwsCisJCQkJCSAgIGludCBzZXQpCit7CisJZW51bSB1c2JfZGV2 aWNlX3N0YXRlIHN0YXRlOworCWVudW0gdXNiX2RldmljZV9zcGVlZCBzcGVlZDsKKwlpbnQgcmV0 ID0gMDsKKwl1MzIgd1ZhbHVlOworCXUzMiB3SW5kZXg7CisJdTE2IHRtb2RlOworCisJd1ZhbHVl ID0gbGUxNl90b19jcHUoY3RybC0+d1ZhbHVlKTsKKwl3SW5kZXggPSBsZTE2X3RvX2NwdShjdHJs LT53SW5kZXgpOworCXN0YXRlID0gcHJpdl9kZXYtPmdhZGdldC5zdGF0ZTsKKwlzcGVlZCA9IHBy aXZfZGV2LT5nYWRnZXQuc3BlZWQ7CisKKwlzd2l0Y2ggKGN0cmwtPndWYWx1ZSkgeworCWNhc2Ug VVNCX0RFVklDRV9SRU1PVEVfV0FLRVVQOgorCQlwcml2X2Rldi0+d2FrZV91cF9mbGFnID0gISFz ZXQ7CisJCWJyZWFrOworCWNhc2UgVVNCX0RFVklDRV9VMV9FTkFCTEU6CisJCWlmIChzdGF0ZSAh PSBVU0JfU1RBVEVfQ09ORklHVVJFRCB8fCBzcGVlZCAhPSBVU0JfU1BFRURfU1VQRVIpCisJCQly ZXR1cm4gLUVJTlZBTDsKKworCQlwcml2X2Rldi0+dTFfYWxsb3dlZCA9ICEhc2V0OworCQlicmVh azsKKwljYXNlIFVTQl9ERVZJQ0VfVTJfRU5BQkxFOgorCQlpZiAoc3RhdGUgIT0gVVNCX1NUQVRF X0NPTkZJR1VSRUQgfHwgc3BlZWQgIT0gVVNCX1NQRUVEX1NVUEVSKQorCQkJcmV0dXJuIC1FSU5W QUw7CisKKwkJcHJpdl9kZXYtPnUyX2FsbG93ZWQgPSAhIXNldDsKKwkJYnJlYWs7CisJY2FzZSBV U0JfREVWSUNFX0xUTV9FTkFCTEU6CisJCXJldCA9IC1FSU5WQUw7CisJCWJyZWFrOworCWNhc2Ug VVNCX0RFVklDRV9URVNUX01PREU6CisJCWlmIChzdGF0ZSAhPSBVU0JfU1RBVEVfQ09ORklHVVJF RCB8fCBzcGVlZCA+IFVTQl9TUEVFRF9ISUdIKQorCQkJcmV0dXJuIC1FSU5WQUw7CisKKwkJdG1v ZGUgPSBsZTE2X3RvX2NwdShjdHJsLT53SW5kZXgpOworCisJCWlmICghc2V0IHx8ICh0bW9kZSAm IDB4ZmYpICE9IDApCisJCQlyZXR1cm4gLUVJTlZBTDsKKworCQlzd2l0Y2ggKHRtb2RlID4+IDgp IHsKKwkJY2FzZSBURVNUX0o6CisJCWNhc2UgVEVTVF9LOgorCQljYXNlIFRFU1RfU0UwX05BSzoK KwkJY2FzZSBURVNUX1BBQ0tFVDoKKwkJCWNkbnMzX3NldF9yZWdpc3Rlcl9iaXQoJnByaXZfZGV2 LT5yZWdzLT51c2JfY21kLAorCQkJCQkgICAgICAgVVNCX0NNRF9TVE1PREUgfAorCQkJCQkgICAg ICAgVVNCX1NUU19UTU9ERV9TRUwodG1vZGUgLSAxKSk7CisJCQlicmVhazsKKwkJZGVmYXVsdDoK KwkJCXJldCA9IC1FSU5WQUw7CisJCX0KKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJcmV0ID0gLUVJ TlZBTDsKKwl9CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgaW50IGNkbnMzX2VwMF9mZWF0 dXJlX2hhbmRsZV9pbnRmKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LAorCQkJCQkgc3Ry dWN0IHVzYl9jdHJscmVxdWVzdCAqY3RybCwKKwkJCQkJIGludCBzZXQpCit7CisJdTMyIHdWYWx1 ZTsKKwlpbnQgcmV0ID0gMDsKKworCXdWYWx1ZSA9IGxlMTZfdG9fY3B1KGN0cmwtPndWYWx1ZSk7 CisKKwlzd2l0Y2ggKHdWYWx1ZSkgeworCWNhc2UgVVNCX0lOVFJGX0ZVTkNfU1VTUEVORDoKKwkJ YnJlYWs7CisJZGVmYXVsdDoKKwkJcmV0ID0gLUVJTlZBTDsKKwl9CisKKwlyZXR1cm4gcmV0Owor fQorCitzdGF0aWMgaW50IGNkbnMzX2VwMF9mZWF0dXJlX2hhbmRsZV9lbmRwb2ludChzdHJ1Y3Qg Y2RuczNfZGV2aWNlICpwcml2X2RldiwKKwkJCQkJICAgICBzdHJ1Y3QgdXNiX2N0cmxyZXF1ZXN0 ICpjdHJsLAorCQkJCQkgICAgIGludCBzZXQpCit7CisJc3RydWN0IGNkbnMzX2VuZHBvaW50ICpw cml2X2VwOworCWludCByZXQgPSAwOworCXU4IGluZGV4OworCisJaWYgKGxlMTZfdG9fY3B1KGN0 cmwtPndWYWx1ZSkgIT0gVVNCX0VORFBPSU5UX0hBTFQpCisJCXJldHVybiAtRUlOVkFMOworCisJ aWYgKCEoY3RybC0+d0luZGV4ICYgflVTQl9ESVJfSU4pKQorCQlyZXR1cm4gMDsKKworCWluZGV4 ID0gY2RuczNfZXBfYWRkcl90b19pbmRleChjdHJsLT53SW5kZXgpOworCXByaXZfZXAgPSBwcml2 X2Rldi0+ZXBzW2luZGV4XTsKKworCWNkbnMzX3NlbGVjdF9lcChwcml2X2RldiwgY3RybC0+d0lu ZGV4KTsKKworCWlmIChzZXQpIHsKKwkJd3JpdGVsKEVQX0NNRF9TU1RBTEwsICZwcml2X2Rldi0+ cmVncy0+ZXBfY21kKTsKKwkJcHJpdl9lcC0+ZmxhZ3MgfD0gRVBfU1RBTEw7CisJfSBlbHNlIHsK KwkJc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXF1ZXN0OworCisJCWlmIChwcml2X2Rldi0+ZXBzW2lu ZGV4XS0+ZmxhZ3MgJiBFUF9XRURHRSkgeworCQkJY2RuczNfc2VsZWN0X2VwKHByaXZfZGV2LCAw eDAwKTsKKwkJCXJldHVybiAwOworCQl9CisKKwkJd3JpdGVsKEVQX0NNRF9DU1RBTEwgfCBFUF9D TURfRVBSU1QsICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKKworCQkvKiB3YWl0IGZvciBFUFJT VCBjbGVhcmVkICovCisJCXJldCA9IGNkbnMzX2hhbmRzaGFrZSgmcHJpdl9kZXYtPnJlZ3MtPmVw X2NtZCwKKwkJCQkgICAgICBFUF9DTURfRVBSU1QsIDAsIDEwMCk7CisJCWlmIChyZXQpCisJCQly ZXR1cm4gLUVJTlZBTDsKKworCQlwcml2X2VwLT5mbGFncyAmPSB+RVBfU1RBTEw7CisKKwkJcmVx dWVzdCA9IGNkbnMzX25leHRfcmVxdWVzdCgmcHJpdl9lcC0+cmVxdWVzdF9saXN0KTsKKwkJaWYg KHJlcXVlc3QpCisJCQljZG5zM19lcF9ydW5fdHJhbnNmZXIocHJpdl9lcCwgcmVxdWVzdCk7CisJ fQorCXJldHVybiByZXQ7Cit9CisKKy8qKgorICogY2RuczNfcmVxX2VwMF9oYW5kbGVfZmVhdHVy ZSAtCisgKiBIYW5kbGluZyBvZiBHRVQvU0VUX0ZFQVRVUkUgc3RhbmRhcmQgVVNCIHJlcXVlc3QK KyAqCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBjdHJsX3JlcTog cG9pbnRlciB0byByZWNlaXZlZCBzZXR1cCBwYWNrZXQKKyAqIEBzZXQ6IG11c3QgYmUgc2V0IHRv IDEgZm9yIFNFVF9GRUFUVVJFIHJlcXVlc3QKKyAqCisgKiBSZXR1cm5zIDAgaWYgc3VjY2Vzcywg ZXJyb3IgY29kZSBvbiBlcnJvcgorICovCitzdGF0aWMgaW50IGNkbnMzX3JlcV9lcDBfaGFuZGxl X2ZlYXR1cmUoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYsCisJCQkJCXN0cnVjdCB1c2Jf Y3RybHJlcXVlc3QgKmN0cmwsCisJCQkJCWludCBzZXQpCit7CisJaW50IHJldCA9IDA7CisJdTMy IHJlY2lwOworCisJcmVjaXAgPSBjdHJsLT5iUmVxdWVzdFR5cGUgJiBVU0JfUkVDSVBfTUFTSzsK KworCXN3aXRjaCAocmVjaXApIHsKKwljYXNlIFVTQl9SRUNJUF9ERVZJQ0U6CisJCXJldCA9IGNk bnMzX2VwMF9mZWF0dXJlX2hhbmRsZV9kZXZpY2UocHJpdl9kZXYsIGN0cmwsIHNldCk7CisJCWJy ZWFrOworCWNhc2UgVVNCX1JFQ0lQX0lOVEVSRkFDRToKKwkJcmV0ID0gY2RuczNfZXAwX2ZlYXR1 cmVfaGFuZGxlX2ludGYocHJpdl9kZXYsIGN0cmwsIHNldCk7CisJCWJyZWFrOworCWNhc2UgVVNC X1JFQ0lQX0VORFBPSU5UOgorCQlyZXQgPSBjZG5zM19lcDBfZmVhdHVyZV9oYW5kbGVfZW5kcG9p bnQocHJpdl9kZXYsIGN0cmwsIHNldCk7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXJldHVybiAt RUlOVkFMOworCX0KKworCWlmICghcmV0KQorCQl3cml0ZWwoRVBfQ01EX0VSRFkgfCBFUF9DTURf UkVRX0NNUEwsICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKKworCXJldHVybiByZXQ7Cit9CisK Ky8qKgorICogY2RuczNfcmVxX2VwMF9zZXRfc2VsIC0gSGFuZGxpbmcgb2YgU0VUX1NFTCBzdGFu ZGFyZCBVU0IgcmVxdWVzdAorICogQHByaXZfZGV2OiBleHRlbmRlZCBnYWRnZXQgb2JqZWN0Cisg KiBAY3RybF9yZXE6IHBvaW50ZXIgdG8gcmVjZWl2ZWQgc2V0dXAgcGFja2V0CisgKgorICogUmV0 dXJucyAwIGlmIHN1Y2Nlc3MsIGVycm9yIGNvZGUgb24gZXJyb3IKKyAqLworc3RhdGljIGludCBj ZG5zM19yZXFfZXAwX3NldF9zZWwoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYsCisJCQkJ IHN0cnVjdCB1c2JfY3RybHJlcXVlc3QgKmN0cmxfcmVxKQoreworCWlmIChwcml2X2Rldi0+Z2Fk Z2V0LnN0YXRlIDwgVVNCX1NUQVRFX0FERFJFU1MpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYg KGN0cmxfcmVxLT53TGVuZ3RoICE9IDYpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAiU2V0 IFNFTCBzaG91bGQgYmUgNiBieXRlcywgZ290ICVkXG4iLAorCQkJY3RybF9yZXEtPndMZW5ndGgp OworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwljZG5zM19lcDBfcnVuX3RyYW5zZmVyKHByaXZf ZGV2LCBwcml2X2Rldi0+c2V0dXBfZG1hLCA2LCAxKTsKKwlyZXR1cm4gMDsKK30KKworLyoqCisg KiBjZG5zM19yZXFfZXAwX3NldF9pc29jaF9kZWxheSAtCisgKiBIYW5kbGluZyBvZiBHRVRfSVNP Q0hfREVMQVkgc3RhbmRhcmQgVVNCIHJlcXVlc3QKKyAqIEBwcml2X2RldjogZXh0ZW5kZWQgZ2Fk Z2V0IG9iamVjdAorICogQGN0cmxfcmVxOiBwb2ludGVyIHRvIHJlY2VpdmVkIHNldHVwIHBhY2tl dAorICoKKyAqIFJldHVybnMgMCBpZiBzdWNjZXNzLCBlcnJvciBjb2RlIG9uIGVycm9yCisgKi8K K3N0YXRpYyBpbnQgY2RuczNfcmVxX2VwMF9zZXRfaXNvY2hfZGVsYXkoc3RydWN0IGNkbnMzX2Rl dmljZSAqcHJpdl9kZXYsCisJCQkJCSBzdHJ1Y3QgdXNiX2N0cmxyZXF1ZXN0ICpjdHJsX3JlcSkK K3sKKwlpZiAoY3RybF9yZXEtPndJbmRleCB8fCBjdHJsX3JlcS0+d0xlbmd0aCkKKwkJcmV0dXJu IC1FSU5WQUw7CisKKwlwcml2X2Rldi0+aXNvY2hfZGVsYXkgPSBjdHJsX3JlcS0+d1ZhbHVlOwor CXdyaXRlbChFUF9DTURfRVJEWSB8IEVQX0NNRF9SRVFfQ01QTCwgJnByaXZfZGV2LT5yZWdzLT5l cF9jbWQpOworCXJldHVybiAwOworfQorCisvKioKKyAqIGNkbnMzX2VwMF9zdGFuZGFyZF9yZXF1 ZXN0IC0gSGFuZGxpbmcgc3RhbmRhcmQgVVNCIHJlcXVlc3RzCisgKiBAcHJpdl9kZXY6IGV4dGVu ZGVkIGdhZGdldCBvYmplY3QKKyAqIEBjdHJsX3JlcTogcG9pbnRlciB0byByZWNlaXZlZCBzZXR1 cCBwYWNrZXQKKyAqCisgKiBSZXR1cm5zIDAgaWYgc3VjY2VzcywgZXJyb3IgY29kZSBvbiBlcnJv cgorICovCitzdGF0aWMgaW50IGNkbnMzX2VwMF9zdGFuZGFyZF9yZXF1ZXN0KHN0cnVjdCBjZG5z M19kZXZpY2UgKnByaXZfZGV2LAorCQkJCSAgICAgIHN0cnVjdCB1c2JfY3RybHJlcXVlc3QgKmN0 cmxfcmVxKQoreworCWludCByZXQ7CisKKwlzd2l0Y2ggKGN0cmxfcmVxLT5iUmVxdWVzdCkgewor CWNhc2UgVVNCX1JFUV9TRVRfQUREUkVTUzoKKwkJcmV0ID0gY2RuczNfcmVxX2VwMF9zZXRfYWRk cmVzcyhwcml2X2RldiwgY3RybF9yZXEpOworCQlicmVhazsKKwljYXNlIFVTQl9SRVFfU0VUX0NP TkZJR1VSQVRJT046CisJCXJldCA9IGNkbnMzX3JlcV9lcDBfc2V0X2NvbmZpZ3VyYXRpb24ocHJp dl9kZXYsIGN0cmxfcmVxKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX0dFVF9TVEFUVVM6CisJ CXJldCA9IGNkbnMzX3JlcV9lcDBfZ2V0X3N0YXR1cyhwcml2X2RldiwgY3RybF9yZXEpOworCQli cmVhazsKKwljYXNlIFVTQl9SRVFfQ0xFQVJfRkVBVFVSRToKKwkJcmV0ID0gY2RuczNfcmVxX2Vw MF9oYW5kbGVfZmVhdHVyZShwcml2X2RldiwgY3RybF9yZXEsIDApOworCQlicmVhazsKKwljYXNl IFVTQl9SRVFfU0VUX0ZFQVRVUkU6CisJCXJldCA9IGNkbnMzX3JlcV9lcDBfaGFuZGxlX2ZlYXR1 cmUocHJpdl9kZXYsIGN0cmxfcmVxLCAxKTsKKwkJYnJlYWs7CisJY2FzZSBVU0JfUkVRX1NFVF9T RUw6CisJCXJldCA9IGNkbnMzX3JlcV9lcDBfc2V0X3NlbChwcml2X2RldiwgY3RybF9yZXEpOwor CQlicmVhazsKKwljYXNlIFVTQl9SRVFfU0VUX0lTT0NIX0RFTEFZOgorCQlyZXQgPSBjZG5zM19y ZXFfZXAwX3NldF9pc29jaF9kZWxheShwcml2X2RldiwgY3RybF9yZXEpOworCQlicmVhazsKKwlk ZWZhdWx0OgorCQlyZXQgPSBjZG5zM19lcDBfZGVsZWdhdGVfcmVxKHByaXZfZGV2LCBjdHJsX3Jl cSk7CisJCWJyZWFrOworCX0KKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyB2b2lkIF9fcGVu ZGluZ19zZXR1cF9zdGF0dXNfaGFuZGxlcihzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldikK K3sKKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3QgPSBwcml2X2Rldi0+cGVuZGluZ19zdGF0 dXNfcmVxdWVzdDsKKworCWlmIChwcml2X2Rldi0+c3RhdHVzX2NvbXBsZXRpb25fbm9fY2FsbCAm JiByZXF1ZXN0ICYmCisJICAgIHJlcXVlc3QtPmNvbXBsZXRlKSB7CisJCXJlcXVlc3QtPmNvbXBs ZXRlKHByaXZfZGV2LT5nYWRnZXQuZXAwLCByZXF1ZXN0KTsKKwkJcHJpdl9kZXYtPnN0YXR1c19j b21wbGV0aW9uX25vX2NhbGwgPSAwOworCX0KK30KKwordm9pZCBjZG5zM19wZW5kaW5nX3NldHVw X3N0YXR1c19oYW5kbGVyKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKK3sKKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldiA9IGNvbnRhaW5lcl9vZih3b3JrLCBzdHJ1Y3QgY2RuczNfZGV2 aWNlLAorCQkJcGVuZGluZ19zdGF0dXNfd3EpOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisKKwlz cGluX2xvY2tfaXJxc2F2ZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKwlfX3BlbmRpbmdfc2V0 dXBfc3RhdHVzX2hhbmRsZXIocHJpdl9kZXYpOworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnBy aXZfZGV2LT5sb2NrLCBmbGFncyk7Cit9CisKKy8qKgorICogY2RuczNfZ2FkZ2V0X2VwX2dpdmVi YWNrIC0gY2FsbCBzdHJ1Y3QgdXNiX3JlcXVlc3QncyAtPmNvbXBsZXRlIGNhbGxiYWNrCisgKiBA cHJpdl9lcDogVGhlIGVuZHBvaW50IHRvIHdob20gdGhlIHJlcXVlc3QgYmVsb25ncyB0bworICog QHByaXZfcmVxOiBUaGUgcmVxdWVzdCB3ZSdyZSBnaXZpbmcgYmFjaworICogQHN0YXR1czogY29t cGxldGlvbiBjb2RlIGZvciB0aGUgcmVxdWVzdAorICoKKyAqIE11c3QgYmUgY2FsbGVkIHdpdGgg Y29udHJvbGxlcidzIGxvY2sgaGVsZCBhbmQgaW50ZXJydXB0cyBkaXNhYmxlZC4gVGhpcworICog ZnVuY3Rpb24gd2lsbCB1bm1hcCBAcmVxIGFuZCBjYWxsIGl0cyAtPmNvbXBsZXRlKCkgY2FsbGJh Y2sgdG8gbm90aWZ5IHVwcGVyCisgKiBsYXllcnMgdGhhdCBpdCBoYXMgY29tcGxldGVkLgorICov CisKK3ZvaWQgY2RuczNfZ2FkZ2V0X2VwMF9naXZlYmFjayhzdHJ1Y3QgY2RuczNfZGV2aWNlICpw cml2X2RldiwKKwkJCSAgICAgICBpbnQgc3RhdHVzKQoreworCXN0cnVjdCBjZG5zM19lbmRwb2lu dCAqcHJpdl9lcDsKKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3Q7CisKKwlwcml2X2VwID0g ZXBfdG9fY2RuczNfZXAocHJpdl9kZXYtPmdhZGdldC5lcDApOworCXJlcXVlc3QgPSBjZG5zM19u ZXh0X3JlcXVlc3QoJnByaXZfZXAtPnJlcXVlc3RfbGlzdCk7CisKKwlwcml2X2VwLT5kaXIgPSBw cml2X2Rldi0+ZXAwX2RhdGFfZGlyOworCWNkbnMzX2dhZGdldF9naXZlYmFjayhwcml2X2VwLCB0 b19jZG5zM19yZXF1ZXN0KHJlcXVlc3QpLCBzdGF0dXMpOworCXByaXZfZGV2LT5lcDBfcmVxdWVz dCA9IE5VTEw7Cit9CisKKy8qKgorICogY2RuczNfZXAwX3NldHVwX3BoYXNlIC0gSGFuZGxpbmcg c2V0dXAgVVNCIHJlcXVlc3RzCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmplY3QK KyAqLworc3RhdGljIHZvaWQgY2RuczNfZXAwX3NldHVwX3BoYXNlKHN0cnVjdCBjZG5zM19kZXZp Y2UgKnByaXZfZGV2KQoreworCXN0cnVjdCB1c2JfY3RybHJlcXVlc3QgKmN0cmwgPSBwcml2X2Rl di0+c2V0dXBfYnVmOworCXN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcDsKKwlpbnQgcmVz dWx0OworCisJcHJpdl9kZXYtPmVwMF9kYXRhX2RpciA9IGN0cmwtPmJSZXF1ZXN0VHlwZSAmIFVT Ql9ESVJfSU47CisJcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKHByaXZfZGV2LT5nYWRnZXQuZXAw KTsKKworCXRyYWNlX2NkbnMzX2N0cmxfcmVxKGN0cmwpOworCisJaWYgKCFsaXN0X2VtcHR5KCZw cml2X2VwLT5yZXF1ZXN0X2xpc3QpKQorCQljZG5zM19nYWRnZXRfZXAwX2dpdmViYWNrKHByaXZf ZGV2LCAtRUNPTk5SRVNFVCk7CisKKwlpZiAoKGN0cmwtPmJSZXF1ZXN0VHlwZSAmIFVTQl9UWVBF X01BU0spID09IFVTQl9UWVBFX1NUQU5EQVJEKQorCQlyZXN1bHQgPSBjZG5zM19lcDBfc3RhbmRh cmRfcmVxdWVzdChwcml2X2RldiwgY3RybCk7CisJZWxzZQorCQlyZXN1bHQgPSBjZG5zM19lcDBf ZGVsZWdhdGVfcmVxKHByaXZfZGV2LCBjdHJsKTsKKworCWlmIChyZXN1bHQgIT0gMCAmJiByZXN1 bHQgIT0gVVNCX0dBREdFVF9ERUxBWUVEX1NUQVRVUykgeworCQlkZXZfZGJnKHByaXZfZGV2LT5k ZXYsICJTVEFMTCBmb3IgZXAwXG4iKTsKKwkJLyogc2V0X3N0YWxsIG9uIGVwMCAqLworCQljZG5z M19zZWxlY3RfZXAocHJpdl9kZXYsIDB4MDApOworCQl3cml0ZWwoRVBfQ01EX1NTVEFMTCwgJnBy aXZfZGV2LT5yZWdzLT5lcF9jbWQpOworCQl3cml0ZWwoRVBfQ01EX0VSRFkgfCBFUF9DTURfUkVR X0NNUEwsICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKKwl9Cit9CisKK3N0YXRpYyB2b2lkIGNk bnMzX3RyYW5zZmVyX2NvbXBsZXRlZChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldikKK3sK KwlzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAgPSBlcF90b19jZG5zM19lcChwcml2X2Rl di0+Z2FkZ2V0LmVwMCk7CisKKwlpZiAocHJpdl9kZXYtPmVwMF9yZXF1ZXN0KSB7CisJCXRyYWNl X2NkbnMzX2NvbXBsZXRlX3RyYihwcml2X2VwLCBwcml2X2Rldi0+ZXAwX3RyYik7CisKKwkJcHJp dl9kZXYtPmVwMF9yZXF1ZXN0LT5hY3R1YWwgPQorCQkJVFJCX0xFTihsZTMyX3RvX2NwdShwcml2 X2Rldi0+ZXAwX3RyYi0+bGVuZ3RoKSk7CisKKwkJY2RuczNfZ2FkZ2V0X2VwMF9naXZlYmFjayhw cml2X2RldiwgMCk7CisJfQorCisJY2RuczNfcHJlcGFyZV9zZXR1cF9wYWNrZXQocHJpdl9kZXYp OworCXdyaXRlbChFUF9DTURfUkVRX0NNUEwsICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKK30K KworLyoqCisgKiBjZG5zM19jaGVja19uZXdfc2V0dXAgLSBDaGVjayBpZiBjb250cm9sbGVyIHJl Y2VpdmUgbmV3IFNFVFVQIHBhY2tldC4KKyAqIEBwcml2X2RldjogZXh0ZW5kZWQgZ2FkZ2V0IG9i amVjdAorICoKKyAqIFRoZSBTRVRVUCBwYWNrZXQgY2FuIGJlIGtlcHQgaW4gb24tY2hpcCBtZW1v cnkgb3IgaW4gc3lzdGVtIG1lbW9yeS4KKyAqLworc3RhdGljIGJvb2wgY2RuczNfY2hlY2tfbmV3 X3NldHVwKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2KQoreworCXUzMiBlcF9zdHNfcmVn OworCisJY2RuczNfc2VsZWN0X2VwKHByaXZfZGV2LCAwIHwgVVNCX0RJUl9PVVQpOworCWVwX3N0 c19yZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPmVwX3N0cyk7CisKKwlyZXR1cm4gISEoZXBf c3RzX3JlZyAmIChFUF9TVFNfU0VUVVAgfCBFUF9TVFNfU1RQV0FJVCkpOworfQorCisvKioKKyAq IGNkbnMzX2NoZWNrX2VwMF9pbnRlcnJ1cHRfcHJvY2VlZCAtIFByb2Nlc3NlcyBpbnRlcnJ1cHQg cmVsYXRlZCB0byBlbmRwb2ludCAwCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmpl Y3QKKyAqIEBkaXI6IFVTQl9ESVJfSU4gZm9yIElOIGRpcmVjdGlvbiwgVVNCX0RJUl9PVVQgZm9y IE9VVCBkaXJlY3Rpb24KKyAqLwordm9pZCBjZG5zM19jaGVja19lcDBfaW50ZXJydXB0X3Byb2Nl ZWQoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYsIGludCBkaXIpCit7CisJdTMyIGVwX3N0 c19yZWc7CisKKwljZG5zM19zZWxlY3RfZXAocHJpdl9kZXYsIGRpcik7CisKKwllcF9zdHNfcmVn ID0gcmVhZGwoJnByaXZfZGV2LT5yZWdzLT5lcF9zdHMpOworCXdyaXRlbChlcF9zdHNfcmVnLCAm cHJpdl9kZXYtPnJlZ3MtPmVwX3N0cyk7CisKKwl0cmFjZV9jZG5zM19lcDBfaXJxKHByaXZfZGV2 KTsKKworCV9fcGVuZGluZ19zZXR1cF9zdGF0dXNfaGFuZGxlcihwcml2X2Rldik7CisKKwlpZiAo KGVwX3N0c19yZWcgJiBFUF9TVFNfU0VUVVApKSB7CisJCWNkbnMzX2VwMF9zZXR1cF9waGFzZShw cml2X2Rldik7CisJfSBlbHNlIGlmICgoZXBfc3RzX3JlZyAmIEVQX1NUU19JT0MpIHx8IChlcF9z dHNfcmVnICYgRVBfU1RTX0lTUCkpIHsKKwkJcHJpdl9kZXYtPmVwMF9kYXRhX2RpciA9IGRpcjsK KwkJY2RuczNfdHJhbnNmZXJfY29tcGxldGVkKHByaXZfZGV2KTsKKwl9CisKKwlpZiAoZXBfc3Rz X3JlZyAmIEVQX1NUU19ERVNDTUlTKSB7CisJCWlmIChkaXIgPT0gMCAmJiAhcHJpdl9kZXYtPnNl dHVwX3BlbmRpbmcpCisJCQljZG5zM19wcmVwYXJlX3NldHVwX3BhY2tldChwcml2X2Rldik7CisJ fQorfQorCisvKioKKyAqIGNkbnMzX2dhZGdldF9lcDBfZW5hYmxlCisgKiBGdW5jdGlvbiBzaG91 bGRuJ3QgYmUgY2FsbGVkIGJ5IGdhZGdldCBkcml2ZXIsCisgKiBlbmRwb2ludCAwIGlzIGFsbHdh eXMgYWN0aXZlCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfZ2FkZ2V0X2VwMF9lbmFibGUoc3RydWN0 IHVzYl9lcCAqZXAsCisJCQkJICAgY29uc3Qgc3RydWN0IHVzYl9lbmRwb2ludF9kZXNjcmlwdG9y ICpkZXNjKQoreworCXJldHVybiAtRUlOVkFMOworfQorCisvKioKKyAqIGNkbnMzX2dhZGdldF9l cDBfZGlzYWJsZQorICogRnVuY3Rpb24gc2hvdWxkbid0IGJlIGNhbGxlZCBieSBnYWRnZXQgZHJp dmVyLAorICogZW5kcG9pbnQgMCBpcyBhbGx3YXlzIGFjdGl2ZQorICovCitzdGF0aWMgaW50IGNk bnMzX2dhZGdldF9lcDBfZGlzYWJsZShzdHJ1Y3QgdXNiX2VwICplcCkKK3sKKwlyZXR1cm4gLUVJ TlZBTDsKK30KKworLyoqCisgKiBjZG5zM19nYWRnZXRfZXAwX3NldF9oYWx0CisgKiBAZXA6IHBv aW50ZXIgdG8gZW5kcG9pbnQgemVybyBvYmplY3QKKyAqIEB2YWx1ZTogMSBmb3Igc2V0IHN0YWxs LCAwIGZvciBjbGVhciBzdGFsbAorICoKKyAqIFJldHVybnMgMAorICovCitzdGF0aWMgaW50IGNk bnMzX2dhZGdldF9lcDBfc2V0X2hhbHQoc3RydWN0IHVzYl9lcCAqZXAsIGludCB2YWx1ZSkKK3sK KwkvKiBUT0RPICovCisJcmV0dXJuIDA7Cit9CisKKy8qKgorICogY2RuczNfZ2FkZ2V0X2VwMF9x dWV1ZSBUcmFuc2ZlciBkYXRhIG9uIGVuZHBvaW50IHplcm8KKyAqIEBlcDogcG9pbnRlciB0byBl bmRwb2ludCB6ZXJvIG9iamVjdAorICogQHJlcXVlc3Q6IHBvaW50ZXIgdG8gcmVxdWVzdCBvYmpl Y3QKKyAqIEBnZnBfZmxhZ3M6IGdmcCBmbGFncworICoKKyAqIFJldHVybnMgMCBvbiBzdWNjZXNz LCBlcnJvciBjb2RlIGVsc2V3aGVyZQorICovCitzdGF0aWMgaW50IGNkbnMzX2dhZGdldF9lcDBf cXVldWUoc3RydWN0IHVzYl9lcCAqZXAsCisJCQkJICBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVl c3QsCisJCQkJICBnZnBfdCBnZnBfZmxhZ3MpCit7CisJc3RydWN0IGNkbnMzX2VuZHBvaW50ICpw cml2X2VwID0gZXBfdG9fY2RuczNfZXAoZXApOworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZf ZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJaW50IGVy ZHlfc2VudCA9IDA7CisJaW50IHJldCA9IDA7CisKKwlkZXZfZGJnKHByaXZfZGV2LT5kZXYsICJR dWV1ZSB0byBFcDAlcyBMOiAlZFxuIiwKKwkJcHJpdl9kZXYtPmVwMF9kYXRhX2RpciA/ICJJTiIg OiAiT1VUIiwKKwkJcmVxdWVzdC0+bGVuZ3RoKTsKKworCS8qIGNhbmNlbCB0aGUgcmVxdWVzdCBp ZiBjb250cm9sbGVyIHJlY2VpdmUgbmV3IFNFVFVQIHBhY2tldC4gKi8KKwlpZiAoY2RuczNfY2hl Y2tfbmV3X3NldHVwKHByaXZfZGV2KSkKKwkJcmV0dXJuIC1FQ09OTlJFU0VUOworCisJLyogc2Vu ZCBTVEFUVVMgc3RhZ2UuIFNob3VsZCBiZSBjYWxsZWQgb25seSBmb3IgU0VUX0NPTkZJR1VSQVRJ T04gKi8KKwlpZiAocmVxdWVzdC0+bGVuZ3RoID09IDAgJiYgcmVxdWVzdC0+emVybyA9PSAwKSB7 CisJCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCQljZG5zM19z ZWxlY3RfZXAocHJpdl9kZXYsIDB4MDApOworCisJCWVyZHlfc2VudCA9ICFwcml2X2Rldi0+aHdf Y29uZmlndXJlZF9mbGFnOworCQljZG5zM19zZXRfaHdfY29uZmlndXJhdGlvbihwcml2X2Rldik7 CisKKwkJaWYgKCFlcmR5X3NlbnQpCisJCQl3cml0ZWwoRVBfQ01EX0VSRFkgfCBFUF9DTURfUkVR X0NNUEwsCisJCQkgICAgICAgJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQpOworCisJCWNkbnMzX3By ZXBhcmVfc2V0dXBfcGFja2V0KHByaXZfZGV2KTsKKwkJcmVxdWVzdC0+YWN0dWFsID0gMDsKKwkJ cHJpdl9kZXYtPnN0YXR1c19jb21wbGV0aW9uX25vX2NhbGwgPSB0cnVlOworCQlwcml2X2Rldi0+ cGVuZGluZ19zdGF0dXNfcmVxdWVzdCA9IHJlcXVlc3Q7CisJCXNwaW5fdW5sb2NrX2lycXJlc3Rv cmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisKKwkJLyoKKwkJICogU2luY2UgdGhlcmUgaXMg bm8gY29tcGxldGlvbiBpbnRlcnJ1cHQgZm9yIHN0YXR1cyBzdGFnZSwKKwkJICogaXQgbmVlZHMg dG8gY2FsbCAtPmNvbXBsZXRpb24gaW4gc29mdHdhcmUgYWZ0ZXIKKwkJICogZXAwX3F1ZXVlIGlz IGJhY2suCisJCSAqLworCQlxdWV1ZV93b3JrKHN5c3RlbV9mcmVlemFibGVfd3EsICZwcml2X2Rl di0+cGVuZGluZ19zdGF0dXNfd3EpOworCQlyZXR1cm4gMDsKKwl9CisKKwlzcGluX2xvY2tfaXJx c2F2ZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKwlpZiAoIWxpc3RfZW1wdHkoJnByaXZfZXAt PnJlcXVlc3RfbGlzdCkpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LAorCQkJImNhbid0IGhh bmRsZSBtdWx0aXBsZSByZXF1ZXN0cyBmb3IgZXAwXG4iKTsKKwkJc3Bpbl91bmxvY2tfaXJxcmVz dG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKwkJcmV0dXJuIC1FQlVTWTsKKwl9CisKKwly ZXQgPSB1c2JfZ2FkZ2V0X21hcF9yZXF1ZXN0X2J5X2Rldihwcml2X2Rldi0+c3lzZGV2LCByZXF1 ZXN0LAorCQkJCQkgICAgcHJpdl9kZXYtPmVwMF9kYXRhX2Rpcik7CisJaWYgKHJldCkgeworCQlz cGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCQlkZXZfZXJy KHByaXZfZGV2LT5kZXYsICJmYWlsZWQgdG8gbWFwIHJlcXVlc3RcbiIpOworCQlyZXR1cm4gLUVJ TlZBTDsKKwl9CisKKwlyZXF1ZXN0LT5zdGF0dXMgPSAtRUlOUFJPR1JFU1M7CisJcHJpdl9kZXYt PmVwMF9yZXF1ZXN0ID0gcmVxdWVzdDsKKwlsaXN0X2FkZF90YWlsKCZyZXF1ZXN0LT5saXN0LCAm cHJpdl9lcC0+cmVxdWVzdF9saXN0KTsKKwljZG5zM19lcDBfcnVuX3RyYW5zZmVyKHByaXZfZGV2 LCByZXF1ZXN0LT5kbWEsIHJlcXVlc3QtPmxlbmd0aCwgMSk7CisJc3Bpbl91bmxvY2tfaXJxcmVz dG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKworCXJldHVybiByZXQ7Cit9CisKKy8qKgor ICogY2RuczNfZ2FkZ2V0X2VwX3NldF93ZWRnZSBTZXQgd2VkZ2Ugb24gc2VsZWN0ZWQgZW5kcG9p bnQKKyAqIEBlcDogZW5kcG9pbnQgb2JqZWN0CisgKgorICogUmV0dXJucyAwCisgKi8KK2ludCBj ZG5zM19nYWRnZXRfZXBfc2V0X3dlZGdlKHN0cnVjdCB1c2JfZXAgKmVwKQoreworCXN0cnVjdCBj ZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsKKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKworCWRldl9kYmcocHJp dl9kZXYtPmRldiwgIldlZGdlIGZvciAlc1xuIiwgZXAtPm5hbWUpOworCWNkbnMzX2dhZGdldF9l cF9zZXRfaGFsdChlcCwgMSk7CisJcHJpdl9lcC0+ZmxhZ3MgfD0gRVBfV0VER0U7CisKKwlyZXR1 cm4gMDsKK30KKworY29uc3Qgc3RydWN0IHVzYl9lcF9vcHMgY2RuczNfZ2FkZ2V0X2VwMF9vcHMg PSB7CisJLmVuYWJsZSA9IGNkbnMzX2dhZGdldF9lcDBfZW5hYmxlLAorCS5kaXNhYmxlID0gY2Ru czNfZ2FkZ2V0X2VwMF9kaXNhYmxlLAorCS5hbGxvY19yZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2Vw X2FsbG9jX3JlcXVlc3QsCisJLmZyZWVfcmVxdWVzdCA9IGNkbnMzX2dhZGdldF9lcF9mcmVlX3Jl cXVlc3QsCisJLnF1ZXVlID0gY2RuczNfZ2FkZ2V0X2VwMF9xdWV1ZSwKKwkuZGVxdWV1ZSA9IGNk bnMzX2dhZGdldF9lcF9kZXF1ZXVlLAorCS5zZXRfaGFsdCA9IGNkbnMzX2dhZGdldF9lcDBfc2V0 X2hhbHQsCisJLnNldF93ZWRnZSA9IGNkbnMzX2dhZGdldF9lcF9zZXRfd2VkZ2UsCit9OworCisv KioKKyAqIGNkbnMzX2VwMF9jb25maWcgLSBDb25maWd1cmVzIGRlZmF1bHQgZW5kcG9pbnQKKyAq IEBwcml2X2RldjogZXh0ZW5kZWQgZ2FkZ2V0IG9iamVjdAorICoKKyAqIEZ1bmN0aW9ucyBzZXRz IHBhcmFtZXRlcnM6IG1heGltYWwgcGFja2V0IHNpemUgYW5kIGVuYWJsZXMgaW50ZXJydXB0cwor ICovCit2b2lkIGNkbnMzX2VwMF9jb25maWcoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYp Cit7CisJc3RydWN0IGNkbnMzX3VzYl9yZWdzIF9faW9tZW0gKnJlZ3M7CisJdTMyIG1heF9wYWNr ZXRfc2l6ZSA9IDY0OworCisJcmVncyA9IHByaXZfZGV2LT5yZWdzOworCisJaWYgKHByaXZfZGV2 LT5nYWRnZXQuc3BlZWQgPT0gVVNCX1NQRUVEX1NVUEVSKQorCQltYXhfcGFja2V0X3NpemUgPSA1 MTI7CisKKwlpZiAocHJpdl9kZXYtPmVwMF9yZXF1ZXN0KSB7CisJCWxpc3RfZGVsX2luaXQoJnBy aXZfZGV2LT5lcDBfcmVxdWVzdC0+bGlzdCk7CisJCXByaXZfZGV2LT5lcDBfcmVxdWVzdCA9IE5V TEw7CisJfQorCisJcHJpdl9kZXYtPnUxX2FsbG93ZWQgPSAwOworCXByaXZfZGV2LT51Ml9hbGxv d2VkID0gMDsKKworCXByaXZfZGV2LT5nYWRnZXQuZXAwLT5tYXhwYWNrZXQgPSBtYXhfcGFja2V0 X3NpemU7CisJY2RuczNfZ2FkZ2V0X2VwMF9kZXNjLndNYXhQYWNrZXRTaXplID0gY3B1X3RvX2xl MTYobWF4X3BhY2tldF9zaXplKTsKKworCS8qIGluaXQgZXAgb3V0ICovCisJY2RuczNfc2VsZWN0 X2VwKHByaXZfZGV2LCBVU0JfRElSX09VVCk7CisKKwl3cml0ZWwoRVBfQ0ZHX0VOQUJMRSB8IEVQ X0NGR19NQVhQS1RTSVpFKG1heF9wYWNrZXRfc2l6ZSksCisJICAgICAgICZyZWdzLT5lcF9jZmcp OworCisJd3JpdGVsKEVQX1NUU19FTl9TRVRVUEVOIHwgRVBfU1RTX0VOX0RFU0NNSVNFTiB8IEVQ X1NUU19FTl9UUkJFUlJFTiwKKwkgICAgICAgJnJlZ3MtPmVwX3N0c19lbik7CisKKwkvKiBpbml0 IGVwIGluICovCisJY2RuczNfc2VsZWN0X2VwKHByaXZfZGV2LCBVU0JfRElSX0lOKTsKKworCXdy aXRlbChFUF9DRkdfRU5BQkxFIHwgRVBfQ0ZHX01BWFBLVFNJWkUobWF4X3BhY2tldF9zaXplKSwK KwkgICAgICAgJnJlZ3MtPmVwX2NmZyk7CisKKwl3cml0ZWwoRVBfU1RTX0VOX1NFVFVQRU4gfCBF UF9TVFNfRU5fVFJCRVJSRU4sICZyZWdzLT5lcF9zdHNfZW4pOworCisJY2RuczNfc2V0X3JlZ2lz dGVyX2JpdCgmcmVncy0+dXNiX2NvbmYsIFVTQl9DT05GX1UxRFMgfCBVU0JfQ09ORl9VMkRTKTsK KwljZG5zM19wcmVwYXJlX3NldHVwX3BhY2tldChwcml2X2Rldik7Cit9CisKKy8qKgorICogY2Ru czNfaW5pdF9lcDAgSW5pdGlhbGl6ZXMgc29mdHdhcmUgZW5kcG9pbnQgMCBvZiBnYWRnZXQKKyAq IEBjZG5zMzogZXh0ZW5kZWQgZ2FkZ2V0IG9iamVjdAorICoKKyAqIFJldHVybnMgMCBvbiBzdWNj ZXNzLCBlcnJvciBjb2RlIGVsc2V3aGVyZQorICovCitpbnQgY2RuczNfaW5pdF9lcDAoc3RydWN0 IGNkbnMzX2RldmljZSAqcHJpdl9kZXYpCit7CisJc3RydWN0IGNkbnMzX2VuZHBvaW50ICplcDA7 CisKKwllcDAgPSBkZXZtX2t6YWxsb2MocHJpdl9kZXYtPmRldiwgc2l6ZW9mKHN0cnVjdCBjZG5z M19lbmRwb2ludCksCisJCQkgICBHRlBfS0VSTkVMKTsKKworCWlmICghZXAwKQorCQlyZXR1cm4g LUVOT01FTTsKKworCWVwMC0+Y2RuczNfZGV2ID0gcHJpdl9kZXY7CisJc3ByaW50ZihlcDAtPm5h bWUsICJlcDAiKTsKKworCS8qIGZpbGwgbGludXggZmllbGRzICovCisJZXAwLT5lbmRwb2ludC5v cHMgPSAmY2RuczNfZ2FkZ2V0X2VwMF9vcHM7CisJZXAwLT5lbmRwb2ludC5tYXhidXJzdCA9IDE7 CisJdXNiX2VwX3NldF9tYXhwYWNrZXRfbGltaXQoJmVwMC0+ZW5kcG9pbnQsIENETlMzX0VQMF9N QVhfUEFDS0VUX0xJTUlUKTsKKwllcDAtPmVuZHBvaW50LmFkZHJlc3MgPSAwOworCWVwMC0+ZW5k cG9pbnQuY2Fwcy50eXBlX2NvbnRyb2wgPSAxOworCWVwMC0+ZW5kcG9pbnQuY2Fwcy5kaXJfaW4g PSAxOworCWVwMC0+ZW5kcG9pbnQuY2Fwcy5kaXJfb3V0ID0gMTsKKwllcDAtPmVuZHBvaW50Lm5h bWUgPSBlcDAtPm5hbWU7CisJZXAwLT5lbmRwb2ludC5kZXNjID0gJmNkbnMzX2dhZGdldF9lcDBf ZGVzYzsKKwlwcml2X2Rldi0+Z2FkZ2V0LmVwMCA9ICZlcDAtPmVuZHBvaW50OworCUlOSVRfTElT VF9IRUFEKCZlcDAtPnJlcXVlc3RfbGlzdCk7CisKKwlyZXR1cm4gMDsKK30KZGlmZiAtLWdpdCBh L2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1leHBvcnQuaCBiL2RyaXZlcnMvdXNiL2NkbnMzL2dh ZGdldC1leHBvcnQuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLjU3 NzQ2OWVlZTk2MQotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC1l eHBvcnQuaApAQCAtMCwwICsxLDI4IEBACisvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BM LTIuMCAqLworLyoKKyAqIENhZGVuY2UgVVNCU1MgRFJEIERyaXZlciAtIEdhZGdldCBFeHBvcnQg QVBJcy4KKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTcgTlhQCisgKiBDb3B5cmlnaHQgKEMpIDIw MTctMjAxOCBOWFAKKyAqCisgKiBBdXRob3JzOiBQZXRlciBDaGVuIDxwZXRlci5jaGVuQG54cC5j b20+CisgKi8KKyNpZm5kZWYgX19MSU5VWF9DRE5TM19HQURHRVRfRVhQT1JUCisjZGVmaW5lIF9f TElOVVhfQ0ROUzNfR0FER0VUX0VYUE9SVAorCisjaWZkZWYgQ09ORklHX1VTQl9DRE5TM19HQURH RVQKKworaW50IGNkbnMzX2dhZGdldF9pbml0KHN0cnVjdCBjZG5zMyAqY2Rucyk7Cit2b2lkIGNk bnMzX2dhZGdldF9leGl0KHN0cnVjdCBjZG5zMyAqY2Rucyk7CisjZWxzZQorCitzdGF0aWMgaW5s aW5lIGludCBjZG5zM19nYWRnZXRfaW5pdChzdHJ1Y3QgY2RuczMgKmNkbnMpCit7CisJcmV0dXJu IC1FTlhJTzsKK30KKworc3RhdGljIGlubGluZSB2b2lkIGNkbnMzX2dhZGdldF9leGl0KHN0cnVj dCBjZG5zMyAqY2RucykgeyB9CisKKyNlbmRpZgorCisjZW5kaWYgLyogX19MSU5VWF9DRE5TM19H QURHRVRfRVhQT1JUICovCmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9nYWRnZXQuYyBi L2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAw MDAwMDAwMDAwMC4uYTAyMWVhZjA3YWVlCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy91c2Iv Y2RuczMvZ2FkZ2V0LmMKQEAgLTAsMCArMSwxODAyIEBACisvLyBTUERYLUxpY2Vuc2UtSWRlbnRp ZmllcjogR1BMLTIuMAorLyoKKyAqIENhZGVuY2UgVVNCU1MgRFJEIERyaXZlciAtIGdhZGdldCBz aWRlLgorICoKKyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNlIERlc2lnbiBTeXN0ZW1zLgor ICogQ29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCisgKgorICogQXV0aG9yczogUGF3ZWwgSmV6 IDxwamV6QGNhZGVuY2UuY29tPiwKKyAqICAgICAgICAgIFBhd2VsIExhc3pjemFrIDxwYXdlbGxA Y2FkZW5jZS5jb20+CisgKgkgICAgUGV0ZXIgQ2hlbiA8cGV0ZXIuY2hlbkBueHAuY29tPgorICov CisKKyNpbmNsdWRlIDxsaW51eC9kbWEtbWFwcGluZy5oPgorI2luY2x1ZGUgPGxpbnV4L3VzYi9n YWRnZXQuaD4KKworI2luY2x1ZGUgImNvcmUuaCIKKyNpbmNsdWRlICJnYWRnZXQtZXhwb3J0Lmgi CisjaW5jbHVkZSAiZ2FkZ2V0LmgiCisKKyNpbmNsdWRlICJ0cmFjZS5oIgorCitzdGF0aWMgaW50 IF9fY2RuczNfZ2FkZ2V0X2VwX3F1ZXVlKHN0cnVjdCB1c2JfZXAgKmVwLAorCQkJCSAgIHN0cnVj dCB1c2JfcmVxdWVzdCAqcmVxdWVzdCwKKwkJCQkgICBnZnBfdCBnZnBfZmxhZ3MpOworCisvKioK KyAqIGNkbnMzX2hhbmRzaGFrZSAtIHNwaW4gcmVhZGluZyAgdW50aWwgaGFuZHNoYWtlIGNvbXBs ZXRlcyBvciBmYWlscworICogQHB0cjogYWRkcmVzcyBvZiBkZXZpY2UgY29udHJvbGxlciByZWdp c3RlciB0byBiZSByZWFkCisgKiBAbWFzazogYml0cyB0byBsb29rIGF0IGluIHJlc3VsdCBvZiBy ZWFkCisgKiBAZG9uZTogdmFsdWUgb2YgdGhvc2UgYml0cyB3aGVuIGhhbmRzaGFrZSBzdWNjZWVk cworICogQHVzZWM6IHRpbWVvdXQgaW4gbWljcm9zZWNvbmRzCisgKgorICogUmV0dXJucyBuZWdh dGl2ZSBlcnJubywgb3IgemVybyBvbiBzdWNjZXNzCisgKgorICogU3VjY2VzcyBoYXBwZW5zIHdo ZW4gdGhlICJtYXNrIiBiaXRzIGhhdmUgdGhlIHNwZWNpZmllZCB2YWx1ZSAoaGFyZHdhcmUKKyAq IGhhbmRzaGFrZSBkb25lKS4gVGhlcmUgYXJlIHR3byBmYWlsdXJlIG1vZGVzOiAidXNlYyIgaGF2 ZSBwYXNzZWQgKG1ham9yCisgKiBoYXJkd2FyZSBmbGFrZW91dCksIG9yIHRoZSByZWdpc3RlciBy ZWFkcyBhcyBhbGwtb25lcyAoaGFyZHdhcmUgcmVtb3ZlZCkuCisgKi8KK2ludCBjZG5zM19oYW5k c2hha2Uodm9pZCBfX2lvbWVtICpwdHIsIHUzMiBtYXNrLCB1MzIgZG9uZSwgaW50IHVzZWMpCit7 CisJdTMyCXJlc3VsdDsKKworCWRvIHsKKwkJcmVzdWx0ID0gcmVhZGwocHRyKTsKKwkJaWYgKHJl c3VsdCA9PSB+KHUzMikwKQkvKiBjYXJkIHJlbW92ZWQgKi8KKwkJCXJldHVybiAtRU5PREVWOwor CQlyZXN1bHQgJj0gbWFzazsKKwkJaWYgKHJlc3VsdCA9PSBkb25lKQorCQkJcmV0dXJuIDA7CisJ CXVkZWxheSgxKTsKKwkJdXNlYy0tOworCX0gd2hpbGUgKHVzZWMgPiAwKTsKKwlyZXR1cm4gLUVU SU1FRE9VVDsKK30KKworLyoqCisgKiBjZG5zM19zZXRfcmVnaXN0ZXJfYml0IC0gc2V0IGJpdCBp biBnaXZlbiByZWdpc3Rlci4KKyAqIEBwdHI6IGFkZHJlc3Mgb2YgZGV2aWNlIGNvbnRyb2xsZXIg cmVnaXN0ZXIgdG8gYmUgcmVhZCBhbmQgY2hhbmdlZAorICogQG1hc2s6IGJpdHMgcmVxdWVzdGVk IHRvIHNldAorICovCit2b2lkIGNkbnMzX3NldF9yZWdpc3Rlcl9iaXQodm9pZCBfX2lvbWVtICpw dHIsIHUzMiBtYXNrKQoreworCW1hc2sgPSByZWFkbChwdHIpIHwgbWFzazsKKwl3cml0ZWwobWFz aywgcHRyKTsKK30KKworLyoqCisgKiBjZG5zM19lcF9yZWdfcG9zX3RvX2luZGV4IC0gTWFjcm8g Y29udmVydHMgYml0IHBvc2l0aW9uIG9mIGVwX2lzdHMgcmVnaXN0ZXIKKyAqIHRvIGluZGV4IG9m IGVuZHBvaW50IG9iamVjdCBpbiBjZG5zM19kZXZpY2UuZXBzW10gY29udGFpbmVyCisgKiBAaTog Yml0IHBvc2l0aW9uIG9mIGVuZHBvaW50IGZvciB3aGljaCBlbmRwb2ludCBvYmplY3QgaXMgcmVx dWlyZWQKKyAqCisgKiBSZW1lbWJlciB0aGF0IGVuZHBvaW50IGNvbnRhaW5lciBkb2Vzbid0IGNv bnRhaW4gZGVmYXVsdCBlbmRwb2ludAorICovCitzdGF0aWMgdTggY2RuczNfZXBfcmVnX3Bvc190 b19pbmRleChpbnQgaSkKK3sKKwlyZXR1cm4gKChpIC8gMTYpICsgKCgoaSAlIDE2KSAtIDIpICog MikpOworfQorCisvKioKKyAqIGNkbnMzX2VwX2FkZHJfdG9faW5kZXggLSBNYWNybyBjb252ZXJ0 cyBlbmRwb2ludCBhZGRyZXNzIHRvCisgKiBpbmRleCBvZiBlbmRwb2ludCBvYmplY3QgaW4gY2Ru czNfZGV2aWNlLmVwc1tdIGNvbnRhaW5lcgorICogQGVwX2FkZHI6IGVuZHBvaW50IGFkZHJlc3Mg Zm9yIHdoaWNoIGVuZHBvaW50IG9iamVjdCBpcyByZXF1aXJlZAorICoKKyAqIFJlbWVtYmVyIHRo YXQgZW5kcG9pbnQgY29udGFpbmVyIGRvZXNuJ3QgY29udGFpbiBkZWZhdWx0IGVuZHBvaW50Cisg Ki8KK3U4IGNkbnMzX2VwX2FkZHJfdG9faW5kZXgodTggZXBfYWRkcikKK3sKKwlyZXR1cm4gKCgo ZXBfYWRkciAmIDB4N0YpIC0gMSkgKyAoKGVwX2FkZHIgJiBVU0JfRElSX0lOKSA/IDEgOiAwKSk7 Cit9CisKKy8qKgorICogY2RuczNfZXBfYWRkcl90b19iaXRfcG9zIC0gTWFjcm8gY29udmVydHMg ZW5kcG9pbnQgYWRkcmVzcyB0bworICogYml0IHBvc2l0aW9uIGluIGVwX2lzdHMgcmVnaXN0ZXIK KyAqIEBlcF9hZGRyOiBlbmRwb2ludCBhZGRyZXNzIGZvciB3aGljaCBiaXQgcG9zaXRpb24gaXMg cmVxdWlyZWQKKyAqCisgKiBSZW1lbWJlciB0aGF0IGVuZHBvaW50IGNvbnRhaW5lciBkb2Vzbid0 IGNvbnRhaW4gZGVmYXVsdCBlbmRwb2ludAorICovCitzdGF0aWMgdTMyIGNkbnMzX2VwX2FkZHJf dG9fYml0X3Bvcyh1OCBlcF9hZGRyKQoreworCXJldHVybiAoMSA8PCAoZXBfYWRkciAmIDB4N0Yp KSA8PCAoKGVwX2FkZHIgJiAweDgwKSA/IDE2IDogMCk7Cit9CisKKy8qKgorICogY2RuczNfbmV4 dF9yZXF1ZXN0IC0gcmV0dXJucyBuZXh0IHJlcXVlc3QgZnJvbSBsaXN0CisgKiBAbGlzdDogbGlz dCBjb250YWluaW5nIHJlcXVlc3RzCisgKgorICogUmV0dXJucyByZXF1ZXN0IG9yIE5VTEwgaWYg bm8gcmVxdWVzdHMgaW4gbGlzdAorICovCitzdHJ1Y3QgdXNiX3JlcXVlc3QgKmNkbnMzX25leHRf cmVxdWVzdChzdHJ1Y3QgbGlzdF9oZWFkICpsaXN0KQoreworCWlmIChsaXN0X2VtcHR5KGxpc3Qp KQorCQlyZXR1cm4gTlVMTDsKKwlyZXR1cm4gbGlzdF9maXJzdF9lbnRyeShsaXN0LCBzdHJ1Y3Qg dXNiX3JlcXVlc3QsIGxpc3QpOworfQorCisvKioKKyAqIHNlbGVjdF9lcCAtIHNlbGVjdHMgZW5k cG9pbnQKKyAqIEBwcml2X2RldjogIGV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBlcDogZW5k cG9pbnQgYWRkcmVzcworICovCit2b2lkIGNkbnMzX3NlbGVjdF9lcChzdHJ1Y3QgY2RuczNfZGV2 aWNlICpwcml2X2RldiwgdTMyIGVwKQoreworCWlmIChwcml2X2Rldi0+c2VsZWN0ZWRfZXAgPT0g ZXApCisJCXJldHVybjsKKworCXByaXZfZGV2LT5zZWxlY3RlZF9lcCA9IGVwOworCXdyaXRlbChl cCwgJnByaXZfZGV2LT5yZWdzLT5lcF9zZWwpOworfQorCitkbWFfYWRkcl90IGNkbnMzX3RyYl92 aXJ0X3RvX2RtYShzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAsCisJCQkJIHN0cnVjdCBj ZG5zM190cmIgKnRyYikKK3sKKwl1MzIgb2Zmc2V0ID0gKGNoYXIgKil0cmIgLSAoY2hhciAqKXBy aXZfZXAtPnRyYl9wb29sOworCisJcmV0dXJuIHByaXZfZXAtPnRyYl9wb29sX2RtYSArIG9mZnNl dDsKK30KKworLyoqCisgKiBjZG5zM19hbGxvY2F0ZV90cmJfcG9vbCAtIEFsbG9jYXRlcyBUUkIn cyBwb29sIGZvciBzZWxlY3RlZCBlbmRwb2ludAorICogQHByaXZfZXA6ICBlbmRwb2ludCBvYmpl Y3QKKyAqCisgKiBGdW5jdGlvbiB3aWxsIHJldHVybiAwIG9uIHN1Y2Nlc3Mgb3IgLUVOT01FTSBv biBhbGxvY2F0aW9uIGVycm9yCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfYWxsb2NhdGVfdHJiX3Bv b2woc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKQoreworCXN0cnVjdCBjZG5zM19kZXZp Y2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCXN0cnVjdCBjZG5zM190cmIgKmxp bmtfdHJiOworCisJaWYgKCFwcml2X2VwLT50cmJfcG9vbCkgeworCQlwcml2X2VwLT50cmJfcG9v bCA9IGRtYV96YWxsb2NfY29oZXJlbnQocHJpdl9kZXYtPnN5c2RldiwKKwkJCQkJCQlUUkJfUklO R19TSVpFLAorCQkJCQkJCSZwcml2X2VwLT50cmJfcG9vbF9kbWEsCisJCQkJCQkJR0ZQX0RNQSk7 CisJCWlmICghcHJpdl9lcC0+dHJiX3Bvb2wpCisJCQlyZXR1cm4gLUVOT01FTTsKKwl9IGVsc2Ug eworCQltZW1zZXQocHJpdl9lcC0+dHJiX3Bvb2wsIDAsIFRSQl9SSU5HX1NJWkUpOworCX0KKwor CWlmICghcHJpdl9lcC0+YWxpZ25lZF9idWZmKSB7CisJCXZvaWQgKmJ1ZmYgPSBkbWFfYWxsb2Nf Y29oZXJlbnQocHJpdl9kZXYtPnN5c2RldiwKKwkJCQkJCUNETlMzX0FMSUdORURfQlVGX1NJWkUs CisJCQkJCQkmcHJpdl9lcC0+YWxpZ25lZF9kbWFfYWRkciwKKwkJCQkJCUdGUF9ETUEpOworCisJ CXByaXZfZXAtPmFsaWduZWRfYnVmZiAgPSBidWZmOworCQlpZiAoIXByaXZfZXAtPmFsaWduZWRf YnVmZikgeworCQkJZG1hX2ZyZWVfY29oZXJlbnQocHJpdl9kZXYtPnN5c2RldiwKKwkJCQkJICBU UkJfUklOR19TSVpFLAorCQkJCQkgIHByaXZfZXAtPnRyYl9wb29sLAorCQkJCQkgIHByaXZfZXAt PnRyYl9wb29sX2RtYSk7CisJCQlwcml2X2VwLT50cmJfcG9vbCA9IE5VTEw7CisKKwkJCXJldHVy biAtRU5PTUVNOworCQl9CisJfQorCisJLyogSW5pdGlhbGl6ZSB0aGUgbGFzdCBUUkIgYXMgTGlu ayBUUkIgKi8KKwlsaW5rX3RyYiA9IChwcml2X2VwLT50cmJfcG9vbCArIFRSQlNfUEVSX1NFR01F TlQgLSAxKTsKKwlsaW5rX3RyYi0+YnVmZmVyID0gVFJCX0JVRkZFUihwcml2X2VwLT50cmJfcG9v bF9kbWEpOworCWxpbmtfdHJiLT5jb250cm9sID0gVFJCX0NZQ0xFIHwgVFJCX1RZUEUoVFJCX0xJ TkspIHwKKwkJCSAgICBUUkJfQ0hBSU4gfCBUUkJfVE9HR0xFOworCisJcmV0dXJuIDA7Cit9CisK K3N0YXRpYyB2b2lkIGNkbnMzX2ZyZWVfdHJiX3Bvb2woc3RydWN0IGNkbnMzX2VuZHBvaW50ICpw cml2X2VwKQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2Ru czNfZGV2OworCisJaWYgKHByaXZfZXAtPnRyYl9wb29sKSB7CisJCWRtYV9mcmVlX2NvaGVyZW50 KHByaXZfZGV2LT5zeXNkZXYsCisJCQkJICBUUkJfUklOR19TSVpFLAorCQkJCSAgcHJpdl9lcC0+ dHJiX3Bvb2wsIHByaXZfZXAtPnRyYl9wb29sX2RtYSk7CisJCXByaXZfZXAtPnRyYl9wb29sID0g TlVMTDsKKwl9CisKKwlpZiAocHJpdl9lcC0+YWxpZ25lZF9idWZmKSB7CisJCWRtYV9mcmVlX2Nv aGVyZW50KHByaXZfZGV2LT5zeXNkZXYsIENETlMzX0FMSUdORURfQlVGX1NJWkUsCisJCQkJICBw cml2X2VwLT5hbGlnbmVkX2J1ZmYsCisJCQkJICBwcml2X2VwLT5hbGlnbmVkX2RtYV9hZGRyKTsK KwkJcHJpdl9lcC0+YWxpZ25lZF9idWZmID0gTlVMTDsKKwl9Cit9CisKKy8qKgorICogY2RuczNf ZGF0YV9mbHVzaCAtIGZsdXNoIGRhdGEgYXQgb25jaGlwIGJ1ZmZlcgorICogQHByaXZfZXA6IGVu ZHBvaW50IG9iamVjdAorICoKKyAqIEVuZHBvaW50IG11c3QgYmUgc2VsZWN0ZWQgYmVmb3JlIGNh bGwgdG8gdGhpcyBmdW5jdGlvbgorICoKKyAqIFJldHVybnMgemVybyBvbiBzdWNjZXNzIG9yIG5l Z2F0aXZlIHZhbHVlIG9uIGZhaWx1cmUKKyAqLworc3RhdGljIGludCBjZG5zM19kYXRhX2ZsdXNo KHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCkKK3sKKwlzdHJ1Y3QgY2RuczNfZGV2aWNl ICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKworCXdyaXRlbChFUF9DTURfREZMVVNI LCAmcHJpdl9kZXYtPnJlZ3MtPmVwX2NtZCk7CisKKwkvKiB3YWl0IGZvciBERkxVU0ggY2xlYXJl ZCAqLworCXJldHVybiBjZG5zM19oYW5kc2hha2UoJnByaXZfZGV2LT5yZWdzLT5lcF9jbWQsIEVQ X0NNRF9ERkxVU0gsIDAsIDEwMCk7Cit9CisKKy8qKgorICogY2RuczNfZXBfc3RhbGxfZmx1c2gg LSBTdGFsbHMgYW5kIGZsdXNoZXMgc2VsZWN0ZWQgZW5kcG9pbnQKKyAqIEBwcml2X2VwOiBlbmRw b2ludCBvYmplY3QKKyAqCisgKiBFbmRwb2ludCBtdXN0IGJlIHNlbGVjdGVkIGJlZm9yZSBjYWxs IHRvIHRoaXMgZnVuY3Rpb24KKyAqLworc3RhdGljIHZvaWQgY2RuczNfZXBfc3RhbGxfZmx1c2go c3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKQoreworCXN0cnVjdCBjZG5zM19kZXZpY2Ug KnByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCisJd3JpdGVsKEVQX0NNRF9ERkxVU0gg fCBFUF9DTURfRVJEWSB8IEVQX0NNRF9TU1RBTEwsCisJICAgICAgICZwcml2X2Rldi0+cmVncy0+ ZXBfY21kKTsKKworCS8qIHdhaXQgZm9yIERGTFVTSCBjbGVhcmVkICovCisJY2RuczNfaGFuZHNo YWtlKCZwcml2X2Rldi0+cmVncy0+ZXBfY21kLCBFUF9DTURfREZMVVNILCAwLCAxMDApOworCXBy aXZfZXAtPmZsYWdzIHw9IEVQX1NUQUxMOworfQorCisvKioKKyAqIGNkbnMzX2dhZGdldF91bmNv bmZpZyAtIHJlc2V0IGRldmljZSBjb25maWd1cmF0aW9uCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVk IGdhZGdldCBvYmplY3QKKyAqLwordm9pZCBjZG5zM19nYWRnZXRfdW5jb25maWcoc3RydWN0IGNk bnMzX2RldmljZSAqcHJpdl9kZXYpCit7CisJLyogUkVTRVQgQ09ORklHVVJBVElPTiAqLworCXdy aXRlbChVU0JfQ09ORl9DRkdSU1QsICZwcml2X2Rldi0+cmVncy0+dXNiX2NvbmYpOworCisJY2Ru czNfYWxsb3dfZW5hYmxlX2wxKHByaXZfZGV2LCAwKTsKKwlwcml2X2Rldi0+aHdfY29uZmlndXJl ZF9mbGFnID0gMDsKKwlwcml2X2Rldi0+b25jaGlwX21lbV9hbGxvY2F0ZWRfc2l6ZSA9IDA7Cit9 CisKKy8qKgorICogY2RuczNfZXBfaW5jX3RyYiAtIGluY3JlbWVudCBhIHRyYiBpbmRleC4KKyAq IEBpbmRleDogUG9pbnRlciB0byB0aGUgVFJCIGluZGV4IHRvIGluY3JlbWVudC4KKyAqIEBjczog Q3ljbGUgc3RhdGUKKyAqCisgKiBUaGUgaW5kZXggc2hvdWxkIG5ldmVyIHBvaW50IHRvIHRoZSBs aW5rIFRSQi4gQWZ0ZXIgaW5jcmVtZW50aW5nLAorICogaWYgaXQgaXMgcG9pbnQgdG8gdGhlIGxp bmsgVFJCLCB3cmFwIGFyb3VuZCB0byB0aGUgYmVnaW5uaW5nIGFuZCByZXZlcnQKKyAqIGN5Y2xl IHN0YXRlIGJpdCBUaGUKKyAqIGxpbmsgVFJCIGlzIGFsd2F5cyBhdCB0aGUgbGFzdCBUUkIgZW50 cnkuCisgKi8KK3N0YXRpYyB2b2lkIGNkbnMzX2VwX2luY190cmIoaW50ICppbmRleCwgdTggKmNz KQoreworCSgqaW5kZXgpKys7CisJaWYgKCppbmRleCA9PSAoVFJCU19QRVJfU0VHTUVOVCAtIDEp KSB7CisJCSppbmRleCA9IDA7CisJCSpjcyBePSAgMTsKKwl9Cit9CisKKy8qKgorICogY2RuczNf ZXBfaW5jX2VucSAtIGluY3JlbWVudCBlbmRwb2ludCdzIGVucXVldWUgcG9pbnRlcgorICogQHBy aXZfZXA6IFRoZSBlbmRwb2ludCB3aG9zZSBlbnF1ZXVlIHBvaW50ZXIgd2UncmUgaW5jcmVtZW50 aW5nCisgKi8KK3N0YXRpYyB2b2lkIGNkbnMzX2VwX2luY19lbnEoc3RydWN0IGNkbnMzX2VuZHBv aW50ICpwcml2X2VwKQoreworCXByaXZfZXAtPmZyZWVfdHJicy0tOworCWNkbnMzX2VwX2luY190 cmIoJnByaXZfZXAtPmVucXVldWUsICZwcml2X2VwLT5wY3MpOworfQorCisvKioKKyAqIGNkbnMz X2VwX2luY19kZXEgLSBpbmNyZW1lbnQgZW5kcG9pbnQncyBkZXF1ZXVlIHBvaW50ZXIKKyAqIEBw cml2X2VwOiBUaGUgZW5kcG9pbnQgd2hvc2UgZGVxdWV1ZSBwb2ludGVyIHdlJ3JlIGluY3JlbWVu dGluZworICovCitzdGF0aWMgdm9pZCBjZG5zM19lcF9pbmNfZGVxKHN0cnVjdCBjZG5zM19lbmRw b2ludCAqcHJpdl9lcCkKK3sKKwlwcml2X2VwLT5mcmVlX3RyYnMrKzsKKwljZG5zM19lcF9pbmNf dHJiKCZwcml2X2VwLT5kZXF1ZXVlLCAmcHJpdl9lcC0+Y2NzKTsKK30KKworLyoqCisgKiBjZG5z M19hbGxvd19lbmFibGVfbDEgLSBlbmFibGUvZGlzYWJsZSBwZXJtaXRzIHRvIHRyYW5zaXRpb24g dG8gTDEuCisgKiBAcHJpdl9kZXY6IEV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBlbmFibGU6 IEVuYWJsZS9kaXNhYmxlIHBlcm1pdCB0byB0cmFuc2l0aW9uIHRvIEwxLgorICoKKyAqIElmIGJp dCBVU0JfQ09ORl9MMUVOIGlzIHNldCBhbmQgZGV2aWNlIHJlY2VpdmUgRXh0ZW5kZWQgVG9rZW4g cGFja2V0LAorICogdGhlbiBjb250cm9sbGVyIGFuc3dlciB3aXRoIEFDSyBoYW5kc2hha2UuCisg KiBJZiBiaXQgVVNCX0NPTkZfTDFEUyBpcyBzZXQgYW5kIGRldmljZSByZWNlaXZlIEV4dGVuZGVk IFRva2VuIHBhY2tldCwKKyAqIHRoZW4gY29udHJvbGxlciBhbnN3ZXIgd2l0aCBOWUVUIGhhbmRz aGFrZS4KKyAqLwordm9pZCBjZG5zM19hbGxvd19lbmFibGVfbDEoc3RydWN0IGNkbnMzX2Rldmlj ZSAqcHJpdl9kZXYsIGludCBlbmFibGUpCit7CisJaWYgKGVuYWJsZSkKKwkJd3JpdGVsKFVTQl9D T05GX0wxRU4sICZwcml2X2Rldi0+cmVncy0+dXNiX2NvbmYpOworCWVsc2UKKwkJd3JpdGVsKFVT Ql9DT05GX0wxRFMsICZwcml2X2Rldi0+cmVncy0+dXNiX2NvbmYpOworfQorCitlbnVtIHVzYl9k ZXZpY2Vfc3BlZWQgY2RuczNfZ2V0X3NwZWVkKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2 KQoreworCXUzMiByZWc7CisKKwlyZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9zdHMp OworCisJaWYgKERFVl9TVVBFUlNQRUVEKHJlZykpCisJCXJldHVybiBVU0JfU1BFRURfU1VQRVI7 CisJZWxzZSBpZiAoREVWX0hJR0hTUEVFRChyZWcpKQorCQlyZXR1cm4gVVNCX1NQRUVEX0hJR0g7 CisJZWxzZSBpZiAoREVWX0ZVTExTUEVFRChyZWcpKQorCQlyZXR1cm4gVVNCX1NQRUVEX0ZVTEw7 CisJZWxzZSBpZiAoREVWX0xPV1NQRUVEKHJlZykpCisJCXJldHVybiBVU0JfU1BFRURfTE9XOwor CXJldHVybiBVU0JfU1BFRURfVU5LTk9XTjsKK30KKworLyoqCisgKiBjZG5zM19zdGFydF9hbGxf cmVxdWVzdCAtIGFkZCB0byByaW5nIGFsbCByZXF1ZXN0IG5vdCBzdGFydGVkCisgKiBAcHJpdl9k ZXY6IEV4dGVuZGVkIGdhZGdldCBvYmplY3QKKyAqIEBwcml2X2VwOiBUaGUgZW5kcG9pbnQgZm9y IHdob20gcmVxdWVzdCB3aWxsIGJlIHN0YXJ0ZWQuCisgKgorICogUmV0dXJucyByZXR1cm4gRU5P TUVNIGlmIHRyYW5zZmVyIHJpbmcgaSBub3QgZW5vdWdoIFRSQnMgdG8gc3RhcnQKKyAqICAgICAg ICAgYWxsIHJlcXVlc3RzLgorICovCitzdGF0aWMgaW50IGNkbnMzX3N0YXJ0X2FsbF9yZXF1ZXN0 KHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LAorCQkJCSAgIHN0cnVjdCBjZG5zM19lbmRw b2ludCAqcHJpdl9lcCkKK3sKKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcSwgKnJlcV90ZW1wOwor CWludCByZXQgPSAwOworCisJbGlzdF9mb3JfZWFjaF9lbnRyeV9zYWZlKHJlcSwgcmVxX3RlbXAs ICZwcml2X2VwLT5yZXF1ZXN0X2xpc3QsIGxpc3QpIHsKKwkJc3RydWN0IGNkbnMzX3JlcXVlc3Qg KnByaXZfcmVxID0gdG9fY2RuczNfcmVxdWVzdChyZXEpOworCisJCWlmICghKHByaXZfcmVxLT5m bGFncyAmIFJFUVVFU1RfUEVORElORykpIHsKKwkJCXJldCA9IGNkbnMzX2VwX3J1bl90cmFuc2Zl cihwcml2X2VwLCByZXEpOworCQkJaWYgKHJldCkKKwkJCQlyZXR1cm4gcmV0OworCQl9CisJfQor CisJcHJpdl9lcC0+ZmxhZ3MgJj0gfkVQX1JJTkdfRlVMTDsKKwlyZXR1cm4gcmV0OworfQorCisv KioKKyAqIGNkbnMzX2dhZGdldF9naXZlYmFjayAtIGNhbGwgc3RydWN0IHVzYl9yZXF1ZXN0J3Mg LT5jb21wbGV0ZSBjYWxsYmFjaworICogQHByaXZfZXA6IFRoZSBlbmRwb2ludCB0byB3aG9tIHRo ZSByZXF1ZXN0IGJlbG9uZ3MgdG8KKyAqIEBwcml2X3JlcTogVGhlIHJlcXVlc3Qgd2UncmUgZ2l2 aW5nIGJhY2sKKyAqIEBzdGF0dXM6IGNvbXBsZXRpb24gY29kZSBmb3IgdGhlIHJlcXVlc3QKKyAq CisgKiBNdXN0IGJlIGNhbGxlZCB3aXRoIGNvbnRyb2xsZXIncyBsb2NrIGhlbGQgYW5kIGludGVy cnVwdHMgZGlzYWJsZWQuIFRoaXMKKyAqIGZ1bmN0aW9uIHdpbGwgdW5tYXAgQHJlcSBhbmQgY2Fs bCBpdHMgLT5jb21wbGV0ZSgpIGNhbGxiYWNrIHRvIG5vdGlmeSB1cHBlcgorICogbGF5ZXJzIHRo YXQgaXQgaGFzIGNvbXBsZXRlZC4KKyAqLwordm9pZCBjZG5zM19nYWRnZXRfZ2l2ZWJhY2soc3Ry dWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAorCQkJICAgc3RydWN0IGNkbnMzX3JlcXVlc3Qg KnByaXZfcmVxLAorCQkJICAgaW50IHN0YXR1cykKK3sKKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpw cml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVl c3QgPSAmcHJpdl9yZXEtPnJlcXVlc3Q7CisKKwlsaXN0X2RlbF9pbml0KCZyZXF1ZXN0LT5saXN0 KTsKKworCWlmIChyZXF1ZXN0LT5zdGF0dXMgPT0gLUVJTlBST0dSRVNTKQorCQlyZXF1ZXN0LT5z dGF0dXMgPSBzdGF0dXM7CisKKwl1c2JfZ2FkZ2V0X3VubWFwX3JlcXVlc3RfYnlfZGV2KHByaXZf ZGV2LT5zeXNkZXYsIHJlcXVlc3QsCisJCQkJCXByaXZfZXAtPmRpcik7CisKKwlwcml2X3JlcS0+ ZmxhZ3MgJj0gflJFUVVFU1RfUEVORElORzsKKwl0cmFjZV9jZG5zM19nYWRnZXRfZ2l2ZWJhY2so cHJpdl9yZXEpOworCisJaWYgKHByaXZfcmVxLT5mbGFncyAmIFJFUVVFU1RfSU5URVJOQUwpIHsK KwkJc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXE7CisKKwkJcmVxID0gY2RuczNfbmV4dF9yZXF1ZXN0 KCZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpOworCisJCXByaXZfZXAtPmRlc2NtaXNfcGVuZGluZyA9 IGZhbHNlOworCQlwcml2X2VwLT5kZXNjbWlzX2ZpbmlzaGVkID0gdHJ1ZTsKKworCQkvKgorCQkg KiBJZiBubyByZXF1ZXN0IGlzIHF1ZXVlZCB0aGVuIGRyaXZlciBjYW4ndCBkbyBub3RoaW5nCisJ CSAqIHdpdGgganVzdCBjb21wbGV0ZWQgcmVxdWVzdC4gUmVxdWVzdCB3aXRoIGZsYWcgc2V0IHRv CisJCSAqIFJFUVVFU1RfSU5URVJOQUwgaXMgb25seSBpbnRlcm5hbCB1c2VkIHJlcXVlc3QgYW5k IGRyaXZlcgorCQkgKiBjYW4ndCBjYWxsIGNvbXBsZXRlIGNhbGxiYWNrLiBCZWZvcmUgY2FsbGlu ZyBjb21wbGV0aW9uLCBkYXRhCisJCSAqIG11c3QgYmUgY29waWVkIHRvIG5vcm1hbCB1c2JfcmVx dWVzdCBvYmplY3QKKwkJICovCisJCWlmICghcmVxKQorCQkJcmV0dXJuOworCisJCXJlcS0+YWN0 dWFsID0gcmVxdWVzdC0+YWN0dWFsOworCQlyZXEtPnN0YXR1cyA9IHJlcXVlc3QtPnN0YXR1czsK KwkJbWVtY3B5KHJlcS0+YnVmLCByZXF1ZXN0LT5idWYsIHJlcXVlc3QtPmFjdHVhbCk7CisKKwkJ cmVxdWVzdCA9IHJlcTsKKwkJbGlzdF9kZWxfaW5pdCgmcmVxdWVzdC0+bGlzdCk7CisJCWNkbnMz X3N0YXJ0X2FsbF9yZXF1ZXN0KHByaXZfZGV2LCBwcml2X2VwKTsKKwkJcHJpdl9lcC0+ZGVzY21p c19maW5pc2hlZCA9IGZhbHNlOworCX0KKworCS8qIFN0YXJ0IGFsbCBub3QgcGVuZGluZyByZXF1 ZXN0ICovCisJaWYgKHByaXZfZXAtPmZsYWdzICYgRVBfUklOR19GVUxMKQorCQljZG5zM19zdGFy dF9hbGxfcmVxdWVzdChwcml2X2RldiwgcHJpdl9lcCk7CisKKwlpZiAocmVxdWVzdC0+Y29tcGxl dGUpIHsKKwkJc3Bpbl91bmxvY2soJnByaXZfZGV2LT5sb2NrKTsKKwkJdXNiX2dhZGdldF9naXZl YmFja19yZXF1ZXN0KCZwcml2X2VwLT5lbmRwb2ludCwKKwkJCQkJICAgIHJlcXVlc3QpOworCQlz cGluX2xvY2soJnByaXZfZGV2LT5sb2NrKTsKKwl9CisKKwlpZiAocmVxdWVzdC0+YnVmID09IHBy aXZfZGV2LT56bHBfYnVmKQorCQljZG5zM19nYWRnZXRfZXBfZnJlZV9yZXF1ZXN0KCZwcml2X2Vw LT5lbmRwb2ludCwgcmVxdWVzdCk7Cit9CisKKy8qKgorICogY2RuczNfZXBfcnVuX3RyYW5zZmVy IC0gc3RhcnQgdHJhbnNmZXIgb24gbm8tZGVmYXVsdCBlbmRwb2ludCBoYXJkd2FyZQorICogQHBy aXZfZXA6IGVuZHBvaW50IG9iamVjdAorICoKKyAqIFJldHVybnMgemVybyBvbiBzdWNjZXNzIG9y IG5lZ2F0aXZlIHZhbHVlIG9uIGZhaWx1cmUKKyAqLworaW50IGNkbnMzX2VwX3J1bl90cmFuc2Zl cihzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAsCisJCQkgIHN0cnVjdCB1c2JfcmVxdWVz dCAqcmVxdWVzdCkKK3sKKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAt PmNkbnMzX2RldjsKKwlzdHJ1Y3QgY2RuczNfcmVxdWVzdCAqcHJpdl9yZXE7CisJc3RydWN0IGNk bnMzX3RyYiAqdHJiOworCWRtYV9hZGRyX3QgdHJiX2RtYTsKKwlpbnQgc2dfaXRlciA9IDA7CisJ dTMyIGZpcnN0X3BjczsKKwlpbnQgIG51bV90cmI7CisJaW50IGFkZHJlc3M7CisJaW50IHBjczsK KworCW51bV90cmIgPSByZXF1ZXN0LT5udW1fc2dzID8gcmVxdWVzdC0+bnVtX3NncyA6IDE7CisK KwlpZiAobnVtX3RyYiA+IHByaXZfZXAtPmZyZWVfdHJicykgeworCQlwcml2X2VwLT5mbGFncyB8 PSBFUF9SSU5HX0ZVTEw7CisJCXJldHVybiAtRU5PTUVNOworCX0KKworCXByaXZfcmVxID0gdG9f Y2RuczNfcmVxdWVzdChyZXF1ZXN0KTsKKwlhZGRyZXNzID0gcHJpdl9lcC0+ZW5kcG9pbnQuZGVz Yy0+YkVuZHBvaW50QWRkcmVzczsKKworCWlmIChwcml2X2VwLT5kZXNjbWlzX3BlbmRpbmcpCisJ CXJldHVybiAwOworCisJaWYgKHByaXZfcmVxLT5mbGFncyAmIFJFUVVFU1RfUEVORElORykKKwkJ Z290byBhcm07CisKKwlwcml2X2VwLT5mbGFncyB8PSBFUF9QRU5ESU5HX1JFUVVFU1Q7CisJdHJi X2RtYSA9IHJlcXVlc3QtPmRtYTsKKworCS8qIG11c3QgYWxsb2NhdGUgYnVmZmVyIGFsaWduZWQg dG8gOCAqLworCWlmICgocmVxdWVzdC0+ZG1hICUgOCkpIHsKKwkJaWYgKHJlcXVlc3QtPmxlbmd0 aCA8PSBDRE5TM19BTElHTkVEX0JVRl9TSVpFKSB7CisJCQltZW1jcHkocHJpdl9lcC0+YWxpZ25l ZF9idWZmLCByZXF1ZXN0LT5idWYsCisJCQkgICAgICAgcmVxdWVzdC0+bGVuZ3RoKTsKKwkJCXRy Yl9kbWEgPSBwcml2X2VwLT5hbGlnbmVkX2RtYV9hZGRyOworCQl9IGVsc2UgeworCQkJcmV0dXJu IC1FTk9NRU07CisJCX0KKwl9CisKKwl0cmIgPSBwcml2X2VwLT50cmJfcG9vbCArIHByaXZfZXAt PmVucXVldWU7CisJcHJpdl9yZXEtPnRyYiA9IHRyYjsKKwlwcml2X3JlcS0+c3RhcnRfdHJiID0g cHJpdl9lcC0+ZW5xdWV1ZTsKKworCS8qIHByZXBhcmUgcmluZyAqLworCWlmICgocHJpdl9lcC0+ ZW5xdWV1ZSArIG51bV90cmIpICA+PSAoVFJCU19QRVJfU0VHTUVOVCAtIDEpKSB7CisJCS8qdXBk YXRpbmcgQyBidCBpbiAgTGluayBUUkIgYmVmb3JlIHN0YXJ0aW5nIERNQSovCisJCXN0cnVjdCBj ZG5zM190cmIgKmxpbmtfdHJiID0gcHJpdl9lcC0+dHJiX3Bvb2wgKworCQkJCQkgICAgIChUUkJT X1BFUl9TRUdNRU5UIC0gMSk7CisJCWxpbmtfdHJiLT5jb250cm9sID0gKChwcml2X2VwLT5wY3Mp ID8gVFJCX0NZQ0xFIDogMCkgfAorCQkJCSAgICBUUkJfVFlQRShUUkJfTElOSykgfCBUUkJfQ0hB SU4gfAorCQkJCSAgICBUUkJfVE9HR0xFOworCX0KKworCWZpcnN0X3BjcyA9IHByaXZfZXAtPnBj cyA/IFRSQl9DWUNMRSA6IDA7CisKKwlkbyB7CisJLyogZmlsbCBUUkIgKi8KKwkJdHJiLT5idWZm ZXIgPSBUUkJfQlVGRkVSKHJlcXVlc3QtPm51bV9zZ3MgPT0gMAorCQkJCT8gdHJiX2RtYSA6IHJl cXVlc3QtPnNnW3NnX2l0ZXJdLmRtYV9hZGRyZXNzKTsKKworCQl0cmItPmxlbmd0aCA9IFRSQl9C VVJTVF9MRU4oMTYpIHwKKwkJICAgIFRSQl9MRU4ocmVxdWVzdC0+bnVtX3NncyA9PSAwID8KKwkJ CQlyZXF1ZXN0LT5sZW5ndGggOiByZXF1ZXN0LT5zZ1tzZ19pdGVyXS5sZW5ndGgpOworCisJCXRy Yi0+Y29udHJvbCA9IFRSQl9UWVBFKFRSQl9OT1JNQUwpOworCQlwY3MgPSBwcml2X2VwLT5wY3Mg PyBUUkJfQ1lDTEUgOiAwOworCisJCS8qCisJCSAqIGZpcnN0IHRyYiBzaG91bGQgYmUgcHJlcGFy ZWQgYXMgbGFzdCB0byBhdm9pZCBwcm9jZXNzaW5nCisJCSAqICB0cmFuc2ZlciB0byBlYXJseQor CQkgKi8KKwkJaWYgKHNnX2l0ZXIgPT0gcmVxdWVzdC0+bnVtX3NncyAmJiBzZ19pdGVyICE9IDAp CisJCQl0cmItPmNvbnRyb2wgfD0gcGNzIHwgVFJCX0lPQyB8IFRSQl9JU1A7CisJCWVsc2UgaWYg KHNnX2l0ZXIgIT0gMCkKKwkJCXRyYi0+Y29udHJvbCB8PSBwY3M7CisKKwkJKytzZ19pdGVyOwor CQkrK3RyYjsKKwkJY2RuczNfZXBfaW5jX2VucShwcml2X2VwKTsKKwl9IHdoaWxlIChzZ19pdGVy IDwgcmVxdWVzdC0+bnVtX3Nncyk7CisKKwl0cmIgPSBwcml2X3JlcS0+dHJiOworCS8qCisJICog TWVtb3J5IGJhcnJpZXIgPSBDeWNsZSBCaXQgbXVzdCBiZSBzZXQgYmVmb3JlIHRyYi0+bGVuZ3Ro ICBhbmQKKwkgKiB0cmItPmJ1ZmZlciBmaWVsZHMuCisJICovCisJd21iKCk7CisKKwkvKiBnaXZl IHRoZSBURCB0byB0aGUgY29uc3VtZXIqLworCWlmIChzZ19pdGVyID09IDEpCisJCXRyYi0+Y29u dHJvbCB8PSBmaXJzdF9wY3MgfCBUUkJfSU9DIHwgVFJCX0lTUDsKKwllbHNlCisJCXRyYi0+Y29u dHJvbCB8PSBmaXJzdF9wY3M7CisKKwlwcml2X3JlcS0+ZmxhZ3MgfD0gUkVRVUVTVF9QRU5ESU5H OworCisJaWYgKHByaXZfcmVxLT5mbGFncyAmIFJFUVVFU1RfSU5URVJOQUwpCisJCXByaXZfZXAt PmRlc2NtaXNfcGVuZGluZyA9IHRydWU7CisKKwl0cmFjZV9jZG5zM19wcmVwYXJlX3RyYihwcml2 X2VwLCBwcml2X3JlcS0+dHJiKTsKKwl0cmFjZV9jZG5zM19yaW5nKHByaXZfZXApOworCithcm06 CisJLyogYXJtIHRyYW5zZmVyIG9uIHNlbGVjdGVkIGVuZHBvaW50ICovCisJY2RuczNfc2VsZWN0 X2VwKHByaXZfZXAtPmNkbnMzX2RldiwgYWRkcmVzcyk7CisKKwkvKgorCSAqIEZvciBETVVMVCBt b2RlIHdlIGNhbiBzZXQgYWRkcmVzcyB0byB0cmFuc2ZlciByaW5nIG9ubHkgb25jZSBhZnRlcgor CSAqIGVuYWJsaW5nIGVuZHBvaW50LgorCSAqLworCWlmIChwcml2X2VwLT5mbGFncyAmIEVQX1VQ REFURV9FUF9UUkJBRERSKSB7CisJCXdyaXRlbChFUF9UUkFERFJfVFJBRERSKHByaXZfZXAtPnRy Yl9wb29sX2RtYSksCisJCSAgICAgICAmcHJpdl9kZXYtPnJlZ3MtPmVwX3RyYWRkcik7CisJCXBy aXZfZXAtPmZsYWdzICY9IH5FUF9VUERBVEVfRVBfVFJCQUREUjsKKwl9CisKKwlpZiAocHJpdl9k ZXYtPmh3X2NvbmZpZ3VyZWRfZmxhZykgeworCQkvKmNsZWFyaW5nIFRSQkVSUiBhbmQgRVBfU1RT X0RFU0NNSVMgYmVmb3JlIHNldGluZyBEUkRZKi8KKwkJd3JpdGVsKEVQX1NUU19UUkJFUlIgfCBF UF9TVFNfREVTQ01JUywgJnByaXZfZGV2LT5yZWdzLT5lcF9zdHMpOworCQl0cmFjZV9jZG5zM19k b29yYmVsbF9lcHgocHJpdl9lcC0+bmFtZSk7CisJCXdyaXRlbChFUF9DTURfRFJEWSwgJnByaXZf ZGV2LT5yZWdzLT5lcF9jbWQpOworCX0KKworCXJldHVybiAwOworfQorCit2b2lkIGNkbnMzX3Nl dF9od19jb25maWd1cmF0aW9uKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2KQoreworCXN0 cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcDsKKwlzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVl c3Q7CisJc3RydWN0IHVzYl9lcCAqZXA7CisJaW50IHJlc3VsdCA9IDA7CisKKwlpZiAocHJpdl9k ZXYtPmh3X2NvbmZpZ3VyZWRfZmxhZykKKwkJcmV0dXJuOworCisJd3JpdGVsKFVTQl9DT05GX0NG R1NFVCwgJnByaXZfZGV2LT5yZWdzLT51c2JfY29uZik7CisJd3JpdGVsKEVQX0NNRF9FUkRZIHwg RVBfQ01EX1JFUV9DTVBMLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX2NtZCk7CisKKwljZG5zM19zZXRf cmVnaXN0ZXJfYml0KCZwcml2X2Rldi0+cmVncy0+dXNiX2NvbmYsCisJCQkgICAgICAgVVNCX0NP TkZfVTFFTiB8IFVTQl9DT05GX1UyRU4pOworCisJLyogd2FpdCB1bnRpbCBjb25maWd1cmF0aW9u IHNldCAqLworCXJlc3VsdCA9IGNkbnMzX2hhbmRzaGFrZSgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9z dHMsCisJCQkJIFVTQl9TVFNfQ0ZHU1RTX01BU0ssIDEsIDEwMCk7CisKKwlwcml2X2Rldi0+aHdf Y29uZmlndXJlZF9mbGFnID0gMTsKKwljZG5zM19hbGxvd19lbmFibGVfbDEocHJpdl9kZXYsIDEp OworCisJbGlzdF9mb3JfZWFjaF9lbnRyeShlcCwgJnByaXZfZGV2LT5nYWRnZXQuZXBfbGlzdCwg ZXBfbGlzdCkgeworCQlpZiAoZXAtPmVuYWJsZWQpIHsKKwkJCXByaXZfZXAgPSBlcF90b19jZG5z M19lcChlcCk7CisJCQlyZXF1ZXN0ID0gY2RuczNfbmV4dF9yZXF1ZXN0KCZwcml2X2VwLT5yZXF1 ZXN0X2xpc3QpOworCQkJaWYgKHJlcXVlc3QpCisJCQkJY2RuczNfZXBfcnVuX3RyYW5zZmVyKHBy aXZfZXAsIHJlcXVlc3QpOworCQl9CisJfQorfQorCitzdGF0aWMgYm9vbCBjZG5zM19yZXF1ZXN0 X2hhbmRsZWQoc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAorCQkJCSAgc3RydWN0IGNk bnMzX3JlcXVlc3QgKnByaXZfcmVxKQoreworCWludCBjdXJyZW50X2luZGV4OworCXN0cnVjdCBj ZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCXN0cnVjdCBjZG5z M190cmIgKnRyYiA9IHByaXZfcmVxLT50cmI7CisKKwlpZiAoIShwcml2X3JlcS0+ZmxhZ3MgJiBS RVFVRVNUX1BFTkRJTkcpKQorCQlyZXR1cm4gZmFsc2U7CisKKwljZG5zM19zZWxlY3RfZXAocHJp dl9kZXYsIHByaXZfZXAtPmVuZHBvaW50LmRlc2MtPmJFbmRwb2ludEFkZHJlc3MpOworCWN1cnJl bnRfaW5kZXggPSAocmVhZGwoJnByaXZfZGV2LT5yZWdzLT5lcF90cmFkZHIpIC0KKwkJCSBwcml2 X2VwLT50cmJfcG9vbF9kbWEpIC8gVFJCX1NJWkU7CisKKwl0cmIgPSAmcHJpdl9lcC0+dHJiX3Bv b2xbcHJpdl9yZXEtPnN0YXJ0X3RyYl07CisKKwlpZiAoKHRyYi0+Y29udHJvbCAgJiBUUkJfQ1lD TEUpICE9IHByaXZfZXAtPmNjcykKKwkJcmV0dXJuIGZhbHNlOworCisJLyoqCisJICogY2FzZSB3 aGVyZSBlcF90cmFkZHIgcG9pbnQgdG8gbGFzdCB0cmIgaW4gcmluZyAobGluayB0cmIpCisJICog YW5kIGRlcXVldWUgcG9pbnRlciBhbHJlYWR5IGhhcyBiZWVuIGNoYW5nZWQgdG8gZmlyc3QgdHJi CisJICovCisJaWYgKChjdXJyZW50X2luZGV4ID09IChUUkJTX1BFUl9TRUdNRU5UIC0gMSkpICYm ICFwcml2X2VwLT5kZXF1ZXVlKQorCQlyZXR1cm4gZmFsc2U7CisKKwlpZiAocHJpdl9yZXEtPnN0 YXJ0X3RyYiAhPSBjdXJyZW50X2luZGV4KQorCQlyZXR1cm4gdHJ1ZTsKKworCXJldHVybiBmYWxz ZTsKK30KKworc3RhdGljIHZvaWQgY2RuczNfdHJhbnNmZXJfY29tcGxldGVkKHN0cnVjdCBjZG5z M19kZXZpY2UgKnByaXZfZGV2LAorCQkJCSAgICAgc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2 X2VwKQoreworCXN0cnVjdCB1c2JfcmVxdWVzdCAqcmVxdWVzdDsKKwlzdHJ1Y3QgY2RuczNfcmVx dWVzdCAqcHJpdl9yZXE7CisJc3RydWN0IGNkbnMzX3RyYiAqdHJiOworCisJd2hpbGUgKCFsaXN0 X2VtcHR5KCZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpKSB7CisJCXJlcXVlc3QgPSBjZG5zM19uZXh0 X3JlcXVlc3QoJnByaXZfZXAtPnJlcXVlc3RfbGlzdCk7CisJCXByaXZfcmVxID0gdG9fY2RuczNf cmVxdWVzdChyZXF1ZXN0KTsKKworCQlpZiAoIWNkbnMzX3JlcXVlc3RfaGFuZGxlZChwcml2X2Vw LCBwcml2X3JlcSkpCisJCQlyZXR1cm47CisKKwkJaWYgKHJlcXVlc3QtPmRtYSAlIDggJiYgcHJp dl9lcC0+ZGlyID09IFVTQl9ESVJfT1VUKQorCQkJbWVtY3B5KHJlcXVlc3QtPmJ1ZiwgcHJpdl9l cC0+YWxpZ25lZF9idWZmLAorCQkJICAgICAgIHJlcXVlc3QtPmxlbmd0aCk7CisKKwkJdHJiID0g cHJpdl9lcC0+dHJiX3Bvb2wgKyBwcml2X2VwLT5kZXF1ZXVlOworCQl0cmFjZV9jZG5zM19jb21w bGV0ZV90cmIocHJpdl9lcCwgdHJiKTsKKwkJaWYgKHRyYiAhPSBwcml2X3JlcS0+dHJiKQorCQkJ ZGV2X3dhcm4ocHJpdl9kZXYtPmRldiwKKwkJCQkgInJlcXVlc3RfdHJiPTB4JXAsIHF1ZXVlX3Ry Yj0weCVwXG4iLAorCQkJCSBwcml2X3JlcS0+dHJiLCB0cmIpOworCisJCXJlcXVlc3QtPmFjdHVh bCA9IFRSQl9MRU4obGUzMl90b19jcHUodHJiLT5sZW5ndGgpKTsKKworCQljZG5zM19lcF9pbmNf ZGVxKHByaXZfZXApOworCisJCWNkbnMzX2dhZGdldF9naXZlYmFjayhwcml2X2VwLCBwcml2X3Jl cSwgMCk7CisJfQorCisJcHJpdl9lcC0+ZmxhZ3MgJj0gfkVQX1BFTkRJTkdfUkVRVUVTVDsKK30K KworLyoqCisgKiBjZG5zM19kZXNjbWlzc2luZ19wYWNrZXQgLSBoYW5kbGVzIGRlc2NyaXB0b3Ig bWlzc2luZyBldmVudC4KKyAqIEBwcml2X2RldjogZXh0ZW5kZWQgZ2FkZ2V0IG9iamVjdAorICoK KyAqIEZ1bmN0aW9uIHByb3RlY3RzIGdhZGdldCBmdW5jdGlvbnMgZnJvbSBnZXR0aW5nIHN0dWNr LgorICogQ29udHJvbGxlciBmb3IgT1VUIGVuZHBvaW50cyBoYXMgc2hhcmVkIG9uLWNoaXAgYnVm ZmVycyBmb3IgYWxsIGluY29taW5nCisgKiBwYWNrZXRzLCBpbmNsdWRpbmcgZXAwb3V0LiBJdCdz IEZJRk8gYnVmZmVyLCBzbyBwYWNrZXRzIG11c3QgYmUgaGFuZGxlIGJ5IERNQQorICogaW4gY29y cmVjdCBvcmRlci4gSWYgdGhlIGZpcnN0IHBhY2tldCBpbiB0aGUgYnVmZmVyIHdpbGwgbm90IGJl IGhhbmRsZWQsCisgKiB0aGVuIHRoZSBmb2xsb3dpbmcgcGFja2V0cyBkaXJlY3RlZCBmb3Igb3Ro ZXIgZW5kcG9pbnRzIGFuZCAgZnVuY3Rpb25zCisgKiB3aWxsIGJlIGJsb2NrZWQuCisgKiBBZGRp dGlvbmFsbHkgdGhlIHBhY2tldHMgZGlyZWN0ZWQgdG8gb25lIGVuZHBvaW50IGNhbiBjbG9nIGVu dGlyZSBvbi1jaGlwCisgKiBidWZmZXJzLiBJbiB0aGlzIGNhc2UgdHJhbnNmZXIgdG8gb3RoZXIg ZW5kcG9pbnRzIGFsc28gd2lsbCBibG9ja2VkLgorICoKKyAqIFRvIHJlc29sdmUgdGhpcyBpc3N1 ZSBhZnRlciByYWlzaW5nIHRoZSBkZXNjcmlwdG9yIG1pc3NpbmcgaW50ZXJydXB0CisgKiBkcml2 ZXIgcHJlcGFyZXMgaW50ZXJuYWwgdXNiX3JlcXVlc3Qgb2JqZWN0IGFuZCB1c2UgaXQgdG8gYXJt IERNQSB0cmFuc2ZlcgorICogZm9yIHRoZSByaWdodCBlbmRwb2ludC4gRHJpdmVyIHVzZSBvbmx5 IHNpbmdsZSB1c2JfcmVxdWVzdCB3aXRoCisgKiBhbGxvY2F0ZWQgNjRLQiBidWZmZXIsIHNvIGlm IGhvc3Qgc2VuZCBtb3JlIG5vdCBleHBlY3RlZCB0cmFuc2ZlcnMsIHRoZW4gb25seQorICogdGhl IGxhc3Qgd2lsbCBiZSBzYXZlZCBhbmQgcmV0dXJuZWQgdG8gZ2FkZ2V0IGZ1bmN0aW9uLgorICog U3VjaCBibG9ja2luZyBzaXR1YXRpb24gd2FzIG9ic2VydmVkIG9uIEFDTSBnYWRnZXQsIGJlY2F1 c2UgaG9zdCBzZW5kIE9VVAorICogZGF0YSBwYWNrZXQgYnV0IEFDTSBmdW5jdGlvbiBkb2Vzbid0 IHdhbnQgdGhlaXIuCisgKi8KK3N0YXRpYyB2b2lkIGNkbnMzX2Rlc2NtaXNzaW5nX3BhY2tldChz dHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXApCit7CisJc3RydWN0IGNkbnMzX3JlcXVlc3Qg KnByaXZfcmVxID0gcHJpdl9lcC0+ZGVzY21pc19yZXE7CisJc3RydWN0IHVzYl9yZXF1ZXN0ICpy ZXF1ZXN0OworCisJaWYgKCFwcml2X3JlcSkgeworCQlyZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2Vw X2FsbG9jX3JlcXVlc3QoJnByaXZfZXAtPmVuZHBvaW50LAorCQkJCQkJCUdGUF9BVE9NSUMpOwor CQlwcml2X3JlcSA9IHRvX2NkbnMzX3JlcXVlc3QocmVxdWVzdCk7CisJCXByaXZfcmVxLT5mbGFn cyB8PSBSRVFVRVNUX0lOVEVSTkFMOworCQlwcml2X3JlcS0+cmVxdWVzdC5idWYgPSBremFsbG9j KENETlMzX0RFU0NNSVNfQlVGX1NJWkUsCisJCQkJCQlHRlBfQVRPTUlDKTsKKwkJcHJpdl9yZXEt PnJlcXVlc3QubGVuZ3RoID0gQ0ROUzNfREVTQ01JU19CVUZfU0laRTsKKwkJcHJpdl9lcC0+ZGVz Y21pc19yZXEgPSBwcml2X3JlcTsKKwl9CisKKwlwcml2X2VwLT5kZXNjbWlzX2ZpbmlzaGVkID0g ZmFsc2U7CisJX19jZG5zM19nYWRnZXRfZXBfcXVldWUoJnByaXZfZXAtPmVuZHBvaW50LAorCQkJ CSZwcml2X2VwLT5kZXNjbWlzX3JlcS0+cmVxdWVzdCwKKwkJCQlHRlBfQVRPTUlDKTsKK30KKwor LyoqCisgKiBjZG5zM19jaGVja19lcF9pbnRlcnJ1cHRfcHJvY2VlZCAtIFByb2Nlc3NlcyBpbnRl cnJ1cHQgcmVsYXRlZCB0byBlbmRwb2ludAorICogQHByaXZfZXA6IGVuZHBvaW50IG9iamVjdAor ICoKKyAqIFJldHVybnMgMAorICovCitzdGF0aWMgaW50IGNkbnMzX2NoZWNrX2VwX2ludGVycnVw dF9wcm9jZWVkKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCkKK3sKKwlzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKwl1MzIgZXBfc3RzX3Jl ZzsKKworCWNkbnMzX3NlbGVjdF9lcChwcml2X2RldiwgcHJpdl9lcC0+ZW5kcG9pbnQuYWRkcmVz cyk7CisJZXBfc3RzX3JlZyA9IHJlYWRsKCZwcml2X2Rldi0+cmVncy0+ZXBfc3RzKTsKKwl3cml0 ZWwoZXBfc3RzX3JlZywgJnByaXZfZGV2LT5yZWdzLT5lcF9zdHMpOworCisJdHJhY2VfY2RuczNf ZXB4X2lycShwcml2X2VwKTsKKworCWlmICgoZXBfc3RzX3JlZyAmIEVQX1NUU19JT0MpIHx8IChl cF9zdHNfcmVnICYgRVBfU1RTX0lTUCkpCisJCWNkbnMzX3RyYW5zZmVyX2NvbXBsZXRlZChwcml2 X2RldiwgcHJpdl9lcCk7CisKKwlpZiAoZXBfc3RzX3JlZyAmIEVQX1NUU19ERVNDTUlTKQorCQlj ZG5zM19kZXNjbWlzc2luZ19wYWNrZXQocHJpdl9lcCk7CisKKwlyZXR1cm4gMDsKK30KKworLyoq CisgKiBjZG5zM19jaGVja191c2JfaW50ZXJydXB0X3Byb2NlZWQgLSBQcm9jZXNzZXMgaW50ZXJy dXB0IHJlbGF0ZWQgdG8gZGV2aWNlCisgKiBAcHJpdl9kZXY6IGV4dGVuZGVkIGdhZGdldCBvYmpl Y3QKKyAqIEB1c2JfaXN0czogYml0bWFwIHJlcHJlc2VudGF0aW9uIG9mIGRldmljZSdzIHJlcG9y dGVkIGludGVycnVwdHMKKyAqICh1c2JfaXN0cyByZWdpc3RlciB2YWx1ZSkKKyAqLworc3RhdGlj IHZvaWQgY2RuczNfY2hlY2tfdXNiX2ludGVycnVwdF9wcm9jZWVkKHN0cnVjdCBjZG5zM19kZXZp Y2UgKnByaXZfZGV2LAorCQkJCQkgICAgICB1MzIgdXNiX2lzdHMpCit7CisJaW50IHNwZWVkID0g MDsKKworCXRyYWNlX2NkbnMzX3VzYl9pcnEocHJpdl9kZXYsIHVzYl9pc3RzKTsKKwkvKiBDb25u ZWN0aW9uIGRldGVjdGVkICovCisJaWYgKHVzYl9pc3RzICYgKFVTQl9JU1RTX0NPTjJJIHwgVVNC X0lTVFNfQ09OSSkpIHsKKwkJc3BlZWQgPSBjZG5zM19nZXRfc3BlZWQocHJpdl9kZXYpOworCQlw cml2X2Rldi0+Z2FkZ2V0LnNwZWVkID0gc3BlZWQ7CisJCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZw cml2X2Rldi0+Z2FkZ2V0LCBVU0JfU1RBVEVfUE9XRVJFRCk7CisJCWNkbnMzX2VwMF9jb25maWco cHJpdl9kZXYpOworCX0KKworCS8qIERpc2Nvbm5lY3Rpb24gZGV0ZWN0ZWQgKi8KKwlpZiAodXNi X2lzdHMgJiAoVVNCX0lTVFNfRElTMkkgfCBVU0JfSVNUU19ESVNJKSkgeworCQlpZiAocHJpdl9k ZXYtPmdhZGdldF9kcml2ZXIgJiYKKwkJICAgIHByaXZfZGV2LT5nYWRnZXRfZHJpdmVyLT5kaXNj b25uZWN0KSB7CisJCQlzcGluX3VubG9jaygmcHJpdl9kZXYtPmxvY2spOworCQkJcHJpdl9kZXYt PmdhZGdldF9kcml2ZXItPmRpc2Nvbm5lY3QoJnByaXZfZGV2LT5nYWRnZXQpOworCQkJc3Bpbl9s b2NrKCZwcml2X2Rldi0+bG9jayk7CisJCX0KKworCQlwcml2X2Rldi0+Z2FkZ2V0LnNwZWVkID0g VVNCX1NQRUVEX1VOS05PV047CisJCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZwcml2X2Rldi0+Z2Fk Z2V0LCBVU0JfU1RBVEVfTk9UQVRUQUNIRUQpOworCQljZG5zM19nYWRnZXRfdW5jb25maWcocHJp dl9kZXYpOworCX0KKworCS8qIHJlc2V0Ki8KKwlpZiAodXNiX2lzdHMgJiAoVVNCX0lTVFNfVVdS RVNJIHwgVVNCX0lTVFNfVUhSRVNJIHwgVVNCX0lTVFNfVTJSRVNJKSkgeworCQkvKnJlYWQgYWdh aW4gdG8gY2hlY2sgdGhlIGFjdHVhbGwgc3BlZWQqLworCQlzcGVlZCA9IGNkbnMzX2dldF9zcGVl ZChwcml2X2Rldik7CisJCXVzYl9nYWRnZXRfc2V0X3N0YXRlKCZwcml2X2Rldi0+Z2FkZ2V0LCBV U0JfU1RBVEVfREVGQVVMVCk7CisJCXByaXZfZGV2LT5nYWRnZXQuc3BlZWQgPSBzcGVlZDsKKwkJ Y2RuczNfZ2FkZ2V0X3VuY29uZmlnKHByaXZfZGV2KTsKKwkJY2RuczNfZXAwX2NvbmZpZyhwcml2 X2Rldik7CisJfQorfQorCisvKioKKyAqIGNkbnMzX2RldmljZV9pcnFfaGFuZGxlci0gaW50ZXJy dXB0IGhhbmRsZXIgZm9yIGRldmljZSBwYXJ0IG9mIGNvbnRyb2xsZXIKKyAqCisgKiBAaXJxOiBp cnEgbnVtYmVyIGZvciBjZG5zMyBjb3JlIGRldmljZQorICogQGRhdGE6IHN0cnVjdHVyZSBvZiBj ZG5zMworICoKKyAqIFJldHVybnMgSVJRX0hBTkRMRUQgb3IgSVJRX05PTkUKKyAqLworc3RhdGlj IGlycXJldHVybl90IGNkbnMzX2RldmljZV9pcnFfaGFuZGxlcihpbnQgaXJxLCB2b2lkICpkYXRh KQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2OworCXN0cnVjdCBjZG5zMyAqY2Ru cyA9IGRhdGE7CisJaXJxcmV0dXJuX3QgcmV0ID0gSVJRX05PTkU7CisJdW5zaWduZWQgbG9uZyBm bGFnczsKKwl1MzIgcmVnOworCisJcHJpdl9kZXYgPSBjZG5zLT5nYWRnZXRfZGV2OworCXNwaW5f bG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCisJLyogY2hlY2sgVVNCIGRl dmljZSBpbnRlcnJ1cHQgKi8KKwlyZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9pc3Rz KTsKKwl3cml0ZWwocmVnLCAmcHJpdl9kZXYtPnJlZ3MtPnVzYl9pc3RzKTsKKworCWlmIChyZWcp IHsKKwkJZGV2X2RiZyhwcml2X2Rldi0+ZGV2LCAiSVJROiB1c2JfaXN0czogJTA4WFxuIiwgcmVn KTsKKwkJY2RuczNfY2hlY2tfdXNiX2ludGVycnVwdF9wcm9jZWVkKHByaXZfZGV2LCByZWcpOwor CQlyZXQgPSBJUlFfSEFORExFRDsKKwl9CisKKwkvKiBjaGVjayBlbmRwb2ludCBpbnRlcnJ1cHQg Ki8KKwlyZWcgPSByZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPmVwX2lzdHMpOworCisJLyogaGFuZGxl IGRlZmF1bHQgZW5kcG9pbnQgT1VUICovCisJaWYgKHJlZyAmIEVQX0lTVFNfRVBfT1VUMCkgewor CQljZG5zM19jaGVja19lcDBfaW50ZXJydXB0X3Byb2NlZWQocHJpdl9kZXYsIFVTQl9ESVJfT1VU KTsKKwkJcmV0ID0gSVJRX0hBTkRMRUQ7CisJfQorCisJLyogaGFuZGxlIGRlZmF1bHQgZW5kcG9p bnQgSU4gKi8KKwlpZiAocmVnICYgRVBfSVNUU19FUF9JTjApIHsKKwkJY2RuczNfY2hlY2tfZXAw X2ludGVycnVwdF9wcm9jZWVkKHByaXZfZGV2LCBVU0JfRElSX0lOKTsKKwkJcmV0ID0gSVJRX0hB TkRMRUQ7CisJfQorCisJLyogY2hlY2sgaWYgaW50ZXJydXB0IGZyb20gbm9uIGRlZmF1bHQgZW5k cG9pbnQsIGlmIG5vIGV4aXQgKi8KKwlyZWcgJj0gfihFUF9JU1RTX0VQX09VVDAgfCBFUF9JU1RT X0VQX0lOMCk7CisJaWYgKCFyZWcpCisJCWdvdG8gaXJxZW5kOworCisJZG8geworCQl1bnNpZ25l ZCBpbnQgYml0X3BvcyA9IGZmcyhyZWcpOworCQl1MzIgYml0X21hc2sgPSAxIDw8IChiaXRfcG9z IC0gMSk7CisJCWludCBpbmRleDsKKworCQlpbmRleCA9IGNkbnMzX2VwX3JlZ19wb3NfdG9faW5k ZXgoYml0X3Bvcyk7CisJCWNkbnMzX2NoZWNrX2VwX2ludGVycnVwdF9wcm9jZWVkKHByaXZfZGV2 LT5lcHNbaW5kZXhdKTsKKwkJcmVnICY9IH5iaXRfbWFzazsKKwkJcmV0ID0gSVJRX0hBTkRMRUQ7 CisJfSB3aGlsZSAocmVnKTsKKworaXJxZW5kOgorCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnBy aXZfZGV2LT5sb2NrLCBmbGFncyk7CisJcmV0dXJuIHJldDsKK30KKworLyoqCisgKiBjZG5zM19l cF9vbmNoaXBfYnVmZmVyX3Jlc2VydmUgLSBUcnkgdG8gcmVzZXJ2ZSBvbmNoaXAgYnVmIGZvciBF UAorICoKKyAqIFRoZSByZWFsIHJlc2VydmF0aW9uIHdpbGwgb2NjdXIgZHVyaW5nIHdyaXRlIHRv IEVQX0NGRyByZWdpc3RlciwKKyAqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBjaGVjayBpZiB0 aGUgJ3NpemUnIHJlc2VydmF0aW9uIGlzIGFsbG93ZWQuCisgKgorICogQHByaXZfZGV2OiBleHRl bmRlZCBnYWRnZXQgb2JqZWN0CisgKiBAc2l6ZTogdGhlIHNpemUgKEtCKSBmb3IgRVAgd291bGQg bGlrZSB0byBhbGxvY2F0ZQorICoKKyAqIFJldHVybiAwIGlmIHRoZSByZXF1aXJlZCBzaXplIGNh biBtZXQgb3IgbmVnYXRpdmUgdmFsdWUgb24gZmFpbHVyZQorICovCitzdGF0aWMgaW50IGNkbnMz X2VwX29uY2hpcF9idWZmZXJfcmVzZXJ2ZShzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiwK KwkJCQkJICBpbnQgc2l6ZSkKK3sKKwl1MzIgb25jaGlwX21lbTsKKworCXByaXZfZGV2LT5vbmNo aXBfbWVtX2FsbG9jYXRlZF9zaXplICs9IHNpemU7CisKKwlvbmNoaXBfbWVtID0gVVNCX0NBUDJf QUNUVUFMX01FTV9TSVpFKHJlYWRsKCZwcml2X2Rldi0+cmVncy0+dXNiX2NhcDIpKTsKKwlpZiAo IW9uY2hpcF9tZW0pCisJCW9uY2hpcF9tZW0gPSAyNTY7CisKKwkvKiAyS0IgaXMgcmVzZXJ2ZWQg Zm9yIEVQMCovCisJb25jaGlwX21lbSAtPSAyOworCWlmIChwcml2X2Rldi0+b25jaGlwX21lbV9h bGxvY2F0ZWRfc2l6ZSA+IG9uY2hpcF9tZW0pIHsKKwkJcHJpdl9kZXYtPm9uY2hpcF9tZW1fYWxs b2NhdGVkX3NpemUgLT0gc2l6ZTsKKwkJcmV0dXJuIC1FUEVSTTsKKwl9CisKKwlyZXR1cm4gMDsK K30KKworLyoqCisgKiBjZG5zM19lcF9jb25maWcgQ29uZmlndXJlIGhhcmR3YXJlIGVuZHBvaW50 CisgKiBAcHJpdl9lcDogZXh0ZW5kZWQgZW5kcG9pbnQgb2JqZWN0CisgKi8KK3ZvaWQgY2RuczNf ZXBfY29uZmlnKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCkKK3sKKwlib29sIGlzX2lz b19lcCA9IChwcml2X2VwLT50eXBlID09IFVTQl9FTkRQT0lOVF9YRkVSX0lTT0MpOworCXN0cnVj dCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCXUzMiBiRW5k cG9pbnRBZGRyZXNzID0gcHJpdl9lcC0+bnVtIHwgcHJpdl9lcC0+ZGlyOworCXUzMiBpbnRlcnJ1 cHRfbWFzayA9IEVQX1NUU19FTl9UUkJFUlJFTjsKKwl1MzIgbWF4X3BhY2tldF9zaXplID0gMDsK Kwl1MzIgZXBfY2ZnID0gMDsKKwlpbnQgcmV0OworCisJaWYgKCFwcml2X2VwLT5kaXIpCisJCWlu dGVycnVwdF9tYXNrIHw9IEVQX1NUU19FTl9ERVNDTUlTRU47CisKKwlpZiAocHJpdl9lcC0+dHlw ZSA9PSBVU0JfRU5EUE9JTlRfWEZFUl9JTlQpIHsKKwkJZXBfY2ZnID0gRVBfQ0ZHX0VQVFlQRShV U0JfRU5EUE9JTlRfWEZFUl9JTlQpOworCX0gZWxzZSBpZiAocHJpdl9lcC0+dHlwZSA9PSBVU0Jf RU5EUE9JTlRfWEZFUl9CVUxLKSB7CisJCWVwX2NmZyA9IEVQX0NGR19FUFRZUEUoVVNCX0VORFBP SU5UX1hGRVJfQlVMSyk7CisJfSBlbHNlIHsKKwkJZXBfY2ZnID0gRVBfQ0ZHX0VQVFlQRShVU0Jf RU5EUE9JTlRfWEZFUl9JU09DKTsKKwkJaW50ZXJydXB0X21hc2sgPSAweEZGRkZGRkZGOworCX0K KworCXN3aXRjaCAocHJpdl9kZXYtPmdhZGdldC5zcGVlZCkgeworCWNhc2UgVVNCX1NQRUVEX0ZV TEw6CisJCW1heF9wYWNrZXRfc2l6ZSA9IGlzX2lzb19lcCA/IDEwMjMgOiA2NDsKKwkJYnJlYWs7 CisJY2FzZSBVU0JfU1BFRURfSElHSDoKKwkJbWF4X3BhY2tldF9zaXplID0gaXNfaXNvX2VwID8g MTAyNCA6IDUxMjsKKwkJYnJlYWs7CisJY2FzZSBVU0JfU1BFRURfU1VQRVI6CisJCW1heF9wYWNr ZXRfc2l6ZSA9IDEwMjQ7CisJCWJyZWFrOworCWRlZmF1bHQ6CisJCS8qIGFsbCBvdGhlciBzcGVl ZCBhcmUgbm90IHN1cHBvcnRlZCAqLworCQlyZXR1cm47CisJfQorCisJcmV0ID0gY2RuczNfZXBf b25jaGlwX2J1ZmZlcl9yZXNlcnZlKHByaXZfZGV2LCBDRE5TM19FUF9CVUZfU0laRSk7CisJaWYg KHJldCkgeworCQlkZXZfZXJyKHByaXZfZGV2LT5kZXYsICJvbmNoaXAgbWVtIGlzIGZ1bGwsIGVw IGlzIGludmFsaWRcbiIpOworCQlyZXR1cm47CisJfQorCisJZXBfY2ZnIHw9IEVQX0NGR19NQVhQ S1RTSVpFKG1heF9wYWNrZXRfc2l6ZSkgfAorCQkgIEVQX0NGR19CVUZGRVJJTkcoQ0ROUzNfRVBf QlVGX1NJWkUgLSAxKSB8CisJCSAgRVBfQ0ZHX01BWEJVUlNUKHByaXZfZXAtPmVuZHBvaW50Lm1h eGJ1cnN0KTsKKworCWNkbnMzX3NlbGVjdF9lcChwcml2X2RldiwgYkVuZHBvaW50QWRkcmVzcyk7 CisKKwl3cml0ZWwoZXBfY2ZnLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX2NmZyk7CisJd3JpdGVsKGlu dGVycnVwdF9tYXNrLCAmcHJpdl9kZXYtPnJlZ3MtPmVwX3N0c19lbik7CisKKwlkZXZfZGJnKHBy aXZfZGV2LT5kZXYsICJDb25maWd1cmUgJXM6IHdpdGggdmFsICUwOHhcbiIsCisJCXByaXZfZXAt Pm5hbWUsIGVwX2NmZyk7CisKKwkvKiBlbmFibGUgaW50ZXJydXB0IGZvciBzZWxlY3RlZCBlbmRw b2ludCAqLworCWNkbnMzX3NldF9yZWdpc3Rlcl9iaXQoJnByaXZfZGV2LT5yZWdzLT5lcF9pZW4s CisJCQkgICAgICAgY2RuczNfZXBfYWRkcl90b19iaXRfcG9zKGJFbmRwb2ludEFkZHJlc3MpKTsK K30KKworLyogRmluZCBjb3JyZWN0IGRpcmVjdGlvbiBmb3IgSFcgZW5kcG9pbnQgYWNjb3JkaW5n IHRvIGRlc2NyaXB0aW9uICovCitzdGF0aWMgaW50IGNkbnMzX2VwX2Rpcl9pc19jb3JyZWN0KHN0 cnVjdCB1c2JfZW5kcG9pbnRfZGVzY3JpcHRvciAqZGVzYywKKwkJCQkgICBzdHJ1Y3QgY2RuczNf ZW5kcG9pbnQgKnByaXZfZXApCit7CisJcmV0dXJuIChwcml2X2VwLT5lbmRwb2ludC5jYXBzLmRp cl9pbiAmJiB1c2JfZW5kcG9pbnRfZGlyX2luKGRlc2MpKSB8fAorCSAgICAgICAocHJpdl9lcC0+ ZW5kcG9pbnQuY2Fwcy5kaXJfb3V0ICYmIHVzYl9lbmRwb2ludF9kaXJfb3V0KGRlc2MpKTsKK30K Kworc3RhdGljIHN0cnVjdAorY2RuczNfZW5kcG9pbnQgKmNkbnMzX2ZpbmRfYXZhaWxhYmxlX2Vw KHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LAorCQkJCQlzdHJ1Y3QgdXNiX2VuZHBvaW50 X2Rlc2NyaXB0b3IgKmRlc2MpCit7CisJc3RydWN0IHVzYl9lcCAqZXA7CisJc3RydWN0IGNkbnMz X2VuZHBvaW50ICpwcml2X2VwOworCisJbGlzdF9mb3JfZWFjaF9lbnRyeShlcCwgJnByaXZfZGV2 LT5nYWRnZXQuZXBfbGlzdCwgZXBfbGlzdCkgeworCQl1bnNpZ25lZCBsb25nIG51bTsKKwkJaW50 IHJldDsKKwkJLyogZXAgbmFtZSBwYXR0ZXJuIGxpa2VzIGVwWGluIG9yIGVwWG91dCAqLworCQlj aGFyIGNbMl0gPSB7ZXAtPm5hbWVbMl0sICdcMCd9OworCisJCXJldCA9IGtzdHJ0b3VsKGMsIDEw LCAmbnVtKTsKKwkJaWYgKHJldCkKKwkJCXJldHVybiBFUlJfUFRSKHJldCk7CisKKwkJcHJpdl9l cCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsKKwkJaWYgKGNkbnMzX2VwX2Rpcl9pc19jb3JyZWN0KGRl c2MsIHByaXZfZXApKSB7CisJCQlpZiAoIShwcml2X2VwLT5mbGFncyAmIEVQX0NMQUlNRUQpKSB7 CisJCQkJcHJpdl9lcC0+bnVtICA9IG51bTsKKwkJCQlyZXR1cm4gcHJpdl9lcDsKKwkJCX0KKwkJ fQorCX0KKwlyZXR1cm4gRVJSX1BUUigtRU5PRU5UKTsKK30KKworc3RhdGljIHN0cnVjdAordXNi X2VwICpjZG5zM19nYWRnZXRfbWF0Y2hfZXAoc3RydWN0IHVzYl9nYWRnZXQgKmdhZGdldCwKKwkJ CSAgICAgIHN0cnVjdCB1c2JfZW5kcG9pbnRfZGVzY3JpcHRvciAqZGVzYywKKwkJCSAgICAgIHN0 cnVjdCB1c2Jfc3NfZXBfY29tcF9kZXNjcmlwdG9yICpjb21wX2Rlc2MpCit7CisJc3RydWN0IGNk bnMzX2RldmljZSAqcHJpdl9kZXYgPSBnYWRnZXRfdG9fY2RuczNfZGV2aWNlKGdhZGdldCk7CisJ c3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisK Kwlwcml2X2VwID0gY2RuczNfZmluZF9hdmFpbGFibGVfZXAocHJpdl9kZXYsIGRlc2MpOworCWlm IChJU19FUlIocHJpdl9lcCkpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAibm8gYXZhaWxh YmxlIGVwXG4iKTsKKwkJcmV0dXJuIE5VTEw7CisJfQorCisJZGV2X2RiZyhwcml2X2Rldi0+ZGV2 LCAibWF0Y2ggZW5kcG9pbnQ6ICVzXG4iLCBwcml2X2VwLT5uYW1lKTsKKworCXNwaW5fbG9ja19p cnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCXByaXZfZXAtPmVuZHBvaW50LmRlc2Mg PSBkZXNjOworCXByaXZfZXAtPmRpciAgPSB1c2JfZW5kcG9pbnRfZGlyX2luKGRlc2MpID8gVVNC X0RJUl9JTiA6IFVTQl9ESVJfT1VUOworCXByaXZfZXAtPnR5cGUgPSB1c2JfZW5kcG9pbnRfdHlw ZShkZXNjKTsKKwlwcml2X2VwLT5mbGFncyB8PSBFUF9DTEFJTUVEOworCXNwaW5fdW5sb2NrX2ly cXJlc3RvcmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisJcmV0dXJuICZwcml2X2VwLT5lbmRw b2ludDsKK30KKworLyoqCisgKiBjZG5zM19nYWRnZXRfZXBfYWxsb2NfcmVxdWVzdCBBbGxvY2F0 ZXMgcmVxdWVzdAorICogQGVwOiBlbmRwb2ludCBvYmplY3QgYXNzb2NpYXRlZCB3aXRoIHJlcXVl c3QKKyAqIEBnZnBfZmxhZ3M6IGdmcCBmbGFncworICoKKyAqIFJldHVybnMgYWxsb2NhdGVkIHJl cXVlc3QgYWRkcmVzcywgTlVMTCBvbiBhbGxvY2F0aW9uIGVycm9yCisgKi8KK3N0cnVjdCB1c2Jf cmVxdWVzdCAqY2RuczNfZ2FkZ2V0X2VwX2FsbG9jX3JlcXVlc3Qoc3RydWN0IHVzYl9lcCAqZXAs CisJCQkJCQkgIGdmcF90IGdmcF9mbGFncykKK3sKKwlzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnBy aXZfZXAgPSBlcF90b19jZG5zM19lcChlcCk7CisJc3RydWN0IGNkbnMzX3JlcXVlc3QgKnByaXZf cmVxOworCisJcHJpdl9yZXEgPSBremFsbG9jKHNpemVvZigqcHJpdl9yZXEpLCBnZnBfZmxhZ3Mp OworCWlmICghcHJpdl9yZXEpCisJCXJldHVybiBOVUxMOworCisJcHJpdl9yZXEtPnByaXZfZXAg PSBwcml2X2VwOworCisJdHJhY2VfY2RuczNfYWxsb2NfcmVxdWVzdChwcml2X3JlcSk7CisJcmV0 dXJuICZwcml2X3JlcS0+cmVxdWVzdDsKK30KKworLyoqCisgKiBjZG5zM19nYWRnZXRfZXBfZnJl ZV9yZXF1ZXN0IEZyZWUgbWVtb3J5IG9jY3VwaWVkIGJ5IHJlcXVlc3QKKyAqIEBlcDogZW5kcG9p bnQgb2JqZWN0IGFzc29jaWF0ZWQgd2l0aCByZXF1ZXN0CisgKiBAcmVxdWVzdDogcmVxdWVzdCB0 byBmcmVlIG1lbW9yeQorICovCit2b2lkIGNkbnMzX2dhZGdldF9lcF9mcmVlX3JlcXVlc3Qoc3Ry dWN0IHVzYl9lcCAqZXAsCisJCQkJICBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3QpCit7CisJ c3RydWN0IGNkbnMzX3JlcXVlc3QgKnByaXZfcmVxID0gdG9fY2RuczNfcmVxdWVzdChyZXF1ZXN0 KTsKKworCXRyYWNlX2NkbnMzX2ZyZWVfcmVxdWVzdChwcml2X3JlcSk7CisJa2ZyZWUocHJpdl9y ZXEpOworfQorCisvKioKKyAqIGNkbnMzX2dhZGdldF9lcF9lbmFibGUgRW5hYmxlIGVuZHBvaW50 CisgKiBAZXA6IGVuZHBvaW50IG9iamVjdAorICogQGRlc2M6IGVuZHBvaW50IGRlc2NyaXB0b3IK KyAqCisgKiBSZXR1cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUKKyAqLwor c3RhdGljIGludCBjZG5zM19nYWRnZXRfZXBfZW5hYmxlKHN0cnVjdCB1c2JfZXAgKmVwLAorCQkJ CSAgY29uc3Qgc3RydWN0IHVzYl9lbmRwb2ludF9kZXNjcmlwdG9yICpkZXNjKQoreworCXN0cnVj dCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcDsKKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rl djsKKwl1bnNpZ25lZCBsb25nIGZsYWdzOworCWludCByZXQ7CisJdTMyIHJlZzsKKworCXByaXZf ZXAgPSBlcF90b19jZG5zM19lcChlcCk7CisJcHJpdl9kZXYgPSBwcml2X2VwLT5jZG5zM19kZXY7 CisKKwlpZiAoIWVwIHx8ICFkZXNjIHx8IGRlc2MtPmJEZXNjcmlwdG9yVHlwZSAhPSBVU0JfRFRf RU5EUE9JTlQpIHsKKwkJZGV2X2RiZyhwcml2X2Rldi0+ZGV2LCAidXNic3M6IGludmFsaWQgcGFy YW1ldGVyc1xuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmICghZGVzYy0+d01heFBh Y2tldFNpemUpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAidXNic3M6IG1pc3Npbmcgd01h eFBhY2tldFNpemVcbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlpZiAoZGV2X1dBUk5f T05DRShwcml2X2Rldi0+ZGV2LCBwcml2X2VwLT5mbGFncyAmIEVQX0VOQUJMRUQsCisJCQkgICIl cyBpcyBhbHJlYWR5IGVuYWJsZWRcbiIsIHByaXZfZXAtPm5hbWUpKQorCQlyZXR1cm4gMDsKKwor CXJldCA9IGNkbnMzX2FsbG9jYXRlX3RyYl9wb29sKHByaXZfZXApOworCWlmIChyZXQpCisJCXJl dHVybiByZXQ7CisKKwl0cmFjZV9jZG5zM19nYWRnZXRfZXBfZW5hYmxlKHByaXZfZXApOworCXNw aW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCisJcHJpdl9lcC0+ZW5k cG9pbnQuZGVzYyA9IGRlc2M7CisJcHJpdl9lcC0+ZGlyID0gdXNiX2VuZHBvaW50X2Rpcl9pbihk ZXNjKSA/IFVTQl9ESVJfSU4gOiBVU0JfRElSX09VVDsKKwlwcml2X2VwLT50eXBlID0gdXNiX2Vu ZHBvaW50X3R5cGUoZGVzYyk7CisKKwljZG5zM19zZWxlY3RfZXAocHJpdl9kZXYsIGRlc2MtPmJF bmRwb2ludEFkZHJlc3MpOworCXdyaXRlbChFUF9DTURfRVBSU1QsICZwcml2X2Rldi0+cmVncy0+ ZXBfY21kKTsKKworCXJldCA9IGNkbnMzX2hhbmRzaGFrZSgmcHJpdl9kZXYtPnJlZ3MtPmVwX2Nt ZCwKKwkJCSAgICAgIEVQX0NNRF9DU1RBTEwgfCBFUF9DTURfRVBSU1QsIDAsIDEwMCk7CisKKwlj ZG5zM19zZXRfcmVnaXN0ZXJfYml0KCZwcml2X2Rldi0+cmVncy0+ZXBfY2ZnLCBFUF9DRkdfRU5B QkxFKTsKKworCWVwLT5kZXNjID0gZGVzYzsKKwlwcml2X2VwLT5mbGFncyAmPSB+KEVQX1BFTkRJ TkdfUkVRVUVTVCB8IEVQX1NUQUxMKTsKKwlwcml2X2VwLT5mbGFncyB8PSBFUF9FTkFCTEVEIHwg RVBfVVBEQVRFX0VQX1RSQkFERFI7CisJcHJpdl9lcC0+ZW5xdWV1ZSA9IDA7CisJcHJpdl9lcC0+ ZGVxdWV1ZSA9IDA7CisJcmVnID0gcmVhZGwoJnByaXZfZGV2LT5yZWdzLT5lcF9zdHMpOworCXBy aXZfZXAtPnBjcyA9ICEhRVBfU1RTX0NDUyhyZWcpOworCXByaXZfZXAtPmNjcyA9ICEhRVBfU1RT X0NDUyhyZWcpOworCS8qIG9uZSBUUkIgaXMgcmVzZXJ2ZWQgZm9yIGxpbmsgVFJCIHVzZWQgaW4g RE1VTFQgbW9kZSovCisJcHJpdl9lcC0+ZnJlZV90cmJzID0gVFJCU19QRVJfU0VHTUVOVCAtIDE7 CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCXJl dHVybiAwOworfQorCisvKioKKyAqIGNkbnMzX2dhZGdldF9lcF9kaXNhYmxlIERpc2FibGUgZW5k cG9pbnQKKyAqIEBlcDogZW5kcG9pbnQgb2JqZWN0CisgKgorICogUmV0dXJucyAwIG9uIHN1Y2Nl c3MsIGVycm9yIGNvZGUgZWxzZXdoZXJlCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfZ2FkZ2V0X2Vw X2Rpc2FibGUoc3RydWN0IHVzYl9lcCAqZXApCit7CisJc3RydWN0IGNkbnMzX2VuZHBvaW50ICpw cml2X2VwOworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2OworCXVuc2lnbmVkIGxvbmcg ZmxhZ3M7CisJaW50IHJldCA9IDA7CisJc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXF1ZXN0OworCXUz MiBlcF9jZmc7CisKKwlpZiAoIWVwKSB7CisJCWRldl9kYmcocHJpdl9kZXYtPmRldiwgInVzYnNz OiBpbnZhbGlkIHBhcmFtZXRlcnNcbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlwcml2 X2VwID0gZXBfdG9fY2RuczNfZXAoZXApOworCXByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2 OworCisJaWYgKGRldl9XQVJOX09OQ0UocHJpdl9kZXYtPmRldiwgIShwcml2X2VwLT5mbGFncyAm IEVQX0VOQUJMRUQpLAorCQkJICAiJXMgaXMgYWxyZWFkeSBkaXNhYmxlZFxuIiwgcHJpdl9lcC0+ bmFtZSkpCisJCXJldHVybiAwOworCisJc3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2Nr LCBmbGFncyk7CisKKwl0cmFjZV9jZG5zM19nYWRnZXRfZXBfZGlzYWJsZShwcml2X2VwKTsKKwor CWNkbnMzX3NlbGVjdF9lcChwcml2X2RldiwgZXAtPmRlc2MtPmJFbmRwb2ludEFkZHJlc3MpOwor CXJldCA9IGNkbnMzX2RhdGFfZmx1c2gocHJpdl9lcCk7CisKKwllcF9jZmcgPSByZWFkbCgmcHJp dl9kZXYtPnJlZ3MtPmVwX2NmZyk7CisJZXBfY2ZnICY9IH5FUF9DRkdfRU5BQkxFOworCXdyaXRl bChlcF9jZmcsICZwcml2X2Rldi0+cmVncy0+ZXBfY2ZnKTsKKworCXdoaWxlICghbGlzdF9lbXB0 eSgmcHJpdl9lcC0+cmVxdWVzdF9saXN0KSkgeworCQlyZXF1ZXN0ID0gY2RuczNfbmV4dF9yZXF1 ZXN0KCZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpOworCisJCWNkbnMzX2dhZGdldF9naXZlYmFjayhw cml2X2VwLCB0b19jZG5zM19yZXF1ZXN0KHJlcXVlc3QpLAorCQkJCSAgICAgIC1FU0hVVERPV04p OworCX0KKworCWlmIChwcml2X2VwLT5kZXNjbWlzX3JlcSkgeworCQlrZnJlZShwcml2X2VwLT5k ZXNjbWlzX3JlcS0+cmVxdWVzdC5idWYpOworCQljZG5zM19nYWRnZXRfZXBfZnJlZV9yZXF1ZXN0 KCZwcml2X2VwLT5lbmRwb2ludCwKKwkJCQkJICAgICAmcHJpdl9lcC0+ZGVzY21pc19yZXEtPnJl cXVlc3QpOworCQlwcml2X2VwLT5kZXNjbWlzX3JlcSA9IE5VTEw7CisJCXByaXZfZXAtPmRlc2Nt aXNfcGVuZGluZyA9IGZhbHNlOworCQlwcml2X2VwLT5kZXNjbWlzX2ZpbmlzaGVkID0gZmFsc2U7 CisJfQorCisJZXAtPmRlc2MgPSBOVUxMOworCXByaXZfZXAtPmZsYWdzICY9IH5FUF9FTkFCTEVE OworCisJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKwor CXJldHVybiByZXQ7Cit9CisKKy8qKgorICogY2RuczNfZ2FkZ2V0X2VwX3F1ZXVlIFRyYW5zZmVy IGRhdGEgb24gZW5kcG9pbnQKKyAqIEBlcDogZW5kcG9pbnQgb2JqZWN0CisgKiBAcmVxdWVzdDog cmVxdWVzdCBvYmplY3QKKyAqIEBnZnBfZmxhZ3M6IGdmcCBmbGFncworICoKKyAqIFJldHVybnMg MCBvbiBzdWNjZXNzLCBlcnJvciBjb2RlIGVsc2V3aGVyZQorICovCitzdGF0aWMgaW50IF9fY2Ru czNfZ2FkZ2V0X2VwX3F1ZXVlKHN0cnVjdCB1c2JfZXAgKmVwLAorCQkJCSAgIHN0cnVjdCB1c2Jf cmVxdWVzdCAqcmVxdWVzdCwKKwkJCQkgICBnZnBfdCBnZnBfZmxhZ3MpCit7CisJc3RydWN0IGNk bnMzX2VuZHBvaW50ICpwcml2X2VwID0gZXBfdG9fY2RuczNfZXAoZXApOworCXN0cnVjdCBjZG5z M19kZXZpY2UgKnByaXZfZGV2ID0gcHJpdl9lcC0+Y2RuczNfZGV2OworCXN0cnVjdCBjZG5zM19y ZXF1ZXN0ICpwcml2X3JlcTsKKwlpbnQgcmV0ID0gMDsKKworCXJlcXVlc3QtPmFjdHVhbCA9IDA7 CisJcmVxdWVzdC0+c3RhdHVzID0gLUVJTlBST0dSRVNTOworCXByaXZfcmVxID0gdG9fY2RuczNf cmVxdWVzdChyZXF1ZXN0KTsKKworCXRyYWNlX2NkbnMzX2VwX3F1ZXVlKHByaXZfcmVxKTsKKwor CS8qIERhdGEgd2lsbCBiZSBjb3BpZWQgZnJvbSBpbnRlcm5hbCB1c2JfcmVxdWVzdCBvYmplY3Qu ICovCisJaWYgKHByaXZfZXAtPmRlc2NtaXNfZmluaXNoZWQpIHsKKwkJcHJpdl9lcC0+ZGVzY21p c19maW5pc2hlZCA9IGZhbHNlOworCQlyZXF1ZXN0LT5hY3R1YWwgPSBwcml2X2VwLT5kZXNjbWlz X3JlcS0+cmVxdWVzdC5hY3R1YWw7CisKKwkJbWVtY3B5KHJlcXVlc3QtPmJ1ZiwgcHJpdl9lcC0+ ZGVzY21pc19yZXEtPnJlcXVlc3QuYnVmLAorCQkgICAgICAgcHJpdl9lcC0+ZGVzY21pc19yZXEt PnJlcXVlc3QuYWN0dWFsKTsKKwkJbGlzdF9hZGRfdGFpbCgmcmVxdWVzdC0+bGlzdCwgJnByaXZf ZXAtPnJlcXVlc3RfbGlzdCk7CisKKwkJY2RuczNfZ2FkZ2V0X2dpdmViYWNrKHByaXZfZXAsCisJ CQkJICAgICAgcHJpdl9yZXEsCisJCQkJICAgICAgcHJpdl9lcC0+ZGVzY21pc19yZXEtPnJlcXVl c3Quc3RhdHVzKTsKKworCQlyZXR1cm4gcmV0OworCX0KKworCXJldCA9IHVzYl9nYWRnZXRfbWFw X3JlcXVlc3RfYnlfZGV2KHByaXZfZGV2LT5zeXNkZXYsIHJlcXVlc3QsCisJCQkJCSAgICB1c2Jf ZW5kcG9pbnRfZGlyX2luKGVwLT5kZXNjKSk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKwor CWxpc3RfYWRkX3RhaWwoJnJlcXVlc3QtPmxpc3QsICZwcml2X2VwLT5yZXF1ZXN0X2xpc3QpOwor CisJY2RuczNfZXBfcnVuX3RyYW5zZmVyKHByaXZfZXAsIHJlcXVlc3QpOworCisJcmV0dXJuIHJl dDsKK30KKworc3RhdGljIGludCBjZG5zM19nYWRnZXRfZXBfcXVldWUoc3RydWN0IHVzYl9lcCAq ZXAsIHN0cnVjdCB1c2JfcmVxdWVzdCAqcmVxdWVzdCwKKwkJCQkgZ2ZwX3QgZ2ZwX2ZsYWdzKQor eworCXN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsK KwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKwlz dHJ1Y3QgdXNiX3JlcXVlc3QgKnpscF9yZXF1ZXN0OworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJ aW50IHJldDsKKworCWlmICghcmVxdWVzdCB8fCAhZXApCisJCXJldHVybiAtRUlOVkFMOworCisJ c3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisJcmV0ID0gX19jZG5z M19nYWRnZXRfZXBfcXVldWUoZXAsIHJlcXVlc3QsIGdmcF9mbGFncyk7CisKKwlpZiAocmV0ID09 IDAgJiYgcmVxdWVzdC0+emVybyAmJiByZXF1ZXN0LT5sZW5ndGggJiYKKwkgICAgKHJlcXVlc3Qt Pmxlbmd0aCAlIGVwLT5tYXhwYWNrZXQgPT0gMCkpIHsKKwkJc3RydWN0IGNkbnMzX3JlcXVlc3Qg KnByaXZfcmVxOworCisJCXpscF9yZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2VwX2FsbG9jX3JlcXVl c3QoZXAsIEdGUF9BVE9NSUMpOworCQl6bHBfcmVxdWVzdC0+YnVmID0gcHJpdl9kZXYtPnpscF9i dWY7CisJCXpscF9yZXF1ZXN0LT5sZW5ndGggPSAwOworCisJCXByaXZfcmVxID0gdG9fY2RuczNf cmVxdWVzdCh6bHBfcmVxdWVzdCk7CisJCXByaXZfcmVxLT5mbGFncyB8PSBSRVFVRVNUX1pMUDsK KworCQlkZXZfZGJnKHByaXZfZGV2LT5kZXYsICJRdWV1aW5nIFpMUCBmb3IgZW5kcG9pbnQ6ICVz XG4iLAorCQkJcHJpdl9lcC0+bmFtZSk7CisJCXJldCA9IF9fY2RuczNfZ2FkZ2V0X2VwX3F1ZXVl KGVwLCB6bHBfcmVxdWVzdCwgZ2ZwX2ZsYWdzKTsKKwl9CisKKwlzcGluX3VubG9ja19pcnFyZXN0 b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCXJldHVybiByZXQ7Cit9CisKKy8qKgorICog Y2RuczNfZ2FkZ2V0X2VwX2RlcXVldWUgUmVtb3ZlIHJlcXVlc3QgZnJvbSB0cmFuc2ZlciBxdWV1 ZQorICogQGVwOiBlbmRwb2ludCBvYmplY3QgYXNzb2NpYXRlZCB3aXRoIHJlcXVlc3QKKyAqIEBy ZXF1ZXN0OiByZXF1ZXN0IG9iamVjdAorICoKKyAqIFJldHVybnMgMCBvbiBzdWNjZXNzLCBlcnJv ciBjb2RlIGVsc2V3aGVyZQorICovCitpbnQgY2RuczNfZ2FkZ2V0X2VwX2RlcXVldWUoc3RydWN0 IHVzYl9lcCAqZXAsCisJCQkgICAgc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXF1ZXN0KQoreworCXN0 cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsKKwlzdHJ1 Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKwlzdHJ1Y3Qg dXNiX3JlcXVlc3QgKnJlcSwgKnJlcV90ZW1wOworCXN0cnVjdCBjZG5zM19yZXF1ZXN0ICpwcml2 X3JlcTsKKwl1bnNpZ25lZCBsb25nIGZsYWdzOworCWludCByZXQgPSAwOworCisJaWYgKCFlcCB8 fCAhcmVxdWVzdCB8fCAhZXAtPmRlc2MpCisJCXJldHVybiAtRUlOVkFMOworCisJc3Bpbl9sb2Nr X2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisKKwlwcml2X3JlcSA9IHRvX2NkbnMz X3JlcXVlc3QocmVxdWVzdCk7CisKKwl0cmFjZV9jZG5zM19lcF9kZXF1ZXVlKHByaXZfcmVxKTsK KworCWNkbnMzX3NlbGVjdF9lcChwcml2X2RldiwgZXAtPmRlc2MtPmJFbmRwb2ludEFkZHJlc3Mp OworCisJbGlzdF9mb3JfZWFjaF9lbnRyeV9zYWZlKHJlcSwgcmVxX3RlbXAsICZwcml2X2VwLT5y ZXF1ZXN0X2xpc3QsIGxpc3QpIHsKKwkJaWYgKHJlcXVlc3QgPT0gcmVxKSB7CisJCQljZG5zM19n YWRnZXRfZ2l2ZWJhY2socHJpdl9lcCwKKwkJCQkJICAgICAgcHJpdl9yZXEsCisJCQkJCSAgICAg IC1FQ09OTlJFU0VUKTsKKwkJCWJyZWFrOworCQl9CisJfQorCisJc3Bpbl91bmxvY2tfaXJxcmVz dG9yZSgmcHJpdl9kZXYtPmxvY2ssIGZsYWdzKTsKKwlyZXR1cm4gcmV0OworfQorCisvKioKKyAq IGNkbnMzX2dhZGdldF9lcF9zZXRfaGFsdCBTZXRzL2NsZWFycyBzdGFsbCBvbiBzZWxlY3RlZCBl bmRwb2ludAorICogQGVwOiBlbmRwb2ludCBvYmplY3QgdG8gc2V0L2NsZWFyIHN0YWxsIG9uCisg KiBAdmFsdWU6IDEgZm9yIHNldCBzdGFsbCwgMCBmb3IgY2xlYXIgc3RhbGwKKyAqCisgKiBSZXR1 cm5zIDAgb24gc3VjY2VzcywgZXJyb3IgY29kZSBlbHNld2hlcmUKKyAqLworaW50IGNkbnMzX2dh ZGdldF9lcF9zZXRfaGFsdChzdHJ1Y3QgdXNiX2VwICplcCwgaW50IHZhbHVlKQoreworCXN0cnVj dCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCA9IGVwX3RvX2NkbnMzX2VwKGVwKTsKKwlzdHJ1Y3Qg Y2RuczNfZGV2aWNlICpwcml2X2RldiA9IHByaXZfZXAtPmNkbnMzX2RldjsKKwl1bnNpZ25lZCBs b25nIGZsYWdzOworCWludCByZXQgPSAwOworCisJaWYgKCEocHJpdl9lcC0+ZmxhZ3MgJiBFUF9F TkFCTEVEKSkKKwkJcmV0dXJuIC1FUEVSTTsKKworCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rl di0+bG9jaywgZmxhZ3MpOworCisJLyogaWYgYWN0dWFsIHRyYW5zZmVyIGlzIHBlbmRpbmcgZGVm ZXIgc2V0dGluZyBzdGFsbCBvbiB0aGlzIGVuZHBvaW50ICovCisJaWYgKChwcml2X2VwLT5mbGFn cyAmIEVQX1BFTkRJTkdfUkVRVUVTVCkgJiYgdmFsdWUpIHsKKwkJcHJpdl9lcC0+ZmxhZ3MgfD0g RVBfU1RBTEw7CisJCWdvdG8gZmluaXNoOworCX0KKworCWRldl9kYmcocHJpdl9kZXYtPmRldiwg IkhhbHQgZW5kcG9pbnQgJXNcbiIsIHByaXZfZXAtPm5hbWUpOworCisJY2RuczNfc2VsZWN0X2Vw KHByaXZfZGV2LCBlcC0+ZGVzYy0+YkVuZHBvaW50QWRkcmVzcyk7CisJaWYgKHZhbHVlKSB7CisJ CWNkbnMzX2VwX3N0YWxsX2ZsdXNoKHByaXZfZXApOworCX0gZWxzZSB7CisJCXByaXZfZXAtPmZs YWdzICY9IH5FUF9XRURHRTsKKwkJd3JpdGVsKEVQX0NNRF9DU1RBTEwgfCBFUF9DTURfRVBSU1Qs ICZwcml2X2Rldi0+cmVncy0+ZXBfY21kKTsKKworCQkvKiB3YWl0IGZvciBFUFJTVCBjbGVhcmVk ICovCisJCXJldCA9IGNkbnMzX2hhbmRzaGFrZSgmcHJpdl9kZXYtPnJlZ3MtPmVwX2NtZCwKKwkJ CQkgICAgICBFUF9DTURfRVBSU1QsIDAsIDEwMCk7CisJCWlmICh1bmxpa2VseShyZXQpKSB7CisJ CQlkZXZfZXJyKHByaXZfZGV2LT5kZXYsCisJCQkJIkNsZWFyaW5nIGhhbHQgY29uZGl0aW9uIGZh aWxlZCBmb3IgJXNcbiIsCisJCQkJcHJpdl9lcC0+bmFtZSk7CisJCQlnb3RvIGZpbmlzaDsKKwor CQl9IGVsc2UgeworCQkJcHJpdl9lcC0+ZmxhZ3MgJj0gfkVQX1NUQUxMOworCQl9CisJfQorCisJ cHJpdl9lcC0+ZmxhZ3MgJj0gfkVQX1BFTkRJTkdfUkVRVUVTVDsKK2ZpbmlzaDoKKwlzcGluX3Vu bG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCisJcmV0dXJuIHJldDsK K30KKworZXh0ZXJuIGNvbnN0IHN0cnVjdCB1c2JfZXBfb3BzIGNkbnMzX2dhZGdldF9lcDBfb3Bz OworCitzdGF0aWMgY29uc3Qgc3RydWN0IHVzYl9lcF9vcHMgY2RuczNfZ2FkZ2V0X2VwX29wcyA9 IHsKKwkuZW5hYmxlID0gY2RuczNfZ2FkZ2V0X2VwX2VuYWJsZSwKKwkuZGlzYWJsZSA9IGNkbnMz X2dhZGdldF9lcF9kaXNhYmxlLAorCS5hbGxvY19yZXF1ZXN0ID0gY2RuczNfZ2FkZ2V0X2VwX2Fs bG9jX3JlcXVlc3QsCisJLmZyZWVfcmVxdWVzdCA9IGNkbnMzX2dhZGdldF9lcF9mcmVlX3JlcXVl c3QsCisJLnF1ZXVlID0gY2RuczNfZ2FkZ2V0X2VwX3F1ZXVlLAorCS5kZXF1ZXVlID0gY2RuczNf Z2FkZ2V0X2VwX2RlcXVldWUsCisJLnNldF9oYWx0ID0gY2RuczNfZ2FkZ2V0X2VwX3NldF9oYWx0 LAorCS5zZXRfd2VkZ2UgPSBjZG5zM19nYWRnZXRfZXBfc2V0X3dlZGdlLAorfTsKKworLyoqCisg KiBjZG5zM19nYWRnZXRfZ2V0X2ZyYW1lIFJldHVybnMgbnVtYmVyIG9mIGFjdHVhbCBJVFAgZnJh bWUKKyAqIEBnYWRnZXQ6IGdhZGdldCBvYmplY3QKKyAqCisgKiBSZXR1cm5zIG51bWJlciBvZiBh Y3R1YWwgSVRQIGZyYW1lCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfZ2FkZ2V0X2dldF9mcmFtZShz dHJ1Y3QgdXNiX2dhZGdldCAqZ2FkZ2V0KQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZf ZGV2ID0gZ2FkZ2V0X3RvX2NkbnMzX2RldmljZShnYWRnZXQpOworCisJcmV0dXJuIHJlYWRsKCZw cml2X2Rldi0+cmVncy0+dXNiX2lwdG4pOworfQorCitzdGF0aWMgaW50IGNkbnMzX2dhZGdldF93 YWtldXAoc3RydWN0IHVzYl9nYWRnZXQgKmdhZGdldCkKK3sKKwlyZXR1cm4gMDsKK30KKworc3Rh dGljIGludCBjZG5zM19nYWRnZXRfc2V0X3NlbGZwb3dlcmVkKHN0cnVjdCB1c2JfZ2FkZ2V0ICpn YWRnZXQsCisJCQkJCWludCBpc19zZWxmcG93ZXJlZCkKK3sKKwlzdHJ1Y3QgY2RuczNfZGV2aWNl ICpwcml2X2RldiA9IGdhZGdldF90b19jZG5zM19kZXZpY2UoZ2FkZ2V0KTsKKwl1bnNpZ25lZCBs b25nIGZsYWdzOworCisJc3Bpbl9sb2NrX2lycXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7 CisJcHJpdl9kZXYtPmlzX3NlbGZwb3dlcmVkID0gISFpc19zZWxmcG93ZXJlZDsKKwlzcGluX3Vu bG9ja19pcnFyZXN0b3JlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCXJldHVybiAwOworfQor CitzdGF0aWMgaW50IGNkbnMzX2dhZGdldF9wdWxsdXAoc3RydWN0IHVzYl9nYWRnZXQgKmdhZGdl dCwgaW50IGlzX29uKQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gZ2FkZ2V0 X3RvX2NkbnMzX2RldmljZShnYWRnZXQpOworCisJaWYgKGlzX29uKQorCQl3cml0ZWwoVVNCX0NP TkZfREVWRU4sICZwcml2X2Rldi0+cmVncy0+dXNiX2NvbmYpOworCWVsc2UKKwkJd3JpdGVsKFVT Ql9DT05GX0RFVkRTLCAmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jb25mKTsKKworCXJldHVybiAwOwor fQorCitzdGF0aWMgdm9pZCBjZG5zM19nYWRnZXRfY29uZmlnKHN0cnVjdCBjZG5zM19kZXZpY2Ug KnByaXZfZGV2KQoreworCXN0cnVjdCBjZG5zM191c2JfcmVncyBfX2lvbWVtICpyZWdzID0gcHJp dl9kZXYtPnJlZ3M7CisKKwljZG5zM19lcDBfY29uZmlnKHByaXZfZGV2KTsKKworCS8qIGVuYWJs ZSBpbnRlcnJ1cHRzIGZvciBlbmRwb2ludCAwIChpbiBhbmQgb3V0KSAqLworCXdyaXRlbChFUF9J RU5fRVBfT1VUMCB8IEVQX0lFTl9FUF9JTjAsICZyZWdzLT5lcF9pZW4pOworCisJLyogZW5hYmxl IGdlbmVyaWMgaW50ZXJydXB0Ki8KKwl3cml0ZWwoVVNCX0lFTl9JTklULCAmcmVncy0+dXNiX2ll bik7CisJd3JpdGVsKFVTQl9DT05GX0NMSzJPRkZEUyB8IFVTQl9DT05GX0wxRFMsICZyZWdzLT51 c2JfY29uZik7CisJd3JpdGVsKFVTQl9DT05GX0RNVUxULCAmcmVncy0+dXNiX2NvbmYpOworCXdy aXRlbChVU0JfQ09ORl9ERVZFTiwgJnJlZ3MtPnVzYl9jb25mKTsKK30KKworLyoqCisgKiBjZG5z M19nYWRnZXRfdWRjX3N0YXJ0IEdhZGdldCBzdGFydAorICogQGdhZGdldDogZ2FkZ2V0IG9iamVj dAorICogQGRyaXZlcjogZHJpdmVyIHdoaWNoIG9wZXJhdGVzIG9uIHRoaXMgZ2FkZ2V0CisgKgor ICogUmV0dXJucyAwIG9uIHN1Y2Nlc3MsIGVycm9yIGNvZGUgZWxzZXdoZXJlCisgKi8KK3N0YXRp YyBpbnQgY2RuczNfZ2FkZ2V0X3VkY19zdGFydChzdHJ1Y3QgdXNiX2dhZGdldCAqZ2FkZ2V0LAor CQkJCSAgc3RydWN0IHVzYl9nYWRnZXRfZHJpdmVyICpkcml2ZXIpCit7CisJc3RydWN0IGNkbnMz X2RldmljZSAqcHJpdl9kZXYgPSBnYWRnZXRfdG9fY2RuczNfZGV2aWNlKGdhZGdldCk7CisJdW5z aWduZWQgbG9uZyBmbGFnczsKKworCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywg ZmxhZ3MpOworCXByaXZfZGV2LT5nYWRnZXRfZHJpdmVyID0gZHJpdmVyOworCWNkbnMzX2dhZGdl dF9jb25maWcocHJpdl9kZXYpOworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnByaXZfZGV2LT5s b2NrLCBmbGFncyk7CisJcmV0dXJuIDA7Cit9CisKKy8qKgorICogY2RuczNfZ2FkZ2V0X3VkY19z dG9wIFN0b3BzIGdhZGdldAorICogQGdhZGdldDogZ2FkZ2V0IG9iamVjdAorICoKKyAqIFJldHVy bnMgMAorICovCitzdGF0aWMgaW50IGNkbnMzX2dhZGdldF91ZGNfc3RvcChzdHJ1Y3QgdXNiX2dh ZGdldCAqZ2FkZ2V0KQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2ID0gZ2FkZ2V0 X3RvX2NkbnMzX2RldmljZShnYWRnZXQpOworCXN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9l cDsKKwl1MzIgYkVuZHBvaW50QWRkcmVzczsKKwlzdHJ1Y3QgdXNiX2VwICplcDsKKwlpbnQgcmV0 ID0gMDsKKwlpbnQgaTsKKworCXByaXZfZGV2LT5nYWRnZXRfZHJpdmVyID0gTlVMTDsKKworCXBy aXZfZGV2LT5vbmNoaXBfbWVtX2FsbG9jYXRlZF9zaXplID0gMDsKKwlwcml2X2Rldi0+Z2FkZ2V0 LnNwZWVkID0gVVNCX1NQRUVEX1VOS05PV047CisKKwlmb3IgKGkgPSAwOyBpIDwgcHJpdl9kZXYt PmVwX251bXMgOyBpKyspCisJCWNkbnMzX2ZyZWVfdHJiX3Bvb2wocHJpdl9kZXYtPmVwc1tpXSk7 CisKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KGVwLCAmcHJpdl9kZXYtPmdhZGdldC5lcF9saXN0LCBl cF9saXN0KSB7CisJCXByaXZfZXAgPSBlcF90b19jZG5zM19lcChlcCk7CisJCWJFbmRwb2ludEFk ZHJlc3MgPSBwcml2X2VwLT5udW0gfCBwcml2X2VwLT5kaXI7CisJCWNkbnMzX3NlbGVjdF9lcChw cml2X2RldiwgYkVuZHBvaW50QWRkcmVzcyk7CisJCXdyaXRlbChFUF9DTURfRVBSU1QsICZwcml2 X2Rldi0+cmVncy0+ZXBfY21kKTsKKwkJcmV0ID0gY2RuczNfaGFuZHNoYWtlKCZwcml2X2Rldi0+ cmVncy0+ZXBfY21kLAorCQkJCSAgICAgIEVQX0NNRF9FUFJTVCwgMCwgMTAwKTsKKwl9CisKKwkv KiBkaXNhYmxlIGludGVycnVwdCBmb3IgZGV2aWNlICovCisJd3JpdGVsKDAsICZwcml2X2Rldi0+ cmVncy0+dXNiX2llbik7CisJd3JpdGVsKFVTQl9DT05GX0RFVkRTLCAmcHJpdl9kZXYtPnJlZ3Mt PnVzYl9jb25mKTsKKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdXNi X2dhZGdldF9vcHMgY2RuczNfZ2FkZ2V0X29wcyA9IHsKKwkuZ2V0X2ZyYW1lID0gY2RuczNfZ2Fk Z2V0X2dldF9mcmFtZSwKKwkud2FrZXVwID0gY2RuczNfZ2FkZ2V0X3dha2V1cCwKKwkuc2V0X3Nl bGZwb3dlcmVkID0gY2RuczNfZ2FkZ2V0X3NldF9zZWxmcG93ZXJlZCwKKwkucHVsbHVwID0gY2Ru czNfZ2FkZ2V0X3B1bGx1cCwKKwkudWRjX3N0YXJ0ID0gY2RuczNfZ2FkZ2V0X3VkY19zdGFydCwK KwkudWRjX3N0b3AgPSBjZG5zM19nYWRnZXRfdWRjX3N0b3AsCisJLm1hdGNoX2VwID0gY2RuczNf Z2FkZ2V0X21hdGNoX2VwLAorfTsKKworc3RhdGljIHZvaWQgY2RuczNfZnJlZV9hbGxfZXAoc3Ry dWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYpCit7CisJaW50IGk7CisKKwlmb3IgKGkgPSAwOyBp IDwgQ0ROUzNfRU5EUE9JTlRTX01BWF9DT1VOVDsgaSsrKQorCQlpZiAocHJpdl9kZXYtPmVwc1tp XSkKKwkJCWRldm1fa2ZyZWUocHJpdl9kZXYtPmRldiwgcHJpdl9kZXYtPmVwc1tpXSk7CisKKwlp ZiAocHJpdl9kZXYtPmdhZGdldC5lcDApCisJCWRldm1fa2ZyZWUocHJpdl9kZXYtPmRldiwgcHJp dl9kZXYtPmdhZGdldC5lcDApOworfQorCisvKioKKyAqIGNkbnMzX2luaXRfZXAgSW5pdGlhbGl6 ZXMgc29mdHdhcmUgZW5kcG9pbnRzIG9mIGdhZGdldAorICogQGNkbnMzOiBleHRlbmRlZCBnYWRn ZXQgb2JqZWN0CisgKgorICogUmV0dXJucyAwIG9uIHN1Y2Nlc3MsIGVycm9yIGNvZGUgZWxzZXdo ZXJlCisgKi8KK3N0YXRpYyBpbnQgY2RuczNfaW5pdF9lcChzdHJ1Y3QgY2RuczNfZGV2aWNlICpw cml2X2RldikKK3sKKwl1MzIgZXBfZW5hYmxlZF9yZWcsIGlzb19lcF9yZWc7CisJc3RydWN0IGNk bnMzX2VuZHBvaW50ICpwcml2X2VwOworCWludCBmb3VuZF9lbmRwb2ludHMgPSAwOworCWludCBl cF9kaXIsIGVwX251bWJlcjsKKwl1MzIgZXBfbWFzazsKKwlpbnQgaTsKKworCS8qIFJlYWQgaXQg ZnJvbSBVU0JfQ0FQMyB0byBVU0JfQ0FQNSAqLworCWVwX2VuYWJsZWRfcmVnID0gcmVhZGwoJnBy aXZfZGV2LT5yZWdzLT51c2JfY2FwMyk7CisJaXNvX2VwX3JlZyA9IHJlYWRsKCZwcml2X2Rldi0+ cmVncy0+dXNiX2NhcDQpOworCisJZGV2X2RiZyhwcml2X2Rldi0+ZGV2LCAiSW5pdGlhbGl6aW5n IG5vbi16ZXJvIGVuZHBvaW50c1xuIik7CisKKwlmb3IgKGkgPSAwOyBpIDwgQ0ROUzNfRU5EUE9J TlRTX01BWF9DT1VOVDsgaSsrKSB7CisJCWVwX251bWJlciA9IChpIC8gMikgKyAxOworCQllcF9k aXIgPSBpICUgMjsKKwkJZXBfbWFzayA9IEJJVCgoMTYgKiBlcF9kaXIpICsgZXBfbnVtYmVyKTsK KworCQlpZiAoIShlcF9lbmFibGVkX3JlZyAmIGVwX21hc2spKQorCQkJY29udGludWU7CisKKwkJ cHJpdl9lcCA9IGRldm1fa3phbGxvYyhwcml2X2Rldi0+ZGV2LCBzaXplb2YoKnByaXZfZXApLAor CQkJCSAgICAgICBHRlBfS0VSTkVMKTsKKwkJaWYgKCFwcml2X2VwKQorCQkJcmV0dXJuIC1FTk9N RU07CisKKwkJLyogc2V0IHBhcmVudCBvZiBlbmRwb2ludCBvYmplY3QgKi8KKwkJcHJpdl9lcC0+ Y2RuczNfZGV2ID0gcHJpdl9kZXY7CisJCXByaXZfZGV2LT5lcHNbZm91bmRfZW5kcG9pbnRzKytd ID0gcHJpdl9lcDsKKworCQlzbnByaW50Zihwcml2X2VwLT5uYW1lLCBzaXplb2YocHJpdl9lcC0+ bmFtZSksICJlcCVkJXMiLAorCQkJIGVwX251bWJlciwgISFlcF9kaXIgPyAiaW4iIDogIm91dCIp OworCQlwcml2X2VwLT5lbmRwb2ludC5uYW1lID0gcHJpdl9lcC0+bmFtZTsKKworCQl1c2JfZXBf c2V0X21heHBhY2tldF9saW1pdCgmcHJpdl9lcC0+ZW5kcG9pbnQsCisJCQkJCSAgIENETlMzX0VQ X01BWF9QQUNLRVRfTElNSVQpOworCQlwcml2X2VwLT5lbmRwb2ludC5tYXhfc3RyZWFtcyA9IENE TlMzX0VQX01BWF9TVFJFQU1TOworCQlwcml2X2VwLT5lbmRwb2ludC5vcHMgPSAmY2RuczNfZ2Fk Z2V0X2VwX29wczsKKwkJaWYgKGVwX2RpcikKKwkJCXByaXZfZXAtPmVuZHBvaW50LmNhcHMuZGly X2luID0gMTsKKwkJZWxzZQorCQkJcHJpdl9lcC0+ZW5kcG9pbnQuY2Fwcy5kaXJfb3V0ID0gMTsK KworCQlpZiAoaXNvX2VwX3JlZyAmIGVwX21hc2spCisJCQlwcml2X2VwLT5lbmRwb2ludC5jYXBz LnR5cGVfaXNvID0gMTsKKworCQlwcml2X2VwLT5lbmRwb2ludC5jYXBzLnR5cGVfYnVsayA9IDE7 CisJCXByaXZfZXAtPmVuZHBvaW50LmNhcHMudHlwZV9pbnQgPSAxOworCQlwcml2X2VwLT5lbmRw b2ludC5tYXhidXJzdCA9IENETlMzX0VQX0JVRl9TSVpFIC0gMTsKKworCQlwcml2X2VwLT5mbGFn cyA9IDA7CisKKwkJZGV2X2luZm8ocHJpdl9kZXYtPmRldiwgIkluaXRpYWxpemVkICAlcyBzdXBw b3J0OiAlcyAlc1xuIiwKKwkJCSBwcml2X2VwLT5uYW1lLAorCQkJIHByaXZfZXAtPmVuZHBvaW50 LmNhcHMudHlwZV9idWxrID8gIkJVTEssIElOVCIgOiAiIiwKKwkJCSBwcml2X2VwLT5lbmRwb2lu dC5jYXBzLnR5cGVfaXNvID8gIklTTyIgOiAiIik7CisKKwkJbGlzdF9hZGRfdGFpbCgmcHJpdl9l cC0+ZW5kcG9pbnQuZXBfbGlzdCwKKwkJCSAgICAgICZwcml2X2Rldi0+Z2FkZ2V0LmVwX2xpc3Qp OworCQlJTklUX0xJU1RfSEVBRCgmcHJpdl9lcC0+cmVxdWVzdF9saXN0KTsKKwl9CisKKwlwcml2 X2Rldi0+ZXBfbnVtcyA9IGZvdW5kX2VuZHBvaW50czsKKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IHZvaWQgY2RuczNfZ2FkZ2V0X2Rpc2FibGUoc3RydWN0IGNkbnMzICpjZG5zKQoreworCXN0cnVj dCBjZG5zM19kZXZpY2UgKnByaXZfZGV2OworCisJcHJpdl9kZXYgPSBjZG5zLT5nYWRnZXRfZGV2 OworCisJaWYgKHByaXZfZGV2LT5nYWRnZXRfZHJpdmVyKQorCQlwcml2X2Rldi0+Z2FkZ2V0X2Ry aXZlci0+ZGlzY29ubmVjdCgmcHJpdl9kZXYtPmdhZGdldCk7CisKKwl1c2JfZ2FkZ2V0X2Rpc2Nv bm5lY3QoJnByaXZfZGV2LT5nYWRnZXQpOworCXByaXZfZGV2LT5nYWRnZXQuc3BlZWQgPSBVU0Jf U1BFRURfVU5LTk9XTjsKK30KKwordm9pZCBjZG5zM19nYWRnZXRfZXhpdChzdHJ1Y3QgY2RuczMg KmNkbnMpCit7CisJc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXY7CisKKwlwcml2X2RldiA9 IGNkbnMtPmdhZGdldF9kZXY7CisKKwljZG5zM19nYWRnZXRfZGlzYWJsZShjZG5zKTsKKworCWRl dm1fZnJlZV9pcnEoY2Rucy0+ZGV2LCBjZG5zLT5pcnEsIGNkbnMpOworCisJcG1fcnVudGltZV9t YXJrX2xhc3RfYnVzeShjZG5zLT5kZXYpOworCXBtX3J1bnRpbWVfcHV0X2F1dG9zdXNwZW5kKGNk bnMtPmRldik7CisKKwl1c2JfZGVsX2dhZGdldF91ZGMoJnByaXZfZGV2LT5nYWRnZXQpOworCisJ Y2RuczNfZnJlZV9hbGxfZXAocHJpdl9kZXYpOworCisJZG1hX2ZyZWVfY29oZXJlbnQocHJpdl9k ZXYtPnN5c2RldiwgOCwgcHJpdl9kZXYtPnNldHVwX2J1ZiwKKwkJCSAgcHJpdl9kZXYtPnNldHVw X2RtYSk7CisJZG1hX2ZyZWVfY29oZXJlbnQocHJpdl9kZXYtPnN5c2RldiwgVFJCX1NJWkUgKiAy LCBwcml2X2Rldi0+ZXAwX3RyYiwKKwkJCSAgcHJpdl9kZXYtPmVwMF90cmJfZG1hKTsKKworCWtm cmVlKHByaXZfZGV2LT56bHBfYnVmKTsKKwlrZnJlZShwcml2X2Rldik7CisJY2Rucy0+Z2FkZ2V0 X2RldiA9IE5VTEw7Cit9CisKK3N0YXRpYyBpbnQgY2RuczNfZ2FkZ2V0X3N0YXJ0KHN0cnVjdCBj ZG5zMyAqY2RucykKK3sKKwlzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2RldjsKKwl1MzIgbWF4 X3NwZWVkOworCWludCByZXQ7CisKKwlwcml2X2RldiA9IGt6YWxsb2Moc2l6ZW9mKCpwcml2X2Rl diksIEdGUF9LRVJORUwpOworCWlmICghcHJpdl9kZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJ Y2Rucy0+Z2FkZ2V0X2RldiA9IHByaXZfZGV2OworCXByaXZfZGV2LT5zeXNkZXYgPSBjZG5zLT5k ZXY7CisJcHJpdl9kZXYtPmRldiA9IGNkbnMtPmRldjsKKwlwcml2X2Rldi0+cmVncyA9IGNkbnMt PmRldl9yZWdzOworCisJbWF4X3NwZWVkID0gdXNiX2dldF9tYXhpbXVtX3NwZWVkKGNkbnMtPmRl dik7CisKKwkvKiBDaGVjayB0aGUgbWF4aW11bV9zcGVlZCBwYXJhbWV0ZXIgKi8KKwlzd2l0Y2gg KG1heF9zcGVlZCkgeworCWNhc2UgVVNCX1NQRUVEX0ZVTEw6CisJY2FzZSBVU0JfU1BFRURfSElH SDoKKwljYXNlIFVTQl9TUEVFRF9TVVBFUjoKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJZGV2X2Vy cihjZG5zLT5kZXYsICJpbnZhbGlkIG1heGltdW1fc3BlZWQgcGFyYW1ldGVyICVkXG4iLAorCQkJ bWF4X3NwZWVkKTsKKwkJLyogZmFsbCB0aHJvdWdoICovCisJY2FzZSBVU0JfU1BFRURfVU5LTk9X TjoKKwkJLyogZGVmYXVsdCB0byBzdXBlcnNwZWVkICovCisJCW1heF9zcGVlZCA9IFVTQl9TUEVF RF9TVVBFUjsKKwkJYnJlYWs7CisJfQorCisJLyogZmlsbCBnYWRnZXQgZmllbGRzICovCisJcHJp dl9kZXYtPmdhZGdldC5tYXhfc3BlZWQgPSBtYXhfc3BlZWQ7CisJcHJpdl9kZXYtPmdhZGdldC5z cGVlZCA9IFVTQl9TUEVFRF9VTktOT1dOOworCXByaXZfZGV2LT5nYWRnZXQub3BzID0gJmNkbnMz X2dhZGdldF9vcHM7CisJcHJpdl9kZXYtPmdhZGdldC5uYW1lID0gInVzYi1zcy1nYWRnZXQiOwor CXByaXZfZGV2LT5nYWRnZXQuc2dfc3VwcG9ydGVkID0gMTsKKworCXNwaW5fbG9ja19pbml0KCZw cml2X2Rldi0+bG9jayk7CisJSU5JVF9XT1JLKCZwcml2X2Rldi0+cGVuZGluZ19zdGF0dXNfd3Es CisJCSAgY2RuczNfcGVuZGluZ19zZXR1cF9zdGF0dXNfaGFuZGxlcik7CisKKwkvKiBpbml0aWFs aXplIGVuZHBvaW50IGNvbnRhaW5lciAqLworCUlOSVRfTElTVF9IRUFEKCZwcml2X2Rldi0+Z2Fk Z2V0LmVwX2xpc3QpOworCisJcmV0ID0gY2RuczNfaW5pdF9lcDAocHJpdl9kZXYpOworCWlmIChy ZXQpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAiRmFpbGVkIHRvIGNyZWF0ZSBlbmRwb2lu dCAwXG4iKTsKKwkJZ290byBlcnIxOworCX0KKworCXJldCA9IGNkbnMzX2luaXRfZXAocHJpdl9k ZXYpOworCWlmIChyZXQpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAiRmFpbGVkIHRvIGNy ZWF0ZSBub24gemVybyBlbmRwb2ludHNcbiIpOworCQlnb3RvIGVycjE7CisJfQorCisJLyogYWxs b2NhdGUgbWVtb3J5IGZvciBkZWZhdWx0IGVuZHBvaW50IFRSQiAqLworCXByaXZfZGV2LT5lcDBf dHJiID0gZG1hX2FsbG9jX2NvaGVyZW50KHByaXZfZGV2LT5zeXNkZXYsIFRSQl9TSVpFICogMiwK KwkJCQkJICAgICAgICZwcml2X2Rldi0+ZXAwX3RyYl9kbWEsIEdGUF9ETUEpOworCWlmICghcHJp dl9kZXYtPmVwMF90cmIpIHsKKwkJZGV2X2Vycihwcml2X2Rldi0+ZGV2LCAiRmFpbGVkIHRvIGFs bG9jYXRlIG1lbW9yeSBmb3IgZXAwIFRSQlxuIik7CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8g ZXJyMTsKKwl9CisKKwkvKiBhbGxvY2F0ZSBtZW1vcnkgZm9yIHNldHVwIHBhY2tldCBidWZmZXIg Ki8KKwlwcml2X2Rldi0+c2V0dXBfYnVmID0gZG1hX2FsbG9jX2NvaGVyZW50KHByaXZfZGV2LT5z eXNkZXYsIDgsCisJCQkJCQkgJnByaXZfZGV2LT5zZXR1cF9kbWEsIEdGUF9ETUEpOworCWlmICgh cHJpdl9kZXYtPnNldHVwX2J1ZikgeworCQlkZXZfZXJyKHByaXZfZGV2LT5kZXYsICJGYWlsZWQg dG8gYWxsb2NhdGUgbWVtb3J5IGZvciBTRVRVUCBidWZmZXJcbiIpOworCQlyZXQgPSAtRU5PTUVN OworCQlnb3RvIGVycjI7CisJfQorCisJZGV2X2RiZyhwcml2X2Rldi0+ZGV2LCAiRGV2aWNlIENv bnRyb2xsZXIgdmVyc2lvbjogJTA4eFxuIiwKKwkJcmVhZGwoJnByaXZfZGV2LT5yZWdzLT51c2Jf Y2FwNikpOworCWRldl9kYmcocHJpdl9kZXYtPmRldiwgIlVTQiBDYXBhYmlsaXRpZXM6OiAlMDh4 XG4iLAorCQlyZWFkbCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAxKSk7CisJZGV2X2RiZyhwcml2 X2Rldi0+ZGV2LCAiT24tQ2hpcCBtZW1vcnkgY25maWd1cmF0aW9uOiAlMDh4XG4iLAorCQlyZWFk bCgmcHJpdl9kZXYtPnJlZ3MtPnVzYl9jYXAyKSk7CisKKwlwcml2X2Rldi0+emxwX2J1ZiA9IGt6 YWxsb2MoQ0ROUzNfRVBfWkxQX0JVRl9TSVpFLCBHRlBfS0VSTkVMKTsKKwlpZiAoIXByaXZfZGV2 LT56bHBfYnVmKSB7CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8gZXJyMzsKKwl9CisKKwkvKiBh ZGQgVVNCIGdhZGdldCBkZXZpY2UgKi8KKwlyZXQgPSB1c2JfYWRkX2dhZGdldF91ZGMocHJpdl9k ZXYtPmRldiwgJnByaXZfZGV2LT5nYWRnZXQpOworCWlmIChyZXQgPCAwKSB7CisJCWRldl9lcnIo cHJpdl9kZXYtPmRldiwKKwkJCSJGYWlsZWQgdG8gcmVnaXN0ZXIgVVNCIGRldmljZSBjb250cm9s bGVyXG4iKTsKKwkJZ290byBlcnI0OworCX0KKworCXJldHVybiAwOworZXJyNDoKKwlrZnJlZShw cml2X2Rldi0+emxwX2J1Zik7CitlcnIzOgorCWRtYV9mcmVlX2NvaGVyZW50KHByaXZfZGV2LT5z eXNkZXYsIDgsIHByaXZfZGV2LT5zZXR1cF9idWYsCisJCQkgIHByaXZfZGV2LT5zZXR1cF9kbWEp OworZXJyMjoKKwlkbWFfZnJlZV9jb2hlcmVudChwcml2X2Rldi0+c3lzZGV2LCBUUkJfU0laRSAq IDIsIHByaXZfZGV2LT5lcDBfdHJiLAorCQkJICBwcml2X2Rldi0+ZXAwX3RyYl9kbWEpOworZXJy MToKKwljZG5zLT5nYWRnZXRfZGV2ID0gTlVMTDsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMg aW50IF9fY2RuczNfZ2FkZ2V0X2luaXQoc3RydWN0IGNkbnMzICpjZG5zKQoreworCXN0cnVjdCBj ZG5zM19kZXZpY2UgKnByaXZfZGV2OworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJaW50IHJldCA9 IDA7CisKKwlyZXQgPSBjZG5zM19nYWRnZXRfc3RhcnQoY2Rucyk7CisJaWYgKHJldCkKKwkJcmV0 dXJuIHJldDsKKworCXByaXZfZGV2ID0gY2Rucy0+Z2FkZ2V0X2RldjsKKwlyZXQgPSBkZXZtX3Jl cXVlc3RfaXJxKGNkbnMtPmRldiwgY2Rucy0+aXJxLCBjZG5zM19kZXZpY2VfaXJxX2hhbmRsZXIs CisJCQkgICAgICAgSVJRRl9TSEFSRUQsIGRldl9uYW1lKGNkbnMtPmRldiksIGNkbnMpOworCisJ aWYgKHJldCkKKwkJZ290byBlcnIwOworCisJcG1fcnVudGltZV9nZXRfc3luYyhjZG5zLT5kZXYp OworCXNwaW5fbG9ja19pcnFzYXZlKCZwcml2X2Rldi0+bG9jaywgZmxhZ3MpOworCXNwaW5fdW5s b2NrX2lycXJlc3RvcmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisJcmV0dXJuIDA7CitlcnIw OgorCWNkbnMzX2dhZGdldF9leGl0KGNkbnMpOworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBp bnQgY2RuczNfZ2FkZ2V0X3N1c3BlbmQoc3RydWN0IGNkbnMzICpjZG5zLCBib29sIGRvX3dha2V1 cCkKK3sKKwljZG5zM19nYWRnZXRfZGlzYWJsZShjZG5zKTsKKwlyZXR1cm4gMDsKK30KKworc3Rh dGljIGludCBjZG5zM19nYWRnZXRfcmVzdW1lKHN0cnVjdCBjZG5zMyAqY2RucywgYm9vbCBoaWJl cm5hdGVkKQoreworCXN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2OworCXVuc2lnbmVkIGxv bmcgZmxhZ3M7CisKKwlwcml2X2RldiA9IGNkbnMtPmdhZGdldF9kZXY7CisJc3Bpbl9sb2NrX2ly cXNhdmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisKKwlpZiAoIXByaXZfZGV2LT5nYWRnZXRf ZHJpdmVyKSB7CisJCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnByaXZfZGV2LT5sb2NrLCBmbGFn cyk7CisJCXJldHVybiAwOworCX0KKworCWNkbnMzX2dhZGdldF9jb25maWcocHJpdl9kZXYpOwor CXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnByaXZfZGV2LT5sb2NrLCBmbGFncyk7CisJcmV0dXJu IDA7Cit9CisKKy8qKgorICogY2RuczNfZ2FkZ2V0X2luaXQgLSBpbml0aWFsaXplIGRldmljZSBz dHJ1Y3R1cmUKKyAqCisgKiBjZG5zOiBjZG5zMyBpbnN0YW5jZQorICoKKyAqIFRoaXMgZnVuY3Rp b24gaW5pdGlhbGl6ZXMgdGhlIGdhZGdldC4KKyAqLworaW50IGNkbnMzX2dhZGdldF9pbml0KHN0 cnVjdCBjZG5zMyAqY2RucykKK3sKKwlzdHJ1Y3QgY2RuczNfcm9sZV9kcml2ZXIgKnJkcnY7CisK KwlyZHJ2ID0gZGV2bV9remFsbG9jKGNkbnMtPmRldiwgc2l6ZW9mKCpyZHJ2KSwgR0ZQX0tFUk5F TCk7CisJaWYgKCFyZHJ2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXJkcnYtPnN0YXJ0CT0gX19j ZG5zM19nYWRnZXRfaW5pdDsKKwlyZHJ2LT5zdG9wCT0gY2RuczNfZ2FkZ2V0X2V4aXQ7CisJcmRy di0+c3VzcGVuZAk9IGNkbnMzX2dhZGdldF9zdXNwZW5kOworCXJkcnYtPnJlc3VtZQk9IGNkbnMz X2dhZGdldF9yZXN1bWU7CisJcmRydi0+c3RhdGUJPSBDRE5TM19ST0xFX1NUQVRFX0lOQUNUSVZF OworCXJkcnYtPm5hbWUJPSAiZ2FkZ2V0IjsKKwljZG5zLT5yb2xlc1tDRE5TM19ST0xFX0dBREdF VF0gPSByZHJ2OworCisJcmV0dXJuIDA7Cit9CmRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9jZG5z My9nYWRnZXQuaCBiL2RyaXZlcnMvdXNiL2NkbnMzL2dhZGdldC5oCm5ldyBmaWxlIG1vZGUgMTAw NjQ0CmluZGV4IDAwMDAwMDAwMDAwMC4uZGIzOThkZmY2NWZjCi0tLSAvZGV2L251bGwKKysrIGIv ZHJpdmVycy91c2IvY2RuczMvZ2FkZ2V0LmgKQEAgLTAsMCArMSwxMTc3IEBACisvKiBTUERYLUxp Y2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMCAqLworLyoKKyAqIFVTQlNTIGRldmljZSBjb250cm9s bGVyIGRyaXZlciBoZWFkZXIgZmlsZQorICoKKyAqIENvcHlyaWdodCAoQykgMjAxOCBDYWRlbmNl LgorICogQ29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCisgKgorICogQXV0aG9yOiBQYXdlbCBM YXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICogICAgICAgICBQYXdlbCBKZXogPHBqZXpA Y2FkZW5jZS5jb20+CisgKiAgICAgICAgIFBldGVyIENoZW4gPHBldGVyLmNoZW5AbnhwLmNvbT4K KyAqLworI2lmbmRlZiBfX0xJTlVYX0NETlMzX0dBREdFVAorI2RlZmluZSBfX0xJTlVYX0NETlMz X0dBREdFVAorI2luY2x1ZGUgPGxpbnV4L3VzYi9nYWRnZXQuaD4KKworLyoKKyAqIFVTQlNTLURF ViByZWdpc3RlciBpbnRlcmZhY2UuCisgKiBUaGlzIGNvcnJlc3BvbmRzIHRvIHRoZSBVU0JTUyBE ZXZpY2UgQ29udHJvbGxlciBJbnRlcmZhY2UKKyAqLworCisvKioKKyAqIHN0cnVjdCBjZG5zM191 c2JfcmVncyAtIGRldmljZSBjb250cm9sbGVyIHJlZ2lzdGVycy4KKyAqIEB1c2JfY29uZjogICAg ICBHbG9iYWwgQ29uZmlndXJhdGlvbiBSZWdpc3Rlci4KKyAqIEB1c2Jfc3RzOiAgICAgICBHbG9i YWwgU3RhdHVzIFJlZ2lzdGVyLgorICogQHVzYl9jbWQ6ICAgICAgIEdsb2JhbCBDb21tYW5kIFJl Z2lzdGVyLgorICogQHVzYl9pcHRuOiAgICAgIElUUC9TT0YgbnVtYmVyIFJlZ2lzdGVyLgorICog QHVzYl9scG06ICAgICAgIEdsb2JhbCBDb21tYW5kIFJlZ2lzdGVyLgorICogQHVzYl9pZW46ICAg ICAgIFVTQiBJbnRlcnJ1cHQgRW5hYmxlIFJlZ2lzdGVyLgorICogQHVzYl9pc3RzOiAgICAgIFVT QiBJbnRlcnJ1cHQgU3RhdHVzIFJlZ2lzdGVyLgorICogQGVwX3NlbDogICAgICAgIEVuZHBvaW50 IFNlbGVjdCBSZWdpc3Rlci4KKyAqIEBlcF90cmFkZHI6ICAgICBFbmRwb2ludCBUcmFuc2ZlciBS aW5nIEFkZHJlc3MgUmVnaXN0ZXIuCisgKiBAZXBfY2ZnOiAgICAgICAgRW5kcG9pbnQgQ29uZmln dXJhdGlvbiBSZWdpc3Rlci4KKyAqIEBlcF9jbWQ6ICAgICAgICBFbmRwb2ludCBDb21tYW5kIFJl Z2lzdGVyLgorICogQGVwX3N0czogICAgICAgIEVuZHBvaW50IFN0YXR1cyBSZWdpc3Rlci4KKyAq IEBlcF9zdHNfc2lkOiAgICBFbmRwb2ludCBTdGF0dXMgUmVnaXN0ZXIuCisgKiBAZXBfc3RzX2Vu OiAgICAgRW5kcG9pbnQgU3RhdHVzIFJlZ2lzdGVyIEVuYWJsZS4KKyAqIEBkcmJsOiAgICAgICAg ICBEb29yYmVsbCBSZWdpc3Rlci4KKyAqIEBlcF9pZW46ICAgICAgICBFUCBJbnRlcnJ1cHQgRW5h YmxlIFJlZ2lzdGVyLgorICogQGVwX2lzdHM6ICAgICAgIEVQIEludGVycnVwdCBTdGF0dXMgUmVn aXN0ZXIuCisgKiBAdXNiX3B3cjogICAgICAgR2xvYmFsIFBvd2VyIENvbmZpZ3VyYXRpb24gUmVn aXN0ZXIuCisgKiBAdXNiX2NvbmYyOiAgICAgR2xvYmFsIENvbmZpZ3VyYXRpb24gUmVnaXN0ZXIg Mi4KKyAqIEB1c2JfY2FwMTogICAgICBDYXBhYmlsaXR5IFJlZ2lzdGVyIDEuCisgKiBAdXNiX2Nh cDI6ICAgICAgQ2FwYWJpbGl0eSBSZWdpc3RlciAyLgorICogQHVzYl9jYXAzOiAgICAgIENhcGFi aWxpdHkgUmVnaXN0ZXIgMy4KKyAqIEB1c2JfY2FwNDogICAgICBDYXBhYmlsaXR5IFJlZ2lzdGVy IDQuCisgKiBAdXNiX2NhcDU6ICAgICAgQ2FwYWJpbGl0eSBSZWdpc3RlciA1LgorICogQHVzYl9j YXA2OiAgICAgIENhcGFiaWxpdHkgUmVnaXN0ZXIgNi4KKyAqIEB1c2JfY3BrdDE6ICAgICBDdXN0 b20gUGFja2V0IFJlZ2lzdGVyIDEuCisgKiBAdXNiX2Nwa3QyOiAgICAgQ3VzdG9tIFBhY2tldCBS ZWdpc3RlciAyLgorICogQHVzYl9jcGt0MzogICAgIEN1c3RvbSBQYWNrZXQgUmVnaXN0ZXIgMy4K KyAqIEByZXNlcnZlZDE6ICAgICBSZXNlcnZlZC4KKyAqIEBjZmdfcmVnczogICAgICBDb25maWd1 cmF0aW9uIHJlZ2lzdGVycy4KKyAqIEByZXNlcnZlZDI6ICAgICBSZXNlcnZlZC4KKyAqIEBkbWFf YXhpX2N0cmw6ICBBWEkgQ29udHJvbCByZWdpc3Rlci4KKyAqIEBkbWFfYXhpX2lkOiAgICBBWEkg SUQgcmVnaXN0ZXIuCisgKiBAZG1hX2F4aV9jYXA6ICAgQVhJIENhcGFiaWxpdHkgcmVnaXN0ZXIu CisgKiBAZG1hX2F4aV9jdHJsMDogQVhJIENvbnRyb2wgMCByZWdpc3Rlci4KKyAqIEBkbWFfYXhp X2N0cmwxOiBBWEkgQ29udHJvbCAxIHJlZ2lzdGVyLgorICovCitzdHJ1Y3QgY2RuczNfdXNiX3Jl Z3MgeworCV9fbGUzMiB1c2JfY29uZjsKKwlfX2xlMzIgdXNiX3N0czsKKwlfX2xlMzIgdXNiX2Nt ZDsKKwlfX2xlMzIgdXNiX2lwdG47CisJX19sZTMyIHVzYl9scG07CisJX19sZTMyIHVzYl9pZW47 CisJX19sZTMyIHVzYl9pc3RzOworCV9fbGUzMiBlcF9zZWw7CisJX19sZTMyIGVwX3RyYWRkcjsK KwlfX2xlMzIgZXBfY2ZnOworCV9fbGUzMiBlcF9jbWQ7CisJX19sZTMyIGVwX3N0czsKKwlfX2xl MzIgZXBfc3RzX3NpZDsKKwlfX2xlMzIgZXBfc3RzX2VuOworCV9fbGUzMiBkcmJsOworCV9fbGUz MiBlcF9pZW47CisJX19sZTMyIGVwX2lzdHM7CisJX19sZTMyIHVzYl9wd3I7CisJX19sZTMyIHVz Yl9jb25mMjsKKwlfX2xlMzIgdXNiX2NhcDE7CisJX19sZTMyIHVzYl9jYXAyOworCV9fbGUzMiB1 c2JfY2FwMzsKKwlfX2xlMzIgdXNiX2NhcDQ7CisJX19sZTMyIHVzYl9jYXA1OworCV9fbGUzMiB1 c2JfY2FwNjsKKwlfX2xlMzIgdXNiX2Nwa3QxOworCV9fbGUzMiB1c2JfY3BrdDI7CisJX19sZTMy IHVzYl9jcGt0MzsKKwlfX2xlMzIgcmVzZXJ2ZWQxWzM2XTsKKwlfX2xlMzIgY2ZnX3JlZzE7CisJ X19sZTMyIGRiZ19saW5rMTsKKwlfX2xlMzIgZGJnX2xpbmsyOworCV9fbGUzMiBjZmdfcmVnc1s3 NF07CisJX19sZTMyIHJlc2VydmVkMlszNF07CisJX19sZTMyIGRtYV9heGlfY3RybDsKKwlfX2xl MzIgZG1hX2F4aV9pZDsKKwlfX2xlMzIgZG1hX2F4aV9jYXA7CisJX19sZTMyIGRtYV9heGlfY3Ry bDA7CisJX19sZTMyIGRtYV9heGlfY3RybDE7Cit9OworCisvKiBVU0JfQ09ORiAtIGJpdG1hc2tz ICovCisvKiBSZXNldCBVU0IgZGV2aWNlIGNvbmZpZ3VyYXRpb24uICovCisjZGVmaW5lIFVTQl9D T05GX0NGR1JTVAkJQklUKDApCisvKiBTZXQgQ29uZmlndXJhdGlvbi4gKi8KKyNkZWZpbmUgVVNC X0NPTkZfQ0ZHU0VUCQlCSVQoMSkKKy8qIERpc2Nvbm5lY3QgVVNCIGRldmljZSBpbiBTdXBlclNw ZWVkLiAqLworI2RlZmluZSBVU0JfQ09ORl9VU0IzRElTCUJJVCgzKQorLyogRGlzY29ubmVjdCBV U0IgZGV2aWNlIGluIEhTL0ZTICovCisjZGVmaW5lIFVTQl9DT05GX1VTQjJESVMJQklUKDQpCisv KiBMaXR0bGUgRW5kaWFuIGFjY2VzcyAtIGRlZmF1bHQgKi8KKyNkZWZpbmUgVVNCX0NPTkZfTEVO RElBTglCSVQoNSkKKy8qCisgKiBCaWcgRW5kaWFuIGFjY2Vzcy4gRHJpdmVyIGFzc3VtZSB0aGF0 IGJ5dGUgb3JkZXIgZm9yCisgKiBTRlJzIGFjY2VzcyBhbHdheXMgaXMgYXMgTGl0dGxlIEVuZGlh biBzbyB0aGlzIGJpdAorICogaXMgbm90IHVzZWQuCisgKi8KKyNkZWZpbmUgVVNCX0NPTkZfQkVO RElBTglCSVQoNikKKy8qIERldmljZSBzb2Z0d2FyZSByZXNldC4gKi8KKyNkZWZpbmUgVVNCX0NP TkZfU1dSU1QJCUJJVCg3KQorLyogU2luZ3VsYXIgRE1BIHRyYW5zZmVyIG1vZGUuICovCisjZGVm aW5lIFVTQl9DT05GX0RTSU5HCQlCSVQoOCkKKy8qIE11bHRpcGxlIERNQSB0cmFuc2ZlcnMgbW9k ZS4gKi8KKyNkZWZpbmUgVVNCX0NPTkZfRE1VTFQJCUJJVCg5KQorLyogRE1BIGNsb2NrIHR1cm4t b2ZmIGVuYWJsZS4gKi8KKyNkZWZpbmUgVVNCX0NPTkZfRE1BT0ZGRU4JQklUKDEwKQorLyogRE1B IGNsb2NrIHR1cm4tb2ZmIGRpc2FibGUuICovCisjZGVmaW5lIFVTQl9DT05GX0RNQU9GRkRTCUJJ VCgxMSkKKy8qIENsZWFyIEZvcmNlIEZ1bGwgU3BlZWQuICovCisjZGVmaW5lIFVTQl9DT05GX0NG T1JDRV9GUwlCSVQoMTIpCisvKiBTZXQgRm9yY2UgRnVsbCBTcGVlZC4gKi8KKyNkZWZpbmUgVVNC X0NPTkZfU0ZPUkNFX0ZTCUJJVCgxMykKKy8qIERldmljZSBlbmFibGUuICovCisjZGVmaW5lIFVT Ql9DT05GX0RFVkVOCQlCSVQoMTQpCisvKiBEZXZpY2UgZGlzYWJsZS4gKi8KKyNkZWZpbmUgVVNC X0NPTkZfREVWRFMJCUJJVCgxNSkKKy8qIEwxIExQTSBzdGF0ZSBlbnRyeSBlbmFibGUgKHVzZWQg aW4gSFMvRlMgbW9kZSkuICovCisjZGVmaW5lIFVTQl9DT05GX0wxRU4JCUJJVCgxNikKKy8qIEwx IExQTSBzdGF0ZSBlbnRyeSBkaXNhYmxlICh1c2VkIGluIEhTL0ZTIG1vZGUpLiAqLworI2RlZmlu ZSBVU0JfQ09ORl9MMURTCQlCSVQoMTcpCisvKiBVU0IgMi4wIGNsb2NrIGdhdGUgZGlzYWJsZS4g Ki8KKyNkZWZpbmUgVVNCX0NPTkZfQ0xLMk9GRkVOCUJJVCgxOCkKKy8qIFVTQiAyLjAgY2xvY2sg Z2F0ZSBlbmFibGUuICovCisjZGVmaW5lIFVTQl9DT05GX0NMSzJPRkZEUwlCSVQoMTkpCisvKiBM MCBMUE0gc3RhdGUgZW50cnkgcmVxdWVzdCAodXNlZCBpbiBIUy9GUyBtb2RlKS4gKi8KKyNkZWZp bmUgVVNCX0NPTkZfTEdPX0wwCQlCSVQoMjApCisvKiBVU0IgMy4wIGNsb2NrIGdhdGUgZGlzYWJs ZS4gKi8KKyNkZWZpbmUgVVNCX0NPTkZfQ0xLM09GRkVOCUJJVCgyMSkKKy8qIFVTQiAzLjAgY2xv Y2sgZ2F0ZSBlbmFibGUuICovCisjZGVmaW5lIFVTQl9DT05GX0NMSzNPRkZEUwlCSVQoMjIpCisv KiBCaXQgMjMgaXMgcmVzZXJ2ZWQqLworLyogVTEgc3RhdGUgZW50cnkgZW5hYmxlICh1c2VkIGlu IFNTIG1vZGUpLiAqLworI2RlZmluZSBVU0JfQ09ORl9VMUVOCQlCSVQoMjQpCisvKiBVMSBzdGF0 ZSBlbnRyeSBkaXNhYmxlICh1c2VkIGluIFNTIG1vZGUpLiAqLworI2RlZmluZSBVU0JfQ09ORl9V MURTCQlCSVQoMjUpCisvKiBVMiBzdGF0ZSBlbnRyeSBlbmFibGUgKHVzZWQgaW4gU1MgbW9kZSku ICovCisjZGVmaW5lIFVTQl9DT05GX1UyRU4JCUJJVCgyNikKKy8qIFUyIHN0YXRlIGVudHJ5IGRp c2FibGUgKHVzZWQgaW4gU1MgbW9kZSkuICovCisjZGVmaW5lIFVTQl9DT05GX1UyRFMJCUJJVCgy NykKKy8qIFUwIHN0YXRlIGVudHJ5IHJlcXVlc3QgKHVzZWQgaW4gU1MgbW9kZSkuICovCisjZGVm aW5lIFVTQl9DT05GX0xHT19VMAkJQklUKDI4KQorLyogVTEgc3RhdGUgZW50cnkgcmVxdWVzdCAo dXNlZCBpbiBTUyBtb2RlKS4gKi8KKyNkZWZpbmUgVVNCX0NPTkZfTEdPX1UxCQlCSVQoMjkpCisv KiBVMiBzdGF0ZSBlbnRyeSByZXF1ZXN0ICh1c2VkIGluIFNTIG1vZGUpLiAqLworI2RlZmluZSBV U0JfQ09ORl9MR09fVTIJCUJJVCgzMCkKKy8qIFNTLkluYWN0aXZlIHN0YXRlIGVudHJ5IHJlcXVl c3QgKHVzZWQgaW4gU1MgbW9kZSkgKi8KKyNkZWZpbmUgVVNCX0NPTkZfTEdPX1NTSU5BQ1QJQklU KDMxKQorCisvKiBVU0JfU1RTIC0gYml0bWFza3MgKi8KKy8qCisgKiBDb25maWd1cmF0aW9uIHN0 YXR1cy4KKyAqIDEgLSBkZXZpY2UgaXMgaW4gdGhlIGNvbmZpZ3VyZWQgc3RhdGUuCisgKiAwIC0g ZGV2aWNlIGlzIG5vdCBjb25maWd1cmVkLgorICovCisjZGVmaW5lIFVTQl9TVFNfQ0ZHU1RTX01B U0sJQklUKDApCisjZGVmaW5lIFVTQl9TVFNfQ0ZHU1RTKHApCSgocCkgJiBVU0JfU1RTX0NGR1NU U19NQVNLKQorLyoKKyAqIE9uLWNoaXAgbWVtb3J5IG92ZXJmbG93LgorICogMCAtIE9uLWNoaXAg bWVtb3J5IHN0YXR1cyBPSy4KKyAqIDEgLSBPbi1jaGlwIG1lbW9yeSBvdmVyZmxvdy4KKyAqLwor I2RlZmluZSBVU0JfU1RTX09WX01BU0sJCUJJVCgxKQorI2RlZmluZSBVU0JfU1RTX09WKHApCQko KHApICYgVVNCX1NUU19PVl9NQVNLKQorLyoKKyAqIFN1cGVyU3BlZWQgY29ubmVjdGlvbiBzdGF0 dXMuCisgKiAwIC0gVVNCIGluIFN1cGVyU3BlZWQgbW9kZSBkaXNjb25uZWN0ZWQuCisgKiAxIC0g VVNCIGluIFN1cGVyU3BlZWQgbW9kZSBjb25uZWN0ZWQuCisgKi8KKyNkZWZpbmUgVVNCX1NUU19V U0IzQ09OU19NQVNLCUJJVCgyKQorI2RlZmluZSBVU0JfU1RTX1VTQjNDT05TKHApCSgocCkgJiBV U0JfU1RTX1VTQjNDT05TX01BU0spCisvKgorICogRE1BIHRyYW5zZmVyIGNvbmZpZ3VyYXRpb24g c3RhdHVzLgorICogMCAtIHNpbmdsZSByZXF1ZXN0LgorICogMSAtIG11bHRpcGxlIFRSQiBjaGFp bgorICovCisjZGVmaW5lIFVTQl9TVFNfRFRSQU5TX01BU0sJQklUKDMpCisjZGVmaW5lIFVTQl9T VFNfRFRSQU5TKHApCSgocCkgJiBVU0JfU1RTX0RUUkFOU19NQVNLKQorLyoKKyAqIERldmljZSBz cGVlZC4KKyAqIDAgLSBVbmRlZmluZWQgKHZhbHVlIGFmdGVyIHJlc2V0KS4KKyAqIDEgLSBMb3cg c3BlZWQKKyAqIDIgLSBGdWxsIHNwZWVkCisgKiAzIC0gSGlnaCBzcGVlZAorICogNCAtIFN1cGVy IHNwZWVkCisgKi8KKyNkZWZpbmUgVVNCX1NUU19VU0JTUEVFRF9NQVNLCUdFTk1BU0soNiwgNCkK KyNkZWZpbmUgVVNCX1NUU19VU0JTUEVFRChwKQkoKChwKSAmIFVTQl9TVFNfVVNCU1BFRURfTUFT SykgPj4gNCkKKyNkZWZpbmUgVVNCX1NUU19MUwkJKDB4MSA8PCA0KQorI2RlZmluZSBVU0JfU1RT X0ZTCQkoMHgyIDw8IDQpCisjZGVmaW5lIFVTQl9TVFNfSFMJCSgweDMgPDwgNCkKKyNkZWZpbmUg VVNCX1NUU19TUwkJKDB4NCA8PCA0KQorI2RlZmluZSBERVZfVU5ERUZTUEVFRChwKQkoKChwKSAm IFVTQl9TVFNfVVNCU1BFRURfTUFTSykgPT0gKDB4MCA8PCA0KSkKKyNkZWZpbmUgREVWX0xPV1NQ RUVEKHApCQkoKChwKSAmIFVTQl9TVFNfVVNCU1BFRURfTUFTSykgPT0gVVNCX1NUU19MUykKKyNk ZWZpbmUgREVWX0ZVTExTUEVFRChwKQkoKChwKSAmIFVTQl9TVFNfVVNCU1BFRURfTUFTSykgPT0g VVNCX1NUU19GUykKKyNkZWZpbmUgREVWX0hJR0hTUEVFRChwKQkoKChwKSAmIFVTQl9TVFNfVVNC U1BFRURfTUFTSykgPT0gVVNCX1NUU19IUykKKyNkZWZpbmUgREVWX1NVUEVSU1BFRUQocCkJKCgo cCkgJiBVU0JfU1RTX1VTQlNQRUVEX01BU0spID09IFVTQl9TVFNfU1MpCisvKgorICogRW5kaWFu bmVzcyBmb3IgU0ZSIGFjY2Vzcy4KKyAqIDAgLSBMaXR0bGUgRW5kaWFuIG9yZGVyIChkZWZhdWx0 IGFmdGVyIGhhcmR3YXJlIHJlc2V0KS4KKyAqIDEgLSBCaWcgRW5kaWFuIG9yZGVyCisgKi8KKyNk ZWZpbmUgVVNCX1NUU19FTkRJQU5fTUFTSwlCSVQoNykKKyNkZWZpbmUgVVNCX1NUU19FTkRJQU4o cCkJKChwKSAmIFVTQl9TVFNfRU5ESUFOX01BU0spCisvKgorICogSFMvRlMgY2xvY2sgdHVybi1v ZmYgc3RhdHVzLgorICogMCAtIGhzZnMgY2xvY2sgaXMgYWx3YXlzIG9uLgorICogMSAtIGhzZnMg Y2xvY2sgdHVybi1vZmYgaW4gTDIgKEhTL0ZTIG1vZGUpIGlzIGVuYWJsZWQKKyAqICAgICAgICAg IChkZWZhdWx0IGFmdGVyIGhhcmR3YXJlIHJlc2V0KS4KKyAqLworI2RlZmluZSBVU0JfU1RTX0NM SzJPRkZfTUFTSwlCSVQoOCkKKyNkZWZpbmUgVVNCX1NUU19DTEsyT0ZGKHApCSgocCkgJiBVU0Jf U1RTX0NMSzJPRkZfTUFTSykKKy8qCisgKiBQQ0xLIGNsb2NrIHR1cm4tb2ZmIHN0YXR1cy4KKyAq IDAgLSBwY2xrIGNsb2NrIGlzIGFsd2F5cyBvbi4KKyAqIDEgLSBwY2xrIGNsb2NrIHR1cm4tb2Zm IGluIFUzIChTUyBtb2RlKSBpcyBlbmFibGVkCisgKiAgICAgICAgICAoZGVmYXVsdCBhZnRlciBo YXJkd2FyZSByZXNldCkuCisgKi8KKyNkZWZpbmUgVVNCX1NUU19DTEszT0ZGX01BU0sJQklUKDkp CisjZGVmaW5lIFVTQl9TVFNfQ0xLM09GRihwKQkoKHApICYgVVNCX1NUU19DTEszT0ZGX01BU0sp CisvKgorICogQ29udHJvbGxlciBpbiByZXNldCBzdGF0ZS4KKyAqIDAgLSBJbnRlcm5hbCByZXNl dCBpcyBhY3RpdmUuCisgKiAxIC0gSW50ZXJuYWwgcmVzZXQgaXMgbm90IGFjdGl2ZSBhbmQgY29u dHJvbGxlciBpcyBmdWxseSBvcGVyYXRpb25hbC4KKyAqLworI2RlZmluZSBVU0JfU1RTX0lOX1JT VF9NQVNLCUJJVCgxMCkKKyNkZWZpbmUgVVNCX1NUU19JTl9SU1QocCkJKChwKSAmIFVTQl9TVFNf SU5fUlNUX01BU0spCisvKgorICogRGV2aWNlIGVuYWJsZSBTdGF0dXMuCisgKiAwIC0gVVNCIGRl dmljZSBpcyBkaXNhYmxlZCAoVkJVUyBpbnB1dCBpcyBkaXNjb25uZWN0ZWQgZnJvbSBpbnRlcm5h bCBsb2dpYykuCisgKiAxIC0gVVNCIGRldmljZSBpcyBlbmFibGVkIChWQlVTIGlucHV0IGlzIGNv bm5lY3RlZCB0byB0aGUgaW50ZXJuYWwgbG9naWMpLgorICovCisjZGVmaW5lIFVTQl9TVFNfREVW U19NQVNLCUJJVCgxNCkKKyNkZWZpbmUgVVNCX1NUU19ERVZTKHApCQkoKHApICYgVVNCX1NUU19E RVZTX01BU0spCisvKgorICogREFkZHJlc3Mgc3RhdHVzcy4KKyAqIDAgLSBVU0IgZGV2aWNlIGlz IGRlZmF1bHQgc3RhdGUuCisgKiAxIC0gVVNCIGRldmljZSBpcyBhdCBsZWFzdCBpbiBhZGRyZXNz IHN0YXRlLgorICovCisjZGVmaW5lIFVTQl9TVFNfQUREUkVTU0VEX01BU0sJQklUKDE1KQorI2Rl ZmluZSBVU0JfU1RTX0FERFJFU1NFRChwKQkoKHApICYgVVNCX1NUU19BRERSRVNTRURfTUFTSykK Ky8qCisgKiBMMSBMUE0gc3RhdGUgZW5hYmxlIHN0YXR1cyAodXNlZCBpbiBIUy9GUyBtb2RlKS4K KyAqIDAgLSBFbnRlcmluZyB0byBMMSBMUE0gc3RhdGUgZGlzYWJsZWQuCisgKiAxIC0gRW50ZXJp bmcgdG8gTDEgTFBNIHN0YXRlIGVuYWJsZWQuCisgKi8KKyNkZWZpbmUgVVNCX1NUU19MMUVOU19N QVNLCUJJVCgxNikKKyNkZWZpbmUgVVNCX1NUU19MMUVOUyhwKQkoKHApICYgVVNCX1NUU19MMUVO U19NQVNLKQorLyoKKyAqIEludGVybmFsIFZCVVMgY29ubmVjdGlvbiBzdGF0dXMgKHVzZWQgYm90 aCBpbiBIUy9GUyAgYW5kIFNTIG1vZGUpLgorICogMCAtIGludGVybmFsIFZCVVMgaXMgbm90IGRl dGVjdGVkLgorICogMSAtIGludGVybmFsIFZCVVMgaXMgZGV0ZWN0ZWQuCisgKi8KKyNkZWZpbmUg VVNCX1NUU19WQlVTU19NQVNLCUJJVCgxNykKKyNkZWZpbmUgVVNCX1NUU19WQlVTUyhwKQkoKHAp ICYgVVNCX1NUU19WQlVTU19NQVNLKQorLyoKKyAqIEhTL0ZTIExQTSAgc3RhdGUgKHVzZWQgaW4g RlMvSFMgbW9kZSkuCisgKiAwIC0gTDAgU3RhdGUKKyAqIDEgLSBMMSBTdGF0ZQorICogMiAtIEwy IFN0YXRlCisgKiAzIC0gTDMgU3RhdGUKKyAqLworI2RlZmluZSBVU0JfU1RTX0xQTVNUX01BU0sJ R0VOTUFTSygxOSwgMTgpCisjZGVmaW5lIERFVl9MMF9TVEFURShwKQkJKCgocCkgJiBVU0JfU1RT X0xQTVNUX01BU0spID09ICgweDAgPDwgMTgpKQorI2RlZmluZSBERVZfTDFfU1RBVEUocCkJCSgo KHApICYgVVNCX1NUU19MUE1TVF9NQVNLKSA9PSAoMHgxIDw8IDE4KSkKKyNkZWZpbmUgREVWX0wy X1NUQVRFKHApCQkoKChwKSAmIFVTQl9TVFNfTFBNU1RfTUFTSykgPT0gKDB4MiA8PCAxOCkpCisj ZGVmaW5lIERFVl9MM19TVEFURShwKQkJKCgocCkgJiBVU0JfU1RTX0xQTVNUX01BU0spID09ICgw eDMgPDwgMTgpKQorLyoKKyAqIERpc2FibGUgSFMgc3RhdHVzICh1c2VkIGluIEZTL0hTIG1vZGUp LgorICogMCAtIHRoZSBkaXNjb25uZWN0IGJpdCBmb3IgSFMvRlMgbW9kZSBpcyBzZXQgLgorICog MSAtIHRoZSBkaXNjb25uZWN0IGJpdCBmb3IgSFMvRlMgbW9kZSBpcyBub3Qgc2V0LgorICovCisj ZGVmaW5lIFVTQl9TVFNfVVNCMkNPTlNfTUFTSwlCSVQoMjApCisjZGVmaW5lIFVTQl9TVFNfVVNC MkNPTlMocCkJKChwKSAmIFVTQl9TVFNfVVNCMkNPTlNfTUFTSykKKy8qCisgKiBIUy9GUyBtb2Rl IGNvbm5lY3Rpb24gc3RhdHVzICh1c2VkIGluIEZTL0hTIG1vZGUpLgorICogMCAtIEhpZ2ggU3Bl ZWQgb3BlcmF0aW9ucyBpbiBVU0IyLjAgKEZTL0hTKSBtb2RlIG5vdCBkaXNhYmxlZC4KKyAqIDEg LSBIaWdoIFNwZWVkIG9wZXJhdGlvbnMgaW4gVVNCMi4wIChGUy9IUykuCisgKi8KKyNkZWZpbmUg VVNCX1NUU19ESVNBQkxFX0hTX01BU0sJQklUKDIxKQorI2RlZmluZSBVU0JfU1RTX0RJU0FCTEVf SFMocCkJKChwKSAmIFVTQl9TVFNfRElTQUJMRV9IU19NQVNLKQorLyoKKyAqIFUxIHN0YXRlIGVu YWJsZSBzdGF0dXMgKHVzZWQgaW4gU1MgbW9kZSkuCisgKiAwIC0gRW50ZXJpbmcgdG8gIFUxIHN0 YXRlIGRpc2FibGVkLgorICogMSAtIEVudGVyaW5nIHRvICBVMSBzdGF0ZSBlbmFibGVkLgorICov CisjZGVmaW5lIFVTQl9TVFNfVTFFTlNfTUFTSwlCSVQoMjQpCisjZGVmaW5lIFVTQl9TVFNfVTFF TlMocCkJKChwKSAmIFVTQl9TVFNfVTFFTlNfTUFTSykKKy8qCisgKiBVMiBzdGF0ZSBlbmFibGUg c3RhdHVzICh1c2VkIGluIFNTIG1vZGUpLgorICogMCAtIEVudGVyaW5nIHRvICBVMiBzdGF0ZSBk aXNhYmxlZC4KKyAqIDEgLSBFbnRlcmluZyB0byAgVTIgc3RhdGUgZW5hYmxlZC4KKyAqLworI2Rl ZmluZSBVU0JfU1RTX1UyRU5TX01BU0sJQklUKDI1KQorI2RlZmluZSBVU0JfU1RTX1UyRU5TKHAp CSgocCkgJiBVU0JfU1RTX1UyRU5TX01BU0spCisvKgorICogU3VwZXJTcGVlZCBMaW5rIExUU1NN IHN0YXRlLiBUaGlzIGZpZWxkIHJlZmxlY3RzIFVTQlNTLURFViBjdXJyZW50CisgKiBTdXBlclNw ZWVkIGxpbmsgc3RhdGUKKyAqLworI2RlZmluZSBVU0JfU1RTX0xTVF9NQVNLCUdFTk1BU0soMjks IDI2KQorI2RlZmluZSBERVZfTFNUX1UwCQkoKChwKSAmIFVTQl9TVFNfTFNUX01BU0spID09ICgw eDAgPDwgMjYpKQorI2RlZmluZSBERVZfTFNUX1UxCQkoKChwKSAmIFVTQl9TVFNfTFNUX01BU0sp ID09ICgweDEgPDwgMjYpKQorI2RlZmluZSBERVZfTFNUX1UyCQkoKChwKSAmIFVTQl9TVFNfTFNU X01BU0spID09ICgweDIgPDwgMjYpKQorI2RlZmluZSBERVZfTFNUX1UzCQkoKChwKSAmIFVTQl9T VFNfTFNUX01BU0spID09ICgweDMgPDwgMjYpKQorI2RlZmluZSBERVZfTFNUX0RJU0FCTEVECSgo KHApICYgVVNCX1NUU19MU1RfTUFTSykgPT0gKDB4NCA8PCAyNikpCisjZGVmaW5lIERFVl9MU1Rf UlhERVRFQ1QJKCgocCkgJiBVU0JfU1RTX0xTVF9NQVNLKSA9PSAoMHg1IDw8IDI2KSkKKyNkZWZp bmUgREVWX0xTVF9JTkFDVElWRQkoKChwKSAmIFVTQl9TVFNfTFNUX01BU0spID09ICgweDYgPDwg MjYpKQorI2RlZmluZSBERVZfTFNUX1BPTExJTkcJCSgoKHApICYgVVNCX1NUU19MU1RfTUFTSykg PT0gKDB4NyA8PCAyNikpCisjZGVmaW5lIERFVl9MU1RfUkVDT1ZFUlkJKCgocCkgJiBVU0JfU1RT X0xTVF9NQVNLKSA9PSAoMHg4IDw8IDI2KSkKKyNkZWZpbmUgREVWX0xTVF9IT1RfUkVTRVQJKCgo cCkgJiBVU0JfU1RTX0xTVF9NQVNLKSA9PSAoMHg5IDw8IDI2KSkKKyNkZWZpbmUgREVWX0xTVF9D T01QX01PREUJKCgocCkgJiBVU0JfU1RTX0xTVF9NQVNLKSA9PSAoMHhhIDw8IDI2KSkKKyNkZWZp bmUgREVWX0xTVF9MQl9TVEFURQkoKChwKSAmIFVTQl9TVFNfTFNUX01BU0spID09ICgweGIgPDwg MjYpKQorLyoKKyAqIERNQSBjbG9jayB0dXJuLW9mZiBzdGF0dXMuCisgKiAwIC0gRE1BIGNsb2Nr IGlzIGFsd2F5cyBvbiAoZGVmYXVsdCBhZnRlciBoYXJkd2FyZSByZXNldCkuCisgKiAxIC0gRE1B IGNsb2NrIHR1cm4tb2ZmIGluIFUxLCBVMiBhbmQgVTMgKFNTIG1vZGUpIGlzIGVuYWJsZWQuCisg Ki8KKyNkZWZpbmUgVVNCX1NUU19ETUFPRkZfTUFTSwlCSVQoMzApCisjZGVmaW5lIFVTQl9TVFNf RE1BT0ZGKHApCSgocCkgJiBVU0JfU1RTX0RNQU9GRl9NQVNLKQorLyoKKyAqIFNGUiBFbmRpYW4g c3RhdHVzcy4KKyAqIDAgLSBMaXR0bGUgRW5kaWFuIG9yZGVyIChkZWZhdWx0IGFmdGVyIGhhcmR3 YXJlIHJlc2V0KS4KKyAqIDEgLSBCaWcgRW5kaWFuIG9yZGVyLgorICovCisjZGVmaW5lIFVTQl9T VFNfRU5ESUFOMl9NQVNLCUJJVCgzMSkKKyNkZWZpbmUgVVNCX1NUU19FTkRJQU4yKHApCSgocCkg JiBVU0JfU1RTX0VORElBTjJfTUFTSykKKworLyogVVNCX0NNRCAtICBiaXRtYXNrcyAqLworLyog U2V0IEZ1bmN0aW9uIEFkZHJlc3MgKi8KKyNkZWZpbmUgVVNCX0NNRF9TRVRfQUREUglCSVQoMCkK Ky8qCisgKiBGdW5jdGlvbiBBZGRyZXNzIFRoaXMgZmllbGQgaXMgc2F2ZWQgdG8gdGhlIGRldmlj ZSBvbmx5IHdoZW4gdGhlIGZpZWxkCisgKiBTRVRfQUREUiBpcyBzZXQgJzEgJyBkdXJpbmcgd3Jp dGUgdG8gVVNCX0NNRCByZWdpc3Rlci4KKyAqIFNvZnR3YXJlIGlzIHJlc3BvbnNpYmxlIGZvciBl bnRlcmluZyB0aGUgYWRkcmVzcyBvZiB0aGUgZGV2aWNlIGR1cmluZworICogU0VUX0FERFJFU1Mg cmVxdWVzdCBzZXJ2aWNlLiBUaGlzIGZpZWxkIHNob3VsZCBiZSBzZXQgaW1tZWRpYXRlbHkgYWZ0 ZXIKKyAqIHRoZSBTRVRVUCBwYWNrZXQgaXMgZGVjb2RlZCwgYW5kIHByaW9yIHRvIGNvbmZpcm1h dGlvbiBvZiB0aGUgc3RhdHVzIHBoYXNlCisgKi8KKyNkZWZpbmUgVVNCX0NNRF9GQUREUl9NQVNL CUdFTk1BU0soNywgMSkKKyNkZWZpbmUgVVNCX0NNRF9GQUREUihwKQkoKChwKSA8PCAxKSAmIFVT Ql9DTURfRkFERFJfTUFTSykKKy8qIFNlbmQgRnVuY3Rpb24gV2FrZSBEZXZpY2UgTm90aWZpY2F0 aW9uIFRQICh1c2VkIG9ubHkgaW4gU1MgbW9kZSkuICovCisjZGVmaW5lIFVTQl9DTURfU0RORlcJ CUJJVCg4KQorLyogU2V0IFRlc3QgTW9kZSAodXNlZCBvbmx5IGluIEhTL0ZTIG1vZGUpLiAqLwor I2RlZmluZSBVU0JfQ01EX1NUTU9ERQkJQklUKDkpCisvKiBUZXN0IG1vZGUgc2VsZWN0b3IgKHVz ZWQgb25seSBpbiBIUy9GUyBtb2RlKSAqLworI2RlZmluZSBVU0JfU1RTX1RNT0RFX1NFTF9NQVNL CUdFTk1BU0soMTEsIDEwKQorI2RlZmluZSBVU0JfU1RTX1RNT0RFX1NFTChwKQkoKChwKSA8PCAx MCkgJiBVU0JfU1RTX1RNT0RFX1NFTF9NQVNLKQorLyoKKyAqICBTZW5kIExhdGVuY3kgVG9sZXJh bmNlIE1lc3NhZ2UgRGV2aWNlIE5vdGlmaWNhdGlvbiBUUCAodXNlZCBvbmx5CisgKiAgaW4gU1Mg bW9kZSkuCisgKi8KKyNkZWZpbmUgVVNCX0NNRF9TRE5MVE0JCUJJVCgxMikKKy8qIFNlbmQgQ3Vz dG9tIFRyYW5zYWN0aW9uIFBhY2tldCAodXNlZCBvbmx5IGluIFNTIG1vZGUpICovCisjZGVmaW5l IFVTQl9DTURfU1BLVAkJQklUKDEzKQorLypEZXZpY2UgTm90aWZpY2F0aW9uICdGdW5jdGlvbiBX YWtlJyAtIEludGVyZmFjZSB2YWx1ZSAob25seSBpbiBTUyBtb2RlLiAqLworI2RlZmluZSBVU0Jf Q01EX0RORldfSU5UX01BU0sJR0VOTUFTSygyMywgMTYpCisjZGVmaW5lIFVTQl9TVFNfRE5GV19J TlQocCkJKCgocCkgPDwgMTYpICYgVVNCX0NNRF9ETkZXX0lOVF9NQVNLKQorLyoKKyAqIERldmlj ZSBOb3RpZmljYXRpb24gJ0xhdGVuY3kgVG9sZXJhbmNlIE1lc3NhZ2UnIC0zNzMgQkVMVCB2YWx1 ZSBbNzowXQorICogKHVzZWQgb25seSBpbiBTUyBtb2RlKS4KKyAqLworI2RlZmluZSBVU0JfQ01E X0ROTFRNX0JFTFRfTUFTSwlHRU5NQVNLKDI3LCAxNikKKyNkZWZpbmUgVVNCX1NUU19ETkxUTV9C RUxUKHApCSgoKHApIDw8IDE2KSAmIFVTQl9DTURfRE5MVE1fQkVMVF9NQVNLKQorCisvKiBVU0Jf SVRQTiAtIGJpdG1hc2tzICovCisvKgorICogSVRQKFNTKSAvIFNPRiAoSFMvRlMpIG51bWJlcgor ICogSW4gU1MgbW9kZSB0aGlzIGZpZWxkIHJlcHJlc2VudCBudW1iZXIgb2YgbGFzdCBJVFAgcmVj ZWl2ZWQgZnJvbSBob3N0LgorICogSW4gSFMvRlMgbW9kZSB0aGlzIGZpZWxkIHJlcHJlc2VudCBu dW1iZXIgb2YgbGFzdCBTT0YgcmVjZWl2ZWQgZnJvbSBob3N0LgorICovCisjZGVmaW5lIFVTQl9J VFBOX01BU0sJCUdFTk1BU0soMTMsIDApCisjZGVmaW5lIFVTQl9JVFBOKHApCQkoKHApICYgVVNC X0lUUE5fTUFTSykKKworLyogVVNCX0xQTSAtIGJpdG1hc2tzICovCisvKiBIb3N0IEluaXRpYXRl ZCBSZXN1bWUgRHVyYXRpb24uICovCisjZGVmaW5lIFVTQl9MUE1fSElSRF9NQVNLCUdFTk1BU0so MywgMCkKKyNkZWZpbmUgVVNCX0xQTV9ISVJEKHApCQkoKHApICYgVVNCX0xQTV9ISVJEX01BU0sp CisvKiBSZW1vdGUgV2FrZXVwIEVuYWJsZSAoYlJlbW90ZVdha2UpLiAqLworI2RlZmluZSBVU0Jf TFBNX0JSVwkJQklUKDQpCisKKy8qIFVTQl9JRU4gLSBiaXRtYXNrcyAqLworLyogU1MgY29ubmVj dGlvbiBpbnRlcnJ1cHQgZW5hYmxlICovCisjZGVmaW5lIFVTQl9JRU5fQ09OSUVOCQlCSVQoMCkK Ky8qIFNTIGRpc2Nvbm5lY3Rpb24gaW50ZXJydXB0IGVuYWJsZS4gKi8KKyNkZWZpbmUgVVNCX0lF Tl9ESVNJRU4JCUJJVCgxKQorLyogVVNCIFNTIHdhcm0gcmVzZXQgaW50ZXJydXB0IGVuYWJsZS4g Ki8KKyNkZWZpbmUgVVNCX0lFTl9VV1JFU0lFTglCSVQoMikKKy8qIFVTQiBTUyBob3QgcmVzZXQg aW50ZXJydXB0IGVuYWJsZSAqLworI2RlZmluZSBVU0JfSUVOX1VIUkVTSUVOCUJJVCgzKQorLyog U1MgbGluayBVMyBzdGF0ZSBlbnRlciBpbnRlcnJ1cHQgZW5hYmxlIChzdXNwZW5kKS4qLworI2Rl ZmluZSBVU0JfSUVOX1UzRU5USUVOCUJJVCg0KQorLyogU1MgbGluayBVMyBzdGF0ZSBleGl0IGlu dGVycnVwdCBlbmFibGUgKHdha2V1cCkuICovCisjZGVmaW5lIFVTQl9JRU5fVTNFWFRJRU4JQklU KDUpCisvKiBTUyBsaW5rIFUyIHN0YXRlIGVudGVyIGludGVycnVwdCBlbmFibGUuKi8KKyNkZWZp bmUgVVNCX0lFTl9VMkVOVElFTglCSVQoNikKKy8qIFNTIGxpbmsgVTIgc3RhdGUgZXhpdCBpbnRl cnJ1cHQgZW5hYmxlLiovCisjZGVmaW5lIFVTQl9JRU5fVTJFWFRJRU4JQklUKDcpCisvKiBTUyBs aW5rIFUxIHN0YXRlIGVudGVyIGludGVycnVwdCBlbmFibGUuKi8KKyNkZWZpbmUgVVNCX0lFTl9V MUVOVElFTglCSVQoOCkKKy8qIFNTIGxpbmsgVTEgc3RhdGUgZXhpdCBpbnRlcnJ1cHQgZW5hYmxl LiovCisjZGVmaW5lIFVTQl9JRU5fVTFFWFRJRU4JQklUKDkpCisvKiBJVFAvU09GIHBhY2tldCBk ZXRlY3RlZCBpbnRlcnJ1cHQgZW5hYmxlLiovCisjZGVmaW5lIFVTQl9JRU5fSVRQSUVOCQlCSVQo MTApCisvKiBXYWtldXAgaW50ZXJydXB0IGVuYWJsZS4qLworI2RlZmluZSBVU0JfSUVOX1dBS0VJ RU4JCUJJVCgxMSkKKy8qIFNlbmQgQ3VzdG9tIFBhY2tldCBpbnRlcnJ1cHQgZW5hYmxlLiovCisj ZGVmaW5lIFVTQl9JRU5fU1BLVElFTgkJQklUKDEyKQorLyogSFMvRlMgbW9kZSBjb25uZWN0aW9u IGludGVycnVwdCBlbmFibGUuKi8KKyNkZWZpbmUgVVNCX0lFTl9DT04ySUVOCQlCSVQoMTYpCisv KiBIUy9GUyBtb2RlIGRpc2Nvbm5lY3Rpb24gaW50ZXJydXB0IGVuYWJsZS4qLworI2RlZmluZSBV U0JfSUVOX0RJUzJJRU4JCUJJVCgxNykKKy8qIFVTQiByZXNldCAoSFMvRlMgbW9kZSkgaW50ZXJy dXB0IGVuYWJsZS4qLworI2RlZmluZSBVU0JfSUVOX1UyUkVTSUVOCUJJVCgxOCkKKy8qIExQTSBM MiBzdGF0ZSBlbnRlciBpbnRlcnJ1cHQgZW5hYmxlLiovCisjZGVmaW5lIFVTQl9JRU5fTDJFTlRJ RU4JQklUKDIwKQorLyogTFBNICBMMiBzdGF0ZSBleGl0IGludGVycnVwdCBlbmFibGUuKi8KKyNk ZWZpbmUgVVNCX0lFTl9MMkVYVElFTglCSVQoMjEpCisvKiBMUE0gTDEgc3RhdGUgZW50ZXIgaW50 ZXJydXB0IGVuYWJsZS4qLworI2RlZmluZSBVU0JfSUVOX0wxRU5USUVOCUJJVCgyNCkKKy8qIExQ TSAgTDEgc3RhdGUgZXhpdCBpbnRlcnJ1cHQgZW5hYmxlLiovCisjZGVmaW5lIFVTQl9JRU5fTDFF WFRJRU4JQklUKDI1KQorLyogQ29uZmlndXJhdGlvbiByZXNldCBpbnRlcnJ1cHQgZW5hYmxlLiov CisjZGVmaW5lIFVTQl9JRU5fQ0ZHUkVTSUVOCUJJVCgyNikKKy8qIFN0YXJ0IG9mIHRoZSBVU0Ig U1Mgd2FybSByZXNldCBpbnRlcnJ1cHQgZW5hYmxlLiovCisjZGVmaW5lIFVTQl9JRU5fVVdSRVNT SUVOCUJJVCgyOCkKKy8qIEVuZCBvZiB0aGUgVVNCIFNTIHdhcm0gcmVzZXQgaW50ZXJydXB0IGVu YWJsZS4qLworI2RlZmluZSBVU0JfSUVOX1VXUkVTRUlFTglCSVQoMjkpCisKKyNkZWZpbmUgVVNC X0lFTl9JTklUICAoVVNCX0lFTl9VMlJFU0lFTiB8IFVTQl9JU1RTX0RJUzJJIHwgVVNCX0lFTl9D T04ySUVOIFwKKwkJICAgICAgIHwgVVNCX0lFTl9VSFJFU0lFTiB8IFVTQl9JRU5fVVdSRVNJRU4g fCBVU0JfSUVOX0RJU0lFTiBcCisJCSAgICAgICB8IFVTQl9JRU5fQ09OSUVOIHwgVVNCX0lFTl9V M0VYVElFTiB8IFVTQl9JRU5fTDJFTlRJRU4gXAorCQkgICAgICAgfCBVU0JfSUVOX0wyRVhUSUVO KQorCisvKiBVU0JfSVNUUyAtIGJpdG1hc2tzICovCisvKiBTUyBDb25uZWN0aW9uIGRldGVjdGVk LiAqLworI2RlZmluZSBVU0JfSVNUU19DT05JCQlCSVQoMCkKKy8qIFNTIERpc2Nvbm5lY3Rpb24g ZGV0ZWN0ZWQuICovCisjZGVmaW5lIFVTQl9JU1RTX0RJU0kJCUJJVCgxKQorLyogVVVTQiB3YXJt IHJlc2V0IGRldGVjdGVkZS4gKi8KKyNkZWZpbmUgVVNCX0lTVFNfVVdSRVNJCQlCSVQoMikKKy8q IFVTQiBob3QgcmVzZXQgZGV0ZWN0ZWQuICovCisjZGVmaW5lIFVTQl9JU1RTX1VIUkVTSQkJQklU KDMpCisvKiBVMyBsaW5rIHN0YXRlIGVudGVyIGRldGVjdGVkIChzdXNwZW5kKS4qLworI2RlZmlu ZSBVU0JfSVNUU19VM0VOVEkJCUJJVCg0KQorLyogVTMgbGluayBzdGF0ZSBleGl0IGRldGVjdGVk ICh3YWtldXApLiAqLworI2RlZmluZSBVU0JfSVNUU19VM0VYVEkJCUJJVCg1KQorLyogVTIgbGlu ayBzdGF0ZSBlbnRlciBkZXRlY3RlZC4qLworI2RlZmluZSBVU0JfSVNUU19VMkVOVEkJCUJJVCg2 KQorLyogVTIgbGluayBzdGF0ZSBleGl0IGRldGVjdGVkLiovCisjZGVmaW5lIFVTQl9JU1RTX1Uy RVhUSQkJQklUKDcpCisvKiBVMSBsaW5rIHN0YXRlIGVudGVyIGRldGVjdGVkLiovCisjZGVmaW5l IFVTQl9JU1RTX1UxRU5USQkJQklUKDgpCisvKiBVMSBsaW5rIHN0YXRlIGV4aXQgZGV0ZWN0ZWQu Ki8KKyNkZWZpbmUgVVNCX0lTVFNfVTFFWFRJCQlCSVQoOSkKKy8qIElUUC9TT0YgcGFja2V0IGRl dGVjdGVkLiovCisjZGVmaW5lIFVTQl9JU1RTX0lUUEkJCUJJVCgxMCkKKy8qIFdha2V1cCBkZXRl Y3RlZC4qLworI2RlZmluZSBVU0JfSVNUU19XQUtFSQkJQklUKDExKQorLyogU2VuZCBDdXN0b20g UGFja2V0IGRldGVjdGVkLiovCisjZGVmaW5lIFVTQl9JU1RTX1NQS1RJCQlCSVQoMTIpCisvKiBI Uy9GUyBtb2RlIGNvbm5lY3Rpb24gZGV0ZWN0ZWQuKi8KKyNkZWZpbmUgVVNCX0lTVFNfQ09OMkkJ CUJJVCgxNikKKy8qIEhTL0ZTIG1vZGUgZGlzY29ubmVjdGlvbiBkZXRlY3RlZC4qLworI2RlZmlu ZSBVU0JfSVNUU19ESVMySQkJQklUKDE3KQorLyogVVNCIHJlc2V0IChIUy9GUyBtb2RlKSBkZXRl Y3RlZC4qLworI2RlZmluZSBVU0JfSVNUU19VMlJFU0kJCUJJVCgxOCkKKy8qIExQTSBMMiBzdGF0 ZSBlbnRlciBkZXRlY3RlZC4qLworI2RlZmluZSBVU0JfSVNUU19MMkVOVEkJCUJJVCgyMCkKKy8q IExQTSAgTDIgc3RhdGUgZXhpdCBkZXRlY3RlZC4qLworI2RlZmluZSBVU0JfSVNUU19MMkVYVEkJ CUJJVCgyMSkKKy8qIExQTSBMMSBzdGF0ZSBlbnRlciBkZXRlY3RlZC4qLworI2RlZmluZSBVU0Jf SVNUU19MMUVOVEkJCUJJVCgyNCkKKy8qIExQTSBMMSBzdGF0ZSBleGl0IGRldGVjdGVkLiovCisj ZGVmaW5lIFVTQl9JU1RTX0wxRVhUSQkJQklUKDI1KQorLyogVVNCIGNvbmZpZ3VyYXRpb24gcmVz ZXQgZGV0ZWN0ZWQuKi8KKyNkZWZpbmUgVVNCX0lTVFNfQ0ZHUkVTSQlCSVQoMjYpCisvKiBTdGFy dCBvZiB0aGUgVVNCIHdhcm0gcmVzZXQgZGV0ZWN0ZWQuKi8KKyNkZWZpbmUgVVNCX0lTVFNfVVdS RVNTSQlCSVQoMjgpCisvKiBFbmQgb2YgdGhlIFVTQiB3YXJtIHJlc2V0IGRldGVjdGVkLiovCisj ZGVmaW5lIFVTQl9JU1RTX1VXUkVTRUkJQklUKDI5KQorCisvKiBVU0JfU0VMIC0gYml0bWFza3Mg Ki8KKyNkZWZpbmUgRVBfU0VMX0VQTk9fTUFTSwlHRU5NQVNLKDMsIDApCisvKiBFbmRwb2ludCBu dW1iZXIuICovCisjZGVmaW5lIEVQX1NFTF9FUE5PKHApCQkoKHApICYgRVBfU0VMX0VQTk9fTUFT SykKKy8qIEVuZHBvaW50IGRpcmVjdGlvbiBiaXQgLSAwIC0gT1VULCAxIC0gSU4uICovCisjZGVm aW5lIEVQX1NFTF9ESVIJCUJJVCg3KQorCisjZGVmaW5lIHNlbGVjdF9lcF9pbihucikJKEVQX1NF TF9FUE5PKHApIHwgRVBfU0VMX0RJUikKKyNkZWZpbmUgc2VsZWN0X2VwX291dAkJKEVQX1NFTF9F UE5PKHApKQorCisvKiBFUF9UUkFERFIgLSBiaXRtYXNrcyAqLworLyogVHJhbnNmZXIgUmluZyBh ZGRyZXNzLiAqLworI2RlZmluZSBFUF9UUkFERFJfVFJBRERSKHApCSgocCkpCisKKy8qIEVQX0NG RyAtIGJpdG1hc2tzICovCisvKiBFbmRwb2ludCBlbmFibGUgKi8KKyNkZWZpbmUgRVBfQ0ZHX0VO QUJMRQkJQklUKDApCisvKgorICogIEVuZHBvaW50IHR5cGUuCisgKiAxIC0gaXNvY2hyb25vdXMK KyAqIDIgLSBidWxrCisgKiAzIC0gaW50ZXJydXB0CisgKi8KKyNkZWZpbmUgRVBfQ0ZHX0VQVFlQ RV9NQVNLCUdFTk1BU0soMiwgMSkKKyNkZWZpbmUgRVBfQ0ZHX0VQVFlQRShwKQkoKChwKSA8PCAx KSAgJiBFUF9DRkdfRVBUWVBFX01BU0spCisvKiBTdHJlYW0gc3VwcG9ydCBlbmFibGUgKG9ubHkg aW4gU1MgbW9kZSkuICovCisjZGVmaW5lIEVQX0NGR19TVFJFQU1fRU4JQklUKDMpCisvKiBUREwg Y2hlY2sgKG9ubHkgaW4gU1MgbW9kZSBmb3IgQlVMSyBFUCkuICovCisjZGVmaW5lIEVQX0NGR19U RExfQ0hLCQlCSVQoNCkKKy8qIFNJRCBjaGVjayAob25seSBpbiBTUyBtb2RlIGZvciBCVUxLIE9V VCBFUCkuICovCisjZGVmaW5lIEVQX0NGR19TSURfQ0hLCQlCSVQoNSkKKy8qIERNQSB0cmFuc2Zl ciBlbmRpYW5uZXNzLiAqLworI2RlZmluZSBFUF9DRkdfRVBFTkRJQU4JCUJJVCg3KQorLyogTWF4 IGJ1cnN0IHNpemUgKHVzZWQgb25seSBpbiBTUyBtb2RlKS4gKi8KKyNkZWZpbmUgRVBfQ0ZHX01B WEJVUlNUX01BU0sJR0VOTUFTSygxMSwgOCkKKyNkZWZpbmUgRVBfQ0ZHX01BWEJVUlNUKHApCSgo KHApIDw8IDgpICYgRVBfQ0ZHX01BWEJVUlNUX01BU0spCisvKiBJU08gbWF4IGJ1cnN0LiAqLwor I2RlZmluZSBFUF9DRkdfTVVMVF9NQVNLCUdFTk1BU0soMTUsIDE0KQorI2RlZmluZSBFUF9DRkdf TVVMVChwKQkJKCgocCkgPDwgMTQpICYgRVBfQ0ZHX01VTFQpCisvKiBJU08gbWF4IGJ1cnN0LiAq LworI2RlZmluZSBFUF9DRkdfTUFYUEtUU0laRV9NQVNLCUdFTk1BU0soMjYsIDE2KQorI2RlZmlu ZSBFUF9DRkdfTUFYUEtUU0laRShwKQkoKChwKSA8PCAxNikgJiBFUF9DRkdfTUFYUEtUU0laRV9N QVNLKQorLyogTWF4IG51bWJlciBvZiBidWZmZXJlZCBwYWNrZXRzLiAqLworI2RlZmluZSBFUF9D RkdfQlVGRkVSSU5HX01BU0sJR0VOTUFTSygzMSwgMjcpCisjZGVmaW5lIEVQX0NGR19CVUZGRVJJ TkcocCkJKCgocCkgPDwgMjcpICYgRVBfQ0ZHX0JVRkZFUklOR19NQVNLKQorCisvKiBFUF9DTUQg LSBiaXRtYXNrcyAqLworLyogRW5kcG9pbnQgcmVzZXQuICovCisjZGVmaW5lIEVQX0NNRF9FUFJT VAkJQklUKDApCisvKiBFbmRwb2ludCBTVEFMTCBzZXQuICovCisjZGVmaW5lIEVQX0NNRF9TU1RB TEwJCUJJVCgxKQorLyogRW5kcG9pbnQgU1RBTEwgY2xlYXIuICovCisjZGVmaW5lIEVQX0NNRF9D U1RBTEwJCUJJVCgyKQorLyogU2VuZCBFUkRZIFRQLiAqLworI2RlZmluZSBFUF9DTURfRVJEWQkJ QklUKDMpCisvKiBSZXF1ZXN0IGNvbXBsZXRlLiAqLworI2RlZmluZSBFUF9DTURfUkVRX0NNUEwJ CUJJVCg1KQorLyogVHJhbnNmZXIgZGVzY3JpcHRvciByZWFkeS4gKi8KKyNkZWZpbmUgRVBfQ01E X0RSRFkJCUJJVCg2KQorLyogRGF0YSBmbHVzaC4gKi8KKyNkZWZpbmUgRVBfQ01EX0RGTFVTSAkJ QklUKDcpCisvKgorICogVHJhbnNmZXIgRGVzY3JpcHRvciBMZW5ndGggd3JpdGUgICh1c2VkIG9u bHkgZm9yIEJ1bGsgU3RyZWFtIGNhcGFibGUKKyAqIGVuZHBvaW50cyBpbiBTUyBtb2RlKS4KKyAq LworI2RlZmluZSBFUF9DTURfU1RETAkJQklUKDgpCisvKiBUcmFuc2ZlciBEZXNjcmlwdG9yIExl bmd0aCAodXNlZCBvbmx5IGluIFNTIG1vZGUgZm9yIGJ1bGsgZW5kcG9pbnRzKS4gKi8KKyNkZWZp bmUgRVBfQ01EX1RETF9NQVNLCQlHRU5NQVNLKDE1LCA5KQorI2RlZmluZSBFUF9DTURfVERMKHAp CQkoKChwKSA8PCA5KSAmIEVQX0NNRF9URExfTUFTSykKKy8qIEVSRFkgU3RyZWFtIElEIHZhbHVl ICh1c2VkIGluIFNTIG1vZGUpLiAqLworI2RlZmluZSBFUF9DTURfRVJEWV9TSURfTUFTSwlHRU5N QVNLKDMxLCAxNikKKyNkZWZpbmUgRVBfQ01EX0VSRFlfU0lEKHApCSgoKHApIDw8IDE2KSAmIEVQ X0NNRF9TSURfTUFTSykKKworLyogRVBfU1RTIC0gYml0bWFza3MgKi8KKy8qIFNldHVwIHRyYW5z ZmVyIGNvbXBsZXRlLiAqLworI2RlZmluZSBFUF9TVFNfU0VUVVAJCUJJVCgwKQorLyogRW5kcG9p bnQgU1RBTEwgc3RhdHVzLiAqLworI2RlZmluZSBFUF9TVFNfU1RBTEwocCkJCSgocCkgJiBCSVQo MSkpCisvKiBJbnRlcnJ1cHQgT24gQ29tcGxldGUuICovCisjZGVmaW5lIEVQX1NUU19JT0MJCUJJ VCgyKQorLyogSW50ZXJydXB0IG9uIFNob3J0IFBhY2tldC4gKi8KKyNkZWZpbmUgRVBfU1RTX0lT UAkJQklUKDMpCisvKiBUcmFuc2ZlciBkZXNjcmlwdG9yIG1pc3NpbmcuICovCisjZGVmaW5lIEVQ X1NUU19ERVNDTUlTCQlCSVQoNCkKKy8qIFN0cmVhbSBSZWplY3RlZCAodXNlZCBvbmx5IGluIFNT IG1vZGUpICovCisjZGVmaW5lIEVQX1NUU19TVFJFQU1SCQlCSVQoNSkKKy8qIEVYSVQgZnJvbSBN T1ZFIERBVEEgU3RhdGUgKHVzZWQgb25seSBmb3Igc3RyZWFtIHRyYW5zZmVycyBpbiBTUyBtb2Rl KS4gKi8KKyNkZWZpbmUgRVBfU1RTX01EX0VYSVQJCUJJVCg2KQorLyogVFJCIGVycm9yLiAqLwor I2RlZmluZSBFUF9TVFNfVFJCRVJSCQlCSVQoNykKKy8qIE5vdCByZWFkeSAodXNlZCBvbmx5IGlu IFNTIG1vZGUpLiAqLworI2RlZmluZSBFUF9TVFNfTlJEWQkJQklUKDgpCisvKiBETUEgYnVzeS4g Ki8KKyNkZWZpbmUgRVBfU1RTX0RCVVNZKHApCQkoKHApICYgQklUKDkpKQorLyogRW5kcG9pbnQg QnVmZmVyIEVtcHR5ICovCisjZGVmaW5lIEVQX1NUU19CVUZGRU1QVFkocCkJKChwKSAmIEJJVCgx MCkpCisvKiBDdXJyZW50IEN5Y2xlIFN0YXR1cyAqLworI2RlZmluZSBFUF9TVFNfQ0NTKHApCQko KHApICYgQklUKDExKSkKKy8qIFByaW1lICh1c2VkIG9ubHkgaW4gU1MgbW9kZS4gKi8KKyNkZWZp bmUgRVBfU1RTX1BSSU1FCQlCSVQoMTIpCisvKiBTdHJlYW0gZXJyb3IgKHVzZWQgb25seSBpbiBT UyBtb2RlKS4gKi8KKyNkZWZpbmUgRVBfU1RTX1NJREVSUgkJQklUKDEzKQorLyogT1VUIHNpemUg bWlzbWF0Y2guICovCisjZGVmaW5lIEVQX1NUU19PVVRTTU0JCUJJVCgxNCkKKy8qIElTTyB0cmFu c21pc3Npb24gZXJyb3IuICovCisjZGVmaW5lIEVQX1NUU19JU09FUlIJCUJJVCgxNSkKKy8qIEhv c3QgUGFja2V0IFBlbmRpbmcgKG9ubHkgZm9yIFNTIG1vZGUpLiAqLworI2RlZmluZSBFUF9TVFNf SE9TVFBQKHApCSgocCkgJiBCSVQoMTYpKQorLyogU3RyZWFtIFByb3RvY29sIFN0YXRlIE1hY2hp bmUgU3RhdGUgKG9ubHkgZm9yIEJ1bGsgc3RyZWFtIGVuZHBvaW50cykuICovCisjZGVmaW5lIEVQ X1NUU19TUFNNU1RfTUFTSwkJR0VOTUFTSygxOCwgMTcpCisjZGVmaW5lIEVQX1NUU19TUFNNU1Rf RElTQUJMRUQocCkJKCgocCkgJiBFUF9TVFNfU1BTTVNUX01BU0spID4+IDE3KQorI2RlZmluZSBF UF9TVFNfU1BTTVNUX0lETEUocCkJCSgoKHApICYgRVBfU1RTX1NQU01TVF9NQVNLKSA+PiAxNykK KyNkZWZpbmUgRVBfU1RTX1NQU01TVF9TVEFSVF9TVFJFQU0ocCkJKCgocCkgJiBFUF9TVFNfU1BT TVNUX01BU0spID4+IDE3KQorI2RlZmluZSBFUF9TVFNfU1BTTVNUX01PVkVfREFUQShwKQkoKChw KSAmIEVQX1NUU19TUFNNU1RfTUFTSykgPj4gMTcpCisvKiBJbnRlcnJ1cHQgT24gVHJhbnNmZXIg Y29tcGxldGUuICovCisjZGVmaW5lIEVQX1NUU19JT1QJCUJJVCgxOSkKKy8qIE9VVCBxdWV1ZSBl bmRwb2ludCBudW1iZXIuICovCisjZGVmaW5lIEVQX1NUU19PVVRRX05PX01BU0sJR0VOTUFTSygy NywgMjQpCisjZGVmaW5lIEVQX1NUU19PVVRRX05PKHApCSgoKHApICYgRVBfU1RTX09VVFFfTk9f TUFTSykgPj4gMjQpCisvKiBPVVQgcXVldWUgdmFsaWQgZmxhZy4gKi8KKyNkZWZpbmUgRVBfU1RT X09VVFFfVkFMX01BU0sJQklUKDI4KQorI2RlZmluZSBFUF9TVFNfT1VUUV9WQUwocCkJKChwKSAm IEVQX1NUU19PVVRRX1ZBTF9NQVNLKQorLyogU0VUVVAgV0FJVC4gKi8KKyNkZWZpbmUgRVBfU1RT X1NUUFdBSVQJCUJJVCgzMSkKKworLyogRVBfU1RTX1NJRCAtIGJpdG1hc2tzICovCisvKiBTdHJl YW0gSUQgKHVzZWQgb25seSBpbiBTUyBtb2RlKS4gKi8KKyNkZWZpbmUgRVBfU1RTX1NJRF9NQVNL CQlHRU5NQVNLKDE1LCAwKQorI2RlZmluZSBFUF9TVFNfU0lEKHApCQkoKHApICYgRVBfU1RTX1NJ RF9NQVNLKQorCisvKiBFUF9TVFNfRU4gLSBiaXRtYXNrcyAqLworLyogU0VUVVAgaW50ZXJydXB0 IGVuYWJsZS4gKi8KKyNkZWZpbmUgRVBfU1RTX0VOX1NFVFVQRU4JQklUKDApCisvKiBPVVQgdHJh bnNmZXIgbWlzc2luZyBkZXNjcmlwdG9yIGVuYWJsZS4gKi8KKyNkZWZpbmUgRVBfU1RTX0VOX0RF U0NNSVNFTglCSVQoNCkKKy8qIFN0cmVhbSBSZWplY3RlZCBlbmFibGUuICovCisjZGVmaW5lIEVQ X1NUU19FTl9TVFJFQU1SRU4JQklUKDUpCisvKiBNb3ZlIERhdGEgRXhpdCBlbmFibGUuKi8KKyNk ZWZpbmUgRVBfU1RTX0VOX01EX0VYSVRFTglCSVQoNikKKy8qIFRSQiBlbmFibGUuICovCisjZGVm aW5lIEVQX1NUU19FTl9UUkJFUlJFTglCSVQoNykKKy8qIE5SRFkgZW5hYmxlLiAqLworI2RlZmlu ZSBFUF9TVFNfRU5fTlJEWUVOCUJJVCg4KQorLyogUHJpbWUgZW5hYmxlLiAqLworI2RlZmluZSBF UF9TVFNfRU5fUFJJTUVFRU4JQklUKDEyKQorLyogU3RyZWFtIGVycm9yIGVuYWJsZS4gKi8KKyNk ZWZpbmUgRVBfU1RTX0VOX1NJREVSUkVOCUJJVCgxMykKKy8qIE9VVCBzaXplIG1pc21hdGNoIGVu YWJsZS4gKi8KKyNkZWZpbmUgRVBfU1RTX0VOX09VVFNNTUVOCUJJVCgxNCkKKy8qIElTTyB0cmFu c21pc3Npb24gZXJyb3IgZW5hYmxlLiAqLworI2RlZmluZSBFUF9TVFNfRU5fSVNPRVJSRU4JQklU KDE1KQorLyogSW50ZXJydXB0IG9uIFRyYW5zbWlzc2lvbiBjb21wbGV0ZSBlbmFibGUuICovCisj ZGVmaW5lIEVQX1NUU19FTl9JT1RFTgkJQklUKDE5KQorLyogU2V0dXAgV2FpdCBpbnRlcnJ1cHQg ZW5hYmxlLiAqLworI2RlZmluZSBFUF9TVFNfRU5fU1RQV0FJVEVOCUJJVCgzMSkKKworLyogRFJC TC0gYml0bWFza3MgKi8KKyNkZWZpbmUgREJfVkFMVUVfQllfSU5ERVgoaW5kZXgpICgxIDw8IChp bmRleCkpCisjZGVmaW5lIERCX1ZBTFVFX0VQMF9PVVQJQklUKDApCisjZGVmaW5lIERCX1ZBTFVF X0VQMF9JTgkJQklUKDE2KQorCisvKiBFUF9JRU4gLSBiaXRtYXNrcyAqLworI2RlZmluZSBFUF9J RU4oaW5kZXgpCQkoMSA8PCAoaW5kZXgpKQorI2RlZmluZSBFUF9JRU5fRVBfT1VUMAkJQklUKDAp CisjZGVmaW5lIEVQX0lFTl9FUF9JTjAJCUJJVCgxNikKKworLyogRVBfSVNUUyAtIGJpdG1hc2tz ICovCisjZGVmaW5lIEVQX0lTVFMoaW5kZXgpCQkoMSA8PCAoaW5kZXgpKQorI2RlZmluZSBFUF9J U1RTX0VQX09VVDAJCUJJVCgwKQorI2RlZmluZSBFUF9JU1RTX0VQX0lOMAkJQklUKDE2KQorCisv KiBFUF9QV1ItIGJpdG1hc2tzICovCisvKlBvd2VyIFNodXQgT2ZmIGNhcGFiaWxpdHkgZW5hYmxl Ki8KKyNkZWZpbmUgUFVTQl9QV1JfUFNPX0VOCQlCSVQoMCkKKy8qUG93ZXIgU2h1dCBPZmYgY2Fw YWJpbGl0eSBkaXNhYmxlKi8KKyNkZWZpbmUgUFVTQl9QV1JfUFNPX0RTCQlCSVQoMSkKKy8qCisg KiBFbmFibGVzIHR1cm5pbmctb2ZmIFJlZmVyZW5jZSBDbG9jay4KKyAqIFRoaXMgYml0IGlzIG9w dGlvbmFsIGFuZCBpbXBsZW1lbnRlZCBvbmx5IHdoZW4gc3VwcG9ydCBmb3IgT1RHIGlzCisgKiBp bXBsZW1lbnRlZCAoaW5kaWNhdGVkIGJ5IE9UR19SRUFEWSBiaXQgc2V0IHRvICcxJykuCisgKi8K KyNkZWZpbmUgUFVTQl9QV1JfU1RCX0NMS19TV0lUQ0hfRU4JQklUKDgpCisvKgorICogU3RhdHVz IGJpdCBpbmRpY2F0aW5nIHRoYXQgb3BlcmF0aW9uIHJlcXVpcmVkIGJ5IFNUQl9DTEtfU1dJVENI X0VOIHdyaXRlCisgKiBpcyBjb21wbGV0ZWQKKyAqLworI2RlZmluZSBQVVNCX1BXUl9TVEJfQ0xL X1NXSVRDSF9ET05FCUJJVCg5KQorLyogVGhpcyBiaXQgaW5mb3JtcyBpZiBGYXN0IFJlZ2lzdGVy cyBBY2Nlc3MgaXMgZW5hYmxlZC4gKi8KKyNkZWZpbmUgUFVTQl9QV1JfRlNUX1JFR19BQ0NFU1Nf U1RBVAlCSVQoMzApCisvKiBGYXN0IFJlZ2lzdGVycyBBY2Nlc3MgRW5hYmxlLiAqLworI2RlZmlu ZSBQVVNCX1BXUl9GU1RfUkVHX0FDQ0VTUwlCSVQoMzEpCisKKy8qIFVTQl9DQVAxLSBiaXRtYXNr cyAqLworLyoKKyAqIFNGUiBJbnRlcmZhY2UgdHlwZQorICogVGhlc2UgZmllbGQgcmVmbGVjdHMg dHlwZSBvZiBTRlIgaW50ZXJmYWNlIGltcGxlbWVudGVkOgorICogMHgwIC0gT0NQCisgKiAweDEg LSBBSEIsCisgKiAweDIgLSBQTEIKKyAqIDB4MyAtIEFYSQorICogMHg0LTB4RiAtIHJlc2VydmVk CisgKi8KKyNkZWZpbmUgVVNCX0NBUDFfU0ZSX1RZUEVfTUFTSwlHRU5NQVNLKDMsIDApCisjZGVm aW5lIERFVl9TRlJfVFlQRV9PQ1AocCkJKCgocCkgJiBVU0JfQ0FQMV9TRlJfVFlQRV9NQVNLKSA9 PSAweDApCisjZGVmaW5lIERFVl9TRlJfVFlQRV9BSEIocCkJKCgocCkgJiBVU0JfQ0FQMV9TRlJf VFlQRV9NQVNLKSA9PSAweDEpCisjZGVmaW5lIERFVl9TRlJfVFlQRV9QTEIocCkJKCgocCkgJiBV U0JfQ0FQMV9TRlJfVFlQRV9NQVNLKSA9PSAweDIpCisjZGVmaW5lIERFVl9TRlJfVFlQRV9BWEko cCkJKCgocCkgJiBVU0JfQ0FQMV9TRlJfVFlQRV9NQVNLKSA9PSAweDMpCisvKgorICogU0ZSIElu dGVyZmFjZSB3aWR0aAorICogVGhlc2UgZmllbGQgcmVmbGVjdHMgd2lkdGggb2YgU0ZSIGludGVy ZmFjZSBpbXBsZW1lbnRlZDoKKyAqIDB4MCAtIDggYml0IGludGVyZmFjZSwKKyAqIDB4MSAtIDE2 IGJpdCBpbnRlcmZhY2UsCisgKiAweDIgLSAzMiBiaXQgaW50ZXJmYWNlCisgKiAweDMgLSA2NCBi aXQgaW50ZXJmYWNlCisgKiAweDQtMHhGIC0gcmVzZXJ2ZWQKKyAqLworI2RlZmluZSBVU0JfQ0FQ MV9TRlJfV0lEVEhfTUFTSwlHRU5NQVNLKDcsIDQpCisjZGVmaW5lIERFVl9TRlJfV0lEVEhfOChw KQkoKChwKSAmIFVTQl9DQVAxX1NGUl9XSURUSF9NQVNLKSA9PSAoMHgwIDw8IDQpKQorI2RlZmlu ZSBERVZfU0ZSX1dJRFRIXzE2KHApCSgoKHApICYgVVNCX0NBUDFfU0ZSX1dJRFRIX01BU0spID09 ICgweDEgPDwgNCkpCisjZGVmaW5lIERFVl9TRlJfV0lEVEhfMzIocCkJKCgocCkgJiBVU0JfQ0FQ MV9TRlJfV0lEVEhfTUFTSykgPT0gKDB4MiA8PCA0KSkKKyNkZWZpbmUgREVWX1NGUl9XSURUSF82 NChwKQkoKChwKSAmIFVTQl9DQVAxX1NGUl9XSURUSF9NQVNLKSA9PSAoMHgzIDw8IDQpKQorLyoK KyAqIERNQSBJbnRlcmZhY2UgdHlwZQorICogVGhlc2UgZmllbGQgcmVmbGVjdHMgdHlwZSBvZiBE TUEgaW50ZXJmYWNlIGltcGxlbWVudGVkOgorICogMHgwIC0gT0NQCisgKiAweDEgLSBBSEIsCisg KiAweDIgLSBQTEIKKyAqIDB4MyAtIEFYSQorICogMHg0LTB4RiAtIHJlc2VydmVkCisgKi8KKyNk ZWZpbmUgVVNCX0NBUDFfRE1BX1RZUEVfTUFTSwlHRU5NQVNLKDExLCA4KQorI2RlZmluZSBERVZf RE1BX1RZUEVfT0NQKHApCSgoKHApICYgVVNCX0NBUDFfRE1BX1RZUEVfTUFTSykgPT0gKDB4MCA8 PCA4KSkKKyNkZWZpbmUgREVWX0RNQV9UWVBFX0FIQihwKQkoKChwKSAmIFVTQl9DQVAxX0RNQV9U WVBFX01BU0spID09ICgweDEgPDwgOCkpCisjZGVmaW5lIERFVl9ETUFfVFlQRV9QTEIocCkJKCgo cCkgJiBVU0JfQ0FQMV9ETUFfVFlQRV9NQVNLKSA9PSAoMHgyIDw8IDgpKQorI2RlZmluZSBERVZf RE1BX1RZUEVfQVhJKHApCSgoKHApICYgVVNCX0NBUDFfRE1BX1RZUEVfTUFTSykgPT0gKDB4MyA8 PCA4KSkKKy8qCisgKiBETUEgSW50ZXJmYWNlIHdpZHRoCisgKiBUaGVzZSBmaWVsZCByZWZsZWN0 cyB3aWR0aCBvZiBETUEgaW50ZXJmYWNlIGltcGxlbWVudGVkOgorICogMHgwIC0gcmVzZXJ2ZWQs CisgKiAweDEgLSByZXNlcnZlZCwKKyAqIDB4MiAtIDMyIGJpdCBpbnRlcmZhY2UKKyAqIDB4MyAt IDY0IGJpdCBpbnRlcmZhY2UKKyAqIDB4NC0weEYgLSByZXNlcnZlZAorICovCisjZGVmaW5lIFVT Ql9DQVAxX0RNQV9XSURUSF9NQVNLCUdFTk1BU0soMTUsIDEyKQorI2RlZmluZSBERVZfRE1BX1dJ RFRIXzMyKHApCSgoKHApICYgVVNCX0NBUDFfRE1BX1dJRFRIX01BU0spID09ICgweDIgPDwgMTIp KQorI2RlZmluZSBERVZfRE1BX1dJRFRIXzY0KHApCSgoKHApICYgVVNCX0NBUDFfRE1BX1dJRFRI X01BU0spID09ICgweDMgPDwgMTIpKQorLyoKKyAqIFVTQjMgUEhZIEludGVyZmFjZSB0eXBlCisg KiBUaGVzZSBmaWVsZCByZWZsZWN0cyB0eXBlIG9mIFVTQjMgUEhZIGludGVyZmFjZSBpbXBsZW1l bnRlZDoKKyAqIDB4MCAtIFVTQiBQSVBFLAorICogMHgxIC0gUk1NSSwKKyAqIDB4Mi0weEYgLSBy ZXNlcnZlZAorICovCisjZGVmaW5lIFVTQl9DQVAxX1UzUEhZX1RZUEVfTUFTSyBHRU5NQVNLKDE5 LCAxNikKKyNkZWZpbmUgREVWX1UzUEhZX1BJUEUocCkgKCgocCkgJiBVU0JfQ0FQMV9VM1BIWV9U WVBFX01BU0spID09ICgweDAgPDwgMTYpKQorI2RlZmluZSBERVZfVTNQSFlfUk1NSShwKSAoKChw KSAmIFVTQl9DQVAxX1UzUEhZX1RZUEVfTUFTSykgPT0gKDB4MSA8PCAxNikpCisvKgorICogVVNC MyBQSFkgSW50ZXJmYWNlIHdpZHRoCisgKiBUaGVzZSBmaWVsZCByZWZsZWN0cyB3aWR0aCBvZiBV U0IzIFBIWSBpbnRlcmZhY2UgaW1wbGVtZW50ZWQ6CisgKiAweDAgLSA4IGJpdCBQSVBFIGludGVy ZmFjZSwKKyAqIDB4MSAtIDE2IGJpdCBQSVBFIGludGVyZmFjZSwKKyAqIDB4MiAtIDMyIGJpdCBQ SVBFIGludGVyZmFjZSwKKyAqIDB4MyAtIDY0IGJpdCBQSVBFIGludGVyZmFjZQorICogMHg0LTB4 RiAtIHJlc2VydmVkCisgKiBOb3RlOiBXaGVuIFNTSUMgaW50ZXJmYWNlIGlzIGltcGxlbWVudGVk IHRoaXMgZmllbGQgc2hvd3MgdGhlIHdpZHRoIG9mCisgKiBpbnRlcm5hbCBQSVBFIGludGVyZmFj ZS4gVGhlIFJNTUkgaW50ZXJmYWNlIGlzIGFsd2F5cyAyMGJpdCB3aWRlLgorICovCisjZGVmaW5l IFVTQl9DQVAxX1UzUEhZX1dJRFRIX01BU0sgR0VOTUFTSygyMywgMjApCisjZGVmaW5lIERFVl9V M1BIWV9XSURUSF84KHApIFwKKwkoKChwKSAmIFVTQl9DQVAxX1UzUEhZX1dJRFRIX01BU0spID09 ICgweDAgPDwgMjApKQorI2RlZmluZSBERVZfVTNQSFlfV0lEVEhfMTYocCkgXAorCSgoKHApICYg VVNCX0NBUDFfVTNQSFlfV0lEVEhfTUFTSykgPT0gKDB4MSA8PCAxNikpCisjZGVmaW5lIERFVl9V M1BIWV9XSURUSF8zMihwKSBcCisJKCgocCkgJiBVU0JfQ0FQMV9VM1BIWV9XSURUSF9NQVNLKSA9 PSAoMHgyIDw8IDIwKSkKKyNkZWZpbmUgREVWX1UzUEhZX1dJRFRIXzY0KHApIFwKKwkoKChwKSAm IFVTQl9DQVAxX1UzUEhZX1dJRFRIX01BU0spID09ICgweDMgPDwgMTYpKQorCisvKgorICogVVNC MiBQSFkgSW50ZXJmYWNlIGVuYWJsZQorICogVGhlc2UgZmllbGQgaW5mb3JtcyBpZiBVU0IyIFBI WSBpbnRlcmZhY2UgaXMgaW1wbGVtZW50ZWQ6CisgKiAweDAgLSBpbnRlcmZhY2UgTk9UIGltcGxl bWVudGVkLAorICogMHgxIC0gaW50ZXJmYWNlIGltcGxlbWVudGVkCisgKi8KKyNkZWZpbmUgVVNC X0NBUDFfVTJQSFlfRU4ocCkJKChwKSAmIEJJVCgyNCkpCisvKgorICogVVNCMiBQSFkgSW50ZXJm YWNlIHR5cGUKKyAqIFRoZXNlIGZpZWxkIHJlZmxlY3RzIHR5cGUgb2YgVVNCMiBQSFkgaW50ZXJm YWNlIGltcGxlbWVudGVkOgorICogMHgwIC0gVVRNSSwKKyAqIDB4MSAtIFVMUEkKKyAqLworI2Rl ZmluZSBERVZfVTJQSFlfVUxQSShwKQkoKHApICYgQklUKDI1KSkKKy8qCisgKiBVU0IyIFBIWSBJ bnRlcmZhY2Ugd2lkdGgKKyAqIFRoZXNlIGZpZWxkIHJlZmxlY3RzIHdpZHRoIG9mIFVTQjIgUEhZ IGludGVyZmFjZSBpbXBsZW1lbnRlZDoKKyAqIDB4MCAtIDggYml0IGludGVyZmFjZSwKKyAqIDB4 MSAtIDE2IGJpdCBpbnRlcmZhY2UsCisgKiBOb3RlOiBUaGUgVUxQSSBpbnRlcmZhY2UgaXMgYWx3 YXlzIDhiaXQgd2lkZS4KKyAqLworI2RlZmluZSBERVZfVTJQSFlfV0lEVEhfMTYocCkJKChwKSAm IEJJVCgyNikpCisvKgorICogT1RHIFJlYWR5CisgKiAweDAgLSBwdXJlIGRldmljZSBtb2RlCisg KiAweDEgLSBzb21lIGZlYXR1cmVzIGFuZCBwb3J0cyBmb3IgQ0ROUyBVU0IgT1RHIGNvbnRyb2xs ZXIgYXJlIGltcGxlbWVudGVkLgorICovCisjZGVmaW5lIFVTQl9DQVAxX09UR19SRUFEWShwKQko KHApICYgQklUKDI3KSkKKworLyogVVNCX0NBUDItIGJpdG1hc2tzICovCisvKgorICogVGhlIGFj dHVhbCBzaXplIG9mIHRoZSBjb25uZWN0ZWQgT24tY2hpcCBSQU0gbWVtb3J5IGluIGtCOgorICog LSAwIG1lYW5zIDI1NiBrQiAobWF4IHN1cHBvcnRlZCBtZW0gc2l6ZSkKKyAqIC0gdmFsdWUgb3Ro ZXIgdGhhbiAwIHJlZmxlY3RzIHRoZSBtZW0gc2l6ZSBpbiBrQgorICovCisjZGVmaW5lIFVTQl9D QVAyX0FDVFVBTF9NRU1fU0laRShwKSAoKHApICYgR0VOTUFTSyg3LCAwKSkKKy8qCisgKiBNYXgg c3VwcG9ydGVkIG1lbSBzaXplCisgKiBUaGVzZSBmaWVsZCByZWZsZWN0cyB3aWR0aCBvZiBvbi1j aGlwIFJBTSBhZGRyZXNzIGJ1cyB3aWR0aCwKKyAqIHdoaWNoIGRldGVybWluZXMgbWF4IHN1cHBv cnRlZCBtZW0gc2l6ZToKKyAqIDB4MC0weDcgLSByZXNlcnZlZCwKKyAqIDB4OCAtIHN1cHBvcnQg Zm9yIDRrQiBtZW0sCisgKiAweDkgLSBzdXBwb3J0IGZvciA4a0IgbWVtLAorICogMHhBIC0gc3Vw cG9ydCBmb3IgMTZrQiBtZW0sCisgKiAweEIgLSBzdXBwb3J0IGZvciAzMmtCIG1lbSwKKyAqIDB4 QyAtIHN1cHBvcnQgZm9yIDY0a0IgbWVtLAorICogMHhEIC0gc3VwcG9ydCBmb3IgMTI4a0IgbWVt LAorICogMHhFIC0gc3VwcG9ydCBmb3IgMjU2a0IgbWVtLAorICogMHhGIC0gcmVzZXJ2ZWQKKyAq LworI2RlZmluZSBVU0JfQ0FQMl9NQVhfTUVNX1NJWkUocCkgKChwKSAmIEdFTk1BU0soMTEsIDgp KQorCisvKiBVU0JfQ0FQMy0gYml0bWFza3MgKi8KKyNkZWZpbmUgRVBfSVNfSU1QTEVNRU5URUQo cmVnLCBpbmRleCkgKChyZWcpICYgKDEgPDwgKGluZGV4KSkpCisKKy8qIFVTQl9DQVA0LSBiaXRt YXNrcyAqLworI2RlZmluZSBFUF9TVVBQT1JUX0lTTyhyZWcsIGluZGV4KSAoKHJlZykgJiAoMSA8 PCAoaW5kZXgpKSkKKworLyogVVNCX0NBUDUtIGJpdG1hc2tzICovCisjZGVmaW5lIEVQX1NVUFBP UlRfU1RSRUFNKHJlZywgaW5kZXgpICgocmVnKSAmICgxIDw8IChpbmRleCkpKQorCisvKiBVU0Jf Q0FQNi0gYml0bWFza3MgKi8KKy8qIFRoZSBVU0JTUy1ERVYgQ29udHJvbGxlciAgSW50ZXJuYWwg YnVpbGQgbnVtYmVyLiAqLworI2RlZmluZSBHRVRfREVWX1ZFUlNJT05fX0lOVEVSTkFMX05VTUJF UihwKSAoKHApICYgR0VOTUFTSyg3LCAwKSkKKy8qIFRoZSBVU0JTUy1ERVYgQ29udHJvbGxlciAg dmVyc2lvbiBudW1iZXIuICovCisjZGVmaW5lIEdFVF9ERVZfVkVSU0lPTihwKSAoKHApICYgR0VO TUFTSygzMSwgOCkpCisKKy8qIERCR19MSU5LMS0gYml0bWFza3MgKi8KKy8qCisgKiBMRlBTX01J Tl9ERVRfVTFfRVhJVCB2YWx1ZSBUaGlzIHBhcmFtZXRlciBjb25maWd1cmVzIHRoZSBtaW5pbXVt CisgKiB0aW1lIHJlcXVpcmVkIGZvciBkZWNvZGluZyB0aGUgcmVjZWl2ZWQgTEZQUyBhcyBhbiBM RlBTLlUxX0V4aXQuCisgKi8KKyNkZWZpbmUgREJHX0xJTksxX0xGUFNfTUlOX0RFVF9VMV9FWElU KHApCSgocCkgJiBHRU5NQVNLKDcsIDApKQorLyoKKyAqIExGUFNfTUlOX0dFTl9VMV9FWElUIHZh bHVlIFRoaXMgcGFyYW1ldGVyIGNvbmZpZ3VyZXMgdGhlIG1pbmltdW0gdGltZSBmb3IKKyAqIHBo eXR4ZWxlY2lkbGUgZGVhc3NlcnRpb24gd2hlbiBMRlBTLlUxX0V4aXQKKyAqLworI2RlZmluZSBE QkdfTElOSzFfTEZQU19NSU5fR0VOX1UxX0VYSVQocCkJKCgocCkgPDwgOCkgJiBHRU5NQVNLKDE1 LCA4KSkKKy8qCisgKiBSWERFVF9CUkVBS19ESVMgdmFsdWUgVGhpcyBwYXJhbWV0ZXIgY29uZmln dXJlcyB0ZXJtaW5hdGluZyB0aGUgRmFyLWVuZAorICogUmVjZWl2ZXIgdGVybWluYXRpb24gZGV0 ZWN0aW9uIHNlcXVlbmNlOgorICogMDogaXQgaXMgcG9zc2libGUgdGhhdCBVU0JTU19ERVYgd2ls bCB0ZXJtaW5hdGUgRmFyZW5kIHJlY2VpdmVyCisgKiAgICB0ZXJtaW5hdGlvbiBkZXRlY3Rpb24g c2VxdWVuY2UKKyAqIDE6IFVTQlNTX0RFViB3aWxsIG5vdCB0ZXJtaW5hdGUgRmFyLWVuZCByZWNl aXZlciB0ZXJtaW5hdGlvbgorICogICAgZGV0ZWN0aW9uIHNlcXVlbmNlCisgKi8KKyNkZWZpbmUg REJHX0xJTksxX1JYREVUX0JSRUFLX0RJUwkJQklUKDE2KQorLyogTEZQU19HRU5fUElORyB2YWx1 ZSBUaGlzIHBhcmFtZXRlciBjb25maWd1cmVzIHRoZSBMRlBTLlBpbmcgZ2VuZXJhdGlvbiAqLwor I2RlZmluZSBEQkdfTElOSzFfTEZQU19HRU5fUElORyhwKQkJKCgocCkgPDwgMTcpICYgR0VOTUFT SygyMSwgMTcpKQorLyoKKyAqIFNldCB0aGUgTEZQU19NSU5fREVUX1UxX0VYSVQgdmFsdWUgV3Jp dGluZyAnMScgdG8gdGhpcyBiaXQgd3JpdGVzIHRoZQorICogTEZQU19NSU5fREVUX1UxX0VYSVQg ZmllbGQgdmFsdWUgdG8gdGhlIGRldmljZS4gVGhpcyBiaXQgaXMgYXV0b21hdGljYWxseQorICog Y2xlYXJlZC4gV3JpdGluZyAnMCcgaGFzIG5vIGVmZmVjdAorICovCisjZGVmaW5lIERCR19MSU5L MV9MRlBTX01JTl9ERVRfVTFfRVhJVF9TRVQJQklUKDI0KQorLyoKKyAqIFNldCB0aGUgTEZQU19N SU5fR0VOX1UxX0VYSVQgdmFsdWUuIFdyaXRpbmcgJzEnIHRvIHRoaXMgYml0IHdyaXRlcyB0aGUK KyAqIExGUFNfTUlOX0dFTl9VMV9FWElUIGZpZWxkIHZhbHVlIHRvIHRoZSBkZXZpY2UuIFRoaXMg Yml0IGlzIGF1dG9tYXRpY2FsbHkKKyAqIGNsZWFyZWQuIFdyaXRpbmcgJzAnIGhhcyBubyBlZmZl Y3QKKyAqLworI2RlZmluZSBEQkdfTElOSzFfTEZQU19NSU5fR0VOX1UxX0VYSVRfU0VUCUJJVCgy NSkKKy8qCisgKiBTZXQgdGhlIFJYREVUX0JSRUFLX0RJUyB2YWx1ZSBXcml0aW5nICcxJyB0byB0 aGlzIGJpdCB3cml0ZXMKKyAqIHRoZSBSWERFVF9CUkVBS19ESVMgZmllbGQgdmFsdWUgdG8gdGhl IGRldmljZS4gVGhpcyBiaXQgaXMgYXV0b21hdGljYWxseQorICogY2xlYXJlZC4gV3JpdGluZyAn MCcgaGFzIG5vIGVmZmVjdAorICovCisjZGVmaW5lIERCR19MSU5LMV9SWERFVF9CUkVBS19ESVNf U0VUCQlCSVQoMjYpCisvKgorICogU2V0IHRoZSBMRlBTX0dFTl9QSU5HX1NFVCB2YWx1ZSBXcml0 aW5nICcxJyB0byB0aGlzIGJpdCB3cml0ZXMKKyAqIHRoZSBMRlBTX0dFTl9QSU5HIGZpZWxkIHZh bHVlIHRvIHRoZSBkZXZpY2UuIFRoaXMgYml0IGlzIGF1dG9tYXRpY2FsbHkKKyAqIGNsZWFyZWQu IFdyaXRpbmcgJzAnIGhhcyBubyBlZmZlY3QuIgorICovCisjZGVmaW5lIERCR19MSU5LMV9MRlBT X0dFTl9QSU5HX1NFVAkJQklUKDI3KQorCisjZGVmaW5lIGdhZGdldF90b19jZG5zM19kZXZpY2Uo ZykgKGNvbnRhaW5lcl9vZihnLCBzdHJ1Y3QgY2RuczNfZGV2aWNlLCBnYWRnZXQpKQorCisjZGVm aW5lIGVwX3RvX2NkbnMzX2VwKGVwKSAoY29udGFpbmVyX29mKGVwLCBzdHJ1Y3QgY2RuczNfZW5k cG9pbnQsIGVuZHBvaW50KSkKKworLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi8KKy8qCisgKiBVU0JTUy1E RVYgRE1BIGludGVyZmFjZSAuCisgKi8KKyNkZWZpbmUgVFJCU19QRVJfU0VHTUVOVAkxNgorCisv KioKKyAqIHN0cnVjdCBjZG5zM190cmIgLSByZXByZXNlbnQgVHJhbnNmZXIgRGVzY3JpcHRvciBi bG9jay4KKyAqIEBidWZmZXI6CXBvaW50ZXIgdG8gYnVmZmVyIGRhdGEKKyAqIEBsZW5ndGg6CWxl bmd0aCBvZiBkYXRhCisgKiBAY29udHJvbDoJY29udHJvbCBmbGFncy4KKyAqCisgKiBUaGlzIHN0 cnVjdHVyZSBkZXNjcmliZXMgdHJhbnNmZXIgYmxvY2sgc2VydmljZWQgYnkgRE1BIG1vZHVsZS4K KyAqLworc3RydWN0IGNkbnMzX3RyYiB7CisJX19sZTMyIGJ1ZmZlcjsKKwlfX2xlMzIgbGVuZ3Ro OworCV9fbGUzMiBjb250cm9sOworfTsKKworI2RlZmluZSBUUkJfU0laRQkJKHNpemVvZihzdHJ1 Y3QgY2RuczNfdHJiKSkKKyNkZWZpbmUgVFJCX1JJTkdfU0laRQkJKFRSQl9TSVpFICogVFJCU19Q RVJfU0VHTUVOVCkKKworLyogVFJCIGJpdCBtYXNrICovCisjZGVmaW5lIFRSQl9UWVBFX0JJVE1B U0sJR0VOTUFTSygxNSwgMTApCisjZGVmaW5lIFRSQl9UWVBFKHApCQkoKHApIDw8IDEwKQorI2Rl ZmluZSBUUkJfRklFTERfVE9fVFlQRShwKQkoKChwKSAmIFRSQl9UWVBFX0JJVE1BU0spID4+IDEw KQorCisvKiBUUkIgdHlwZSBJRHMgKi8KKy8qIGJ1bGssIGludGVycnVwdCwgaXNvYyAsIGFuZCBj b250cm9sIGRhdGEgc3RhZ2UgKi8KKyNkZWZpbmUgVFJCX05PUk1BTAkJMQorLyogVFJCIGZvciBs aW5raW5nIHJpbmcgc2VnbWVudHMgKi8KKyNkZWZpbmUgVFJCX0xJTksJCTYKKworLyogQ3ljbGUg Yml0IC0gaW5kaWNhdGVzIFRSQiBvd25lcnNoaXAgYnkgZHJpdmVyIG9yIGh3Ki8KKyNkZWZpbmUg VFJCX0NZQ0xFCQlCSVQoMCkKKy8qCisgKiBXaGVuIHNldCB0byAnMScsIHRoZSBkZXZpY2Ugd2ls bCB0b2dnbGUgaXRzIGludGVycHJldGF0aW9uIG9mIHRoZSBDeWNsZSBiaXQKKyAqLworI2RlZmlu ZSBUUkJfVE9HR0xFCQlCSVQoMSkKKworLyogSW50ZXJydXB0IG9uIHNob3J0IHBhY2tldCovCisj ZGVmaW5lIFRSQl9JU1AJCQlCSVQoMikKKy8qU2V0dGluZyB0aGlzIGJpdCBlbmFibGVzIEZJRk8g RE1BIG9wZXJhdGlvbiBtb2RlKi8KKyNkZWZpbmUgVFJCX0ZJRk9fTU9ERQkJQklUKDMpCisvKiBT ZXQgUENJZSBubyBzbm9vcCBhdHRyaWJ1dGUgKi8KKyNkZWZpbmUgVFJCX0NIQUlOCQlCSVQoNCkK Ky8qIEludGVycnVwdCBvbiBjb21wbGV0aW9uICovCisjZGVmaW5lIFRSQl9JT0MJCQlCSVQoNSkK KworLyogc3RyZWFtIElEIGJpdG1hc2tzLiAqLworI2RlZmluZSBUUkJfU1RSRUFNX0lEKHApCSgo cCkgJiBHRU5NQVNLKDMxLCAxNikpCisKKy8qIHRyYW5zZmVyX2xlbiBiaXRtYXNrcy4gKi8KKyNk ZWZpbmUgVFJCX0xFTihwKQkJKChwKSAmIEdFTk1BU0soMTYsIDApKQorCisvKiB0cmFuc2Zlcl9s ZW4gYml0bWFza3MgLSBiaXRzIDMxOjI0ICovCisjZGVmaW5lIFRSQl9CVVJTVF9MRU4ocCkJKChw KSAmIEdFTk1BU0soMzEsIDI0KSkKKworLyogRGF0YSBidWZmZXIgcG9pbnRlciBiaXRtYXNrcyov CisjZGVmaW5lIFRSQl9CVUZGRVIocCkJCSgocCkgJiBHRU5NQVNLKDMxLCAwKSkKKworLyotLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tKi8KKy8qIERyaXZlciBudW1lcmljIGNvbnN0YW50cyAqLworCisvKiBTdWNo IGRlY2xhcmF0aW9uIHNob3VsZCBiZSBhZGRlZCB0byBjaDkuaCAqLworI2RlZmluZSBVU0JfREVW SUNFX01BWF9BRERSRVNTCTEyNworCisvKiBFbmRwb2ludCBpbml0IHZhbHVlcyAqLworI2RlZmlu ZSBDRE5TM19FUF9NQVhfUEFDS0VUX0xJTUlUCTEwMjQKKyNkZWZpbmUgQ0ROUzNfRVBfTUFYX1NU UkVBTVMJCTE1CisKKyNkZWZpbmUgQ0ROUzNfRVAwX01BWF9QQUNLRVRfTElNSVQJNTEyCisKKy8q IEFsbCBlbmRwb2ludHMgZXhjZXB0IEVQMCAqLworI2RlZmluZSBDRE5TM19FTkRQT0lOVFNfTUFY X0NPVU5UCTMwCisKKyNkZWZpbmUgQ0ROUzNfRVBfWkxQX0JVRl9TSVpFCQkxMDI0CisKKy8qLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLSovCisjZGVmaW5lIENETlMzX0VQX0JVRl9TSVpFCTIJLyogS0IgKi8KKyNk ZWZpbmUgQ0ROUzNfQUxJR05FRF9CVUZfU0laRQkxNjM4NCAvKiBCeXRlcyAqLworI2RlZmluZSBD RE5TM19ERVNDTUlTX0JVRl9TSVpFCTY1NTM2IC8qIEJ5dGVzICovCisvKi0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0qLworLyogVXNlZCBzdHJ1Y3RzICovCisKK3N0cnVjdCBjZG5zM19kZXZpY2U7CisKKy8qKgor ICogc3RydWN0IGNkbnMzX2VuZHBvaW50IC0gZXh0ZW5kZWQgZGV2aWNlIHNpZGUgcmVwcmVzZW50 YXRpb24gb2YgVVNCIGVuZHBvaW50LgorICogQGVuZHBvaW50OiB1c2IgZW5kcG9pbnQKKyAqIEBy ZXF1ZXN0X2xpc3Q6IGxpc3Qgb2YgcmVxdWVzdCBmb3IgdGhpcyBlbmRwb2ludAorICogQHRyYl9w b29sOiB0cmFuc2ZlciByaW5nIC0gYXJyYXkgb2YgdHJhbnNhY3Rpb24gYnVmZmVycworICogQHRy Yl9wb29sX2RtYTogZG1hIGFkZHJlc3Mgb2YgdHJhbnNmZXIgcmluZworICogQGNkbnMzX2Rldjog ZGV2aWNlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGVuZHBvaW50CisgKiBAbmFtZTogYSBodW1hbiBy ZWFkYWJsZSBuYW1lIGUuZy4gZXAxb3V0CisgKiBAZmxhZ3M6IHNwZWNpZnkgdGhlIGN1cnJlbnQg c3RhdGUgb2YgZW5kcG9pbnQKKyAqIEBkZXNjbWlzX3JlcTogaW50ZXJuYWwgdHJhbnNmZXIgb2Jq ZWN0IHVzZWQgZm9yIGdldHRpbmcgZGF0YSBmcm9tIG9uLWNoaXAKKyAqICAgICBidWZmZXIuIEl0 IGNhbiBoYXBwZW4gb25seSBpZiBmdW5jdGlvbiBkcml2ZXIgZG9lc24ndCBzZW5kIHVzYl9yZXF1 ZXN0CisgKiAgICAgb2JqZWN0IG9uIHRpbWUuCisgKiBAZGVzY21pc19wZW5kaW5nOiBmbGFnIHNw ZWNpZnkgdGhhdCBpbnRlcm5hbCBidWZmZXIgd2FzIHVzZWQgZm9yIERNQSB0bworICogICAgIHRh a2UgZGF0YSBmcm9tIHNoYXJlZCBvbi1jaGlwIGJ1ZmZlcnMgdG8gYXZvaWQgYmxvY2tpbmcgdHJh bnNmZXIgdG8gb3RoZXIKKyAqICAgICBlbmRwb2ludHMuIEl0IGluZGljYXRlIHRoYXQgaXMgc3Rp bGwgaW4gcHJvZ3Jlc3MuCisgKiBAZGVzY21pc19maW5pc2hlZDogZmxhZyBzcGVjaWZ5IHRoYXQg dHJhbnNmZXIgaGFzIGFybWVkIG9uIGRlc2NyaXB0b3IKKyAqICAgICBtaXNzaW5nIGV2ZW50IGhh cyBiZWVuIGNvbXBsZXRlZC4gSWYgZnVuY3Rpb24gZHJpdmVyIHJlcXVlc3RzCisgKiAgICAgdGhl IHRyYW5zZmVyIHRoZW4gY29udHJvbGxlciBkcml2ZXIgY2FuIGp1c3QgcmV0dXJuIHRoaXMgZGF0 YS4KKyAqIEBhbGlnbmVkX2J1ZmY6IGFsaWduZWQgdG8gOCBieXRlcyBkYXRhIGJ1ZmZlci4gQnVm ZmVyIGFkZHJlc3MgdXNlZCBpbgorICogICAgIFRSQiBzaGFsbCBiZSBhbGlnbmVkIHRvIDguCisg KiBAYWxpZ25lZF9kbWFfYWRkcjogZG1hIGFkZHJlc3Mgb2YgYWxpZ25lZF9idWZmCisgKiBAZGly OiBlbmRwb2ludCBkaXJlY3Rpb24KKyAqIEBudW06IGVuZHBvaW50IG51bWJlciAoMSAtIDE1KQor ICogQHR5cGU6IHNldCB0byBibUF0dHJpYnV0ZXMgJiBVU0JfRU5EUE9JTlRfWEZFUlRZUEVfTUFT SworICogQGZyZWVfdHJiczogbnVtYmVyIG9mIGZyZWUgVFJCcyBpbiB0cmFuc2ZlciByaW5nCisg KiBAcGNzOiBwcm9kdWNlciBjeWNsZSBzdGF0ZQorICogQGNjczogY29uc3VtZXIgY3ljbGUgc3Rh dGUKKyAqIEBlbnF1ZXVlOiBlbnF1ZXVlIGluZGV4IGluIHRyYW5zZmVyIHJpbmcKKyAqIEBkZXF1 ZXVlOiBkZXF1ZXVlIGluZGV4IGluIHRyYW5zZmVyIHJpbmcKKyAqLworc3RydWN0IGNkbnMzX2Vu ZHBvaW50IHsKKwlzdHJ1Y3QgdXNiX2VwCQllbmRwb2ludDsKKwlzdHJ1Y3QgbGlzdF9oZWFkCXJl cXVlc3RfbGlzdDsKKworCXN0cnVjdCBjZG5zM190cmIJKnRyYl9wb29sOworCWRtYV9hZGRyX3QJ CXRyYl9wb29sX2RtYTsKKworCXN0cnVjdCBjZG5zM19kZXZpY2UJKmNkbnMzX2RldjsKKwljaGFy CQkJbmFtZVsyMF07CisKKyNkZWZpbmUgRVBfRU5BQkxFRAkJQklUKDApCisjZGVmaW5lIEVQX1NU QUxMCQlCSVQoMSkKKyNkZWZpbmUgRVBfV0VER0UJCUJJVCgyKQorI2RlZmluZSBFUF9UUkFOU0ZF Ul9TVEFSVEVECUJJVCgzKQorI2RlZmluZSBFUF9VUERBVEVfRVBfVFJCQUREUglCSVQoNCkKKyNk ZWZpbmUgRVBfUEVORElOR19SRVFVRVNUCUJJVCg1KQorI2RlZmluZSBFUF9SSU5HX0ZVTEwJCUJJ VCg2KQorI2RlZmluZSBFUF9DTEFJTUVECQlCSVQoNSkKKwl1MzIJCQlmbGFnczsKKworCXN0cnVj dCBjZG5zM19yZXF1ZXN0CSpkZXNjbWlzX3JlcTsKKwl1MzIJCQlkZXNjbWlzX3BlbmRpbmc6MTsK Kwl1MzIJCQlkZXNjbWlzX2ZpbmlzaGVkOjE7CisKKwl2b2lkCQkJKmFsaWduZWRfYnVmZjsKKwlk bWFfYWRkcl90CQlhbGlnbmVkX2RtYV9hZGRyOworCXU4CQkJZGlyOworCXU4CQkJbnVtOworCXU4 CQkJdHlwZTsKKworCWludAkJCWZyZWVfdHJiczsKKwl1OAkJCXBjczsKKwl1OAkJCWNjczsKKwlp bnQJCQllbnF1ZXVlOworCWludAkJCWRlcXVldWU7Cit9OworCisvKioKKyAqIHN0cnVjdCBjZG5z M19yZXF1ZXN0IC0gZXh0ZW5kZWQgZGV2aWNlIHNpZGUgcmVwcmVzZW50YXRpb24gb2YgdXNiX3Jl cXVlc3QKKyAqICAgICAgICAgICAgICAgICAgICAgICAgb2JqZWN0IC4KKyAqIEByZXF1ZXN0OiBn ZW5lcmljIHVzYl9yZXF1ZXN0IG9iamVjdCBkZXNjcmliaW5nIHNpbmdsZSBJL08gcmVxdWVzdC4K KyAqIEBwcml2X2VwOiBleHRlbmRlZCByZXByZXNlbnRhdGlvbiBvZiB1c2JfZXAgb2JqZWN0Cisg KiBAdHJiOiB0aGUgZmlyc3QgVFJCIGFzc29jaWF0aW9uIHdpdGggdGhpcyByZXF1ZXN0CisgKiBA c3RhcnRfdHJiOiBudW1iZXIgb2YgdGhlIGZpcnN0IFRSQiBpbiB0cmFuc2ZlciByaW5nCisgKiBA ZW5kX3RyYjogbnVtYmVyIG9mIHRoZSBsYXN0IFRSQiBpbiB0cmFuc2ZlciByaW5nCisgKiBAZmxh Z3M6IGZsYWcgc3BlY2lmeWluZyBzcGVjaWFsIHVzYWdlIG9mIHJlcXVlc3QKKyAqLworc3RydWN0 IGNkbnMzX3JlcXVlc3QgeworCXN0cnVjdCB1c2JfcmVxdWVzdCByZXF1ZXN0OworCXN0cnVjdCBj ZG5zM19lbmRwb2ludCAqcHJpdl9lcDsKKwlzdHJ1Y3QgY2RuczNfdHJiICp0cmI7CisJaW50IHN0 YXJ0X3RyYjsKKwlpbnQgZW5kX3RyYjsKKyNkZWZpbmUgUkVRVUVTVF9QRU5ESU5HCQlCSVQoMCkK KyNkZWZpbmUgUkVRVUVTVF9JTlRFUk5BTAlCSVQoMSkKKyNkZWZpbmUgUkVRVUVTVF9aTFAJCUJJ VCgyKQorCXUzMiBmbGFnczsKK307CisKKyNkZWZpbmUgdG9fY2RuczNfcmVxdWVzdChyKSAoY29u dGFpbmVyX29mKHIsIHN0cnVjdCBjZG5zM19yZXF1ZXN0LCByZXF1ZXN0KSkKKworLyoqCisgKiBz dHJ1Y3QgY2RuczNfZGV2aWNlIC0gcmVwcmVzZW50IFVTQiBkZXZpY2UuCisgKiBAZGV2OiBwb2lu dGVyIHRvIGRldmljZSBzdHJ1Y3R1cmUgYXNzb2NpYXRlZCB3aGl0IHRoaXMgY29udHJvbGxlcgor ICogQHN5c2RldjogcG9pbnRlciB0byB0aGUgRE1BIGNhcGFibGUgZGV2aWNlCisgKiBAZ2FkZ2V0 OiBkZXZpY2Ugc2lkZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGVyaXBoZXJhbCBjb250cm9sbGVy CisgKiBAZ2FkZ2V0X2RyaXZlcjogcG9pbnRlciB0byB0aGUgZ2FkZ2V0IGRyaXZlcgorICogQGxv Y2s6IGZvciBzeW5jaHJvbml6aW5nCisgKiBAcmVnczogYmFzZSBhZGRyZXNzIGZvciBkZXZpY2Ug c2lkZSByZWdpc3RlcnMKKyAqIEBzZXR1cF9idWY6IHVzZWQgd2hpbGUgcHJvY2Vzc2luZyB1c2Ig Y29udHJvbCByZXF1ZXN0cworICogQHNldHVwX2RtYTogZG1hIGFkZHJlc3MgZm9yIHNldHVwX2J1 ZgorICogQGVwMF90cmI6IFRSQiB1c2VkIGZvciBjb250cm9sIHRyYW5zZmVyCisgKiBAZXAwX3Ry Yl9kbWE6IGRtYSBhZGRyZXNzIG9mIGVwMF90cmIKKyAqIEB6bHBfYnVmIC0gemxwIGJ1ZmZlcgor ICogQGVwMF9yZXF1ZXN0OiBkdW1teSByZXF1ZXN0IHVzZWQgd2hpbGUgaGFuZGxpbmcgVVNCIGNv bnRyb2wgcmVxdWVzdAorICogQGVwMF9kYXRhX2RpcjogZGlyZWN0aW9uIGZvciBjb250cm9sIHRy YW5zZmVyCisgKiBAZXBzOiBhcnJheSBvZiBwb2ludGVycyB0byBhbGwgZW5kcG9pbnRzIHdpdGgg ZXhjbHVzaW9uIGVwMAorICogQGVwX251bXM6IG51bWJlciBvZiBlbmRwb2ludHMgaW4gZXBzCisg KiBAaXNvY2hfZGVsYXk6IHZhbHVlIGZyb20gU2V0IElzb2NoIERlbGF5IHJlcXVlc3QuIE9ubHkg dmFsaWQgb24gU1MvU1NQLgorICogQHUxX2FsbG93ZWQ6IGFsbG93IGRldmljZSB0cmFuc2l0aW9u IHRvIHUxIHN0YXRlCisgKiBAdTJfYWxsb3dlZDogYWxsb3cgZGV2aWNlIHRyYW5zaXRpb24gdG8g dTIgc3RhdGUKKyAqIEBpc19zZWxmcG93ZXJlZDogZGV2aWNlIGlzIHNlbGYgcG93ZXJlZAorICog QHNldHVwX3BlbmRpbmc6IHNldHVwIHBhY2tldCBpcyBwcm9jZXNzaW5nIGJ5IGdhZGdldCBkcml2 ZXIKKyAqIEBod19jb25maWd1cmVkX2ZsYWc6IGhhcmR3YXJlIGVuZHBvaW50IGNvbmZpZ3VyYXRp b24gd2FzIHNldC4KKyAqIEB3YWtlX3VwX2ZsYWc6IGFsbG93IGRldmljZSB0byByZW1vdGUgdXAg dGhlIGhvc3QKKyAqIEBzdGF0dXNfY29tcGxldGlvbl9ub19jYWxsOiBpbmRpY2F0ZSB0aGF0IGRy aXZlciBpcyB3YWl0aW5nIGZvciBzdGF0dXMgcworICogICAgIHN0YWdlIGNvbXBsZXRpb24uIEl0 J3MgdXNlZCBpbiBkZWZlcnJlZCBTRVRfQ09ORklHVVJBVElPTiByZXF1ZXN0LgorICogQG9uY2hp cF9tZW1fYWxsb2NhdGVkX3NpemU6IGFjdHVhbCBzaXplIG9mIG9uLWNoaXAgbWVtb3J5IGFzc2ln bmVkCisgKiAgICAgdG8gZW5kcG9pbnRzCisgKiBAcGVuZGluZ19zdGF0dXNfd3E6IHdvcmtxdWV1 ZSBoYW5kbGluZyBzdGF0dXMgc3RhZ2UgZm9yIGRlZmVycmVkIHJlcXVlc3RzLgorICogQHBlbmRp bmdfc3RhdHVzX3JlcXVlc3Q6IHJlcXVlc3QgZm9yIHdoaWNoIHN0YXR1cyBzdGFnZSB3YXMgZGVm ZXJyZWQKKyAqLworc3RydWN0IGNkbnMzX2RldmljZSB7CisJc3RydWN0IGRldmljZQkJCSpkZXY7 CisJc3RydWN0IGRldmljZQkJCSpzeXNkZXY7CisKKwlzdHJ1Y3QgdXNiX2dhZGdldAkJZ2FkZ2V0 OworCXN0cnVjdCB1c2JfZ2FkZ2V0X2RyaXZlcgkqZ2FkZ2V0X2RyaXZlcjsKKworCS8qIGdlbmVy aWMgc3Bpbi1sb2NrIGZvciBkcml2ZXJzICovCisJc3BpbmxvY2tfdAkJCWxvY2s7CisKKwlzdHJ1 Y3QgY2RuczNfdXNiX3JlZ3MJCV9faW9tZW0gKnJlZ3M7CisKKwlzdHJ1Y3QgdXNiX2N0cmxyZXF1 ZXN0CQkqc2V0dXBfYnVmOworCWRtYV9hZGRyX3QJCQlzZXR1cF9kbWE7CisJc3RydWN0IGNkbnMz X3RyYgkJKmVwMF90cmI7CisJZG1hX2FkZHJfdAkJCWVwMF90cmJfZG1hOworCXZvaWQJCQkJKnps cF9idWY7CisJc3RydWN0IHVzYl9yZXF1ZXN0CQkqZXAwX3JlcXVlc3Q7CisJaW50CQkJCWVwMF9k YXRhX2RpcjsKKworCXN0cnVjdCBjZG5zM19lbmRwb2ludAkJKmVwc1tDRE5TM19FTkRQT0lOVFNf TUFYX0NPVU5UXTsKKwlpbnQJCQkJZXBfbnVtczsKKworCXUzMgkJCQlzZWxlY3RlZF9lcDsKKwl1 MTYJCQkJaXNvY2hfZGVsYXk7CisKKwl1bnNpZ25lZAkJCXUxX2FsbG93ZWQ6MTsKKwl1bnNpZ25l ZAkJCXUyX2FsbG93ZWQ6MTsKKwl1bnNpZ25lZAkJCWlzX3NlbGZwb3dlcmVkOjE7CisJdW5zaWdu ZWQJCQlzZXR1cF9wZW5kaW5nOjE7CisJaW50CQkJCWh3X2NvbmZpZ3VyZWRfZmxhZzoxOworCWlu dAkJCQl3YWtlX3VwX2ZsYWc6MTsKKwl1bnNpZ25lZAkJCXN0YXR1c19jb21wbGV0aW9uX25vX2Nh bGw6MTsKKworCXN0cnVjdCB3b3JrX3N0cnVjdAkJcGVuZGluZ19zdGF0dXNfd3E7CisJc3RydWN0 IHVzYl9yZXF1ZXN0CQkqcGVuZGluZ19zdGF0dXNfcmVxdWVzdDsKKworCS8qaW4gS0IgKi8KKwlp bnQJCQkJb25jaGlwX21lbV9hbGxvY2F0ZWRfc2l6ZTsKK307CisKK2ludCBjZG5zM19oYW5kc2hh a2Uodm9pZCBfX2lvbWVtICpwdHIsIHUzMiBtYXNrLCB1MzIgZG9uZSwgaW50IHVzZWMpOwordm9p ZCBjZG5zM19zZXRfcmVnaXN0ZXJfYml0KHZvaWQgX19pb21lbSAqcHRyLCB1MzIgbWFzayk7Citk bWFfYWRkcl90IGNkbnMzX3RyYl92aXJ0X3RvX2RtYShzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnBy aXZfZXAsCisJCQkJIHN0cnVjdCBjZG5zM190cmIgKnRyYik7CitlbnVtIHVzYl9kZXZpY2Vfc3Bl ZWQgY2RuczNfZ2V0X3NwZWVkKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2KTsKK3ZvaWQg Y2RuczNfcGVuZGluZ19zZXR1cF9zdGF0dXNfaGFuZGxlcihzdHJ1Y3Qgd29ya19zdHJ1Y3QgKndv cmspOwordm9pZCBjZG5zM19nYWRnZXRfdW5jb25maWcoc3RydWN0IGNkbnMzX2RldmljZSAqcHJp dl9kZXYpOwordm9pZCBjZG5zM19zZXRfaHdfY29uZmlndXJhdGlvbihzdHJ1Y3QgY2RuczNfZGV2 aWNlICpwcml2X2Rldik7Cit2b2lkIGNkbnMzX3NlbGVjdF9lcChzdHJ1Y3QgY2RuczNfZGV2aWNl ICpwcml2X2RldiwgdTMyIGVwKTsKK3ZvaWQgY2RuczNfYWxsb3dfZW5hYmxlX2wxKHN0cnVjdCBj ZG5zM19kZXZpY2UgKnByaXZfZGV2LCBpbnQgZW5hYmxlKTsKK3N0cnVjdCB1c2JfcmVxdWVzdCAq Y2RuczNfbmV4dF9yZXF1ZXN0KHN0cnVjdCBsaXN0X2hlYWQgKmxpc3QpOworaW50IGNkbnMzX2Vw X3J1bl90cmFuc2ZlcihzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXAsCisJCQkgIHN0cnVj dCB1c2JfcmVxdWVzdCAqcmVxdWVzdCk7Cit1OCBjZG5zM19lcF9hZGRyX3RvX2luZGV4KHU4IGVw X2FkZHIpOworaW50IGNkbnMzX2dhZGdldF9lcF9zZXRfd2VkZ2Uoc3RydWN0IHVzYl9lcCAqZXAp OworaW50IGNkbnMzX2dhZGdldF9lcF9zZXRfaGFsdChzdHJ1Y3QgdXNiX2VwICplcCwgaW50IHZh bHVlKTsKK3N0cnVjdCB1c2JfcmVxdWVzdCAqY2RuczNfZ2FkZ2V0X2VwX2FsbG9jX3JlcXVlc3Qo c3RydWN0IHVzYl9lcCAqZXAsCisJCQkJCQkgIGdmcF90IGdmcF9mbGFncyk7Cit2b2lkIGNkbnMz X2dhZGdldF9lcF9mcmVlX3JlcXVlc3Qoc3RydWN0IHVzYl9lcCAqZXAsCisJCQkJICBzdHJ1Y3Qg dXNiX3JlcXVlc3QgKnJlcXVlc3QpOworaW50IGNkbnMzX2dhZGdldF9lcF9kZXF1ZXVlKHN0cnVj dCB1c2JfZXAgKmVwLCBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcXVlc3QpOwordm9pZCBjZG5zM19n YWRnZXRfZ2l2ZWJhY2soc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLAorCQkJICAgc3Ry dWN0IGNkbnMzX3JlcXVlc3QgKnByaXZfcmVxLAorCQkJICAgaW50IHN0YXR1cyk7CisKK2ludCBj ZG5zM19pbml0X2VwMChzdHJ1Y3QgY2RuczNfZGV2aWNlICpwcml2X2Rldik7Cit2b2lkIGNkbnMz X2VwMF9jb25maWcoc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9kZXYpOwordm9pZCBjZG5zM19l cF9jb25maWcoc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKTsKK3ZvaWQgY2RuczNfY2hl Y2tfZXAwX2ludGVycnVwdF9wcm9jZWVkKHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LCBp bnQgZGlyKTsKKworI2VuZGlmIC8qIF9fTElOVVhfQ0ROUzNfR0FER0VUICovCmRpZmYgLS1naXQg YS9kcml2ZXJzL3VzYi9jZG5zMy9ob3N0LWV4cG9ydC5oIGIvZHJpdmVycy91c2IvY2RuczMvaG9z dC1leHBvcnQuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLmI0OThh MTcwYjdlOAotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL2hvc3QtZXhwb3J0 LmgKQEAgLTAsMCArMSwyOCBAQAorLyogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAg Ki8KKy8qCisgKiBDYWRlbmNlIFVTQlNTIERSRCBEcml2ZXIgLSBIb3N0IEV4cG9ydCBBUElzCisg KgorICogQ29weXJpZ2h0IChDKSAyMDE3LTIwMTggTlhQCisgKgorICogQXV0aG9yczogUGV0ZXIg Q2hlbiA8cGV0ZXIuY2hlbkBueHAuY29tPgorICovCisjaWZuZGVmIF9fTElOVVhfQ0ROUzNfSE9T VF9FWFBPUlQKKyNkZWZpbmUgX19MSU5VWF9DRE5TM19IT1NUX0VYUE9SVAorCisjaWZkZWYgQ09O RklHX1VTQl9DRE5TM19IT1NUCisKK2ludCBjZG5zM19ob3N0X2luaXQoc3RydWN0IGNkbnMzICpj ZG5zKTsKK3ZvaWQgY2RuczNfaG9zdF9leGl0KHN0cnVjdCBjZG5zMyAqY2Rucyk7CisKKyNlbHNl CisKK3N0YXRpYyBpbmxpbmUgaW50IGNkbnMzX2hvc3RfaW5pdChzdHJ1Y3QgY2RuczMgKmNkbnMp Cit7CisJcmV0dXJuIC1FTlhJTzsKK30KKworc3RhdGljIGlubGluZSB2b2lkIGNkbnMzX2hvc3Rf ZXhpdChzdHJ1Y3QgY2RuczMgKmNkbnMpIHsgfQorCisjZW5kaWYgLyogQ09ORklHX1VTQl9DRE5T M19IT1NUICovCisKKyNlbmRpZiAvKiBfX0xJTlVYX0NETlMzX0hPU1RfRVhQT1JUICovCmRpZmYg LS1naXQgYS9kcml2ZXJzL3VzYi9jZG5zMy9ob3N0LmMgYi9kcml2ZXJzL3VzYi9jZG5zMy9ob3N0 LmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi5lMTYxNzVlMDMyOGEK LS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL3VzYi9jZG5zMy9ob3N0LmMKQEAgLTAsMCArMSw3 NCBAQAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKy8qCisgKiBDYWRlbmNl IFVTQlNTIERSRCBEcml2ZXIgLSBob3N0IHNpZGUKKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTgg Q2FkZW5jZSBEZXNpZ24gU3lzdGVtcy4KKyAqIENvcHlyaWdodCAoQykgMjAxNy0yMDE4IE5YUAor ICoKKyAqIEF1dGhvcnM6IFBldGVyIENoZW4gPHBldGVyLmNoZW5AbnhwLmNvbT4KKyAqCSAgICBQ YXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICovCisKKyNpbmNsdWRlIDxsaW51 eC9wbGF0Zm9ybV9kZXZpY2UuaD4KKyNpbmNsdWRlICJjb3JlLmgiCisKK3N0YXRpYyBpbnQgX19j ZG5zM19ob3N0X2luaXQoc3RydWN0IGNkbnMzICpjZG5zKQoreworCXN0cnVjdCBwbGF0Zm9ybV9k ZXZpY2UgKnhoY2k7CisJaW50IHJldDsKKworCXhoY2kgPSBwbGF0Zm9ybV9kZXZpY2VfYWxsb2Mo InhoY2ktaGNkIiwgUExBVEZPUk1fREVWSURfQVVUTyk7CisJaWYgKCF4aGNpKSB7CisJCWRldl9l cnIoY2Rucy0+ZGV2LCAiY291bGRuJ3QgYWxsb2NhdGUgeEhDSSBkZXZpY2VcbiIpOworCQlyZXR1 cm4gLUVOT01FTTsKKwl9CisKKwl4aGNpLT5kZXYucGFyZW50ID0gY2Rucy0+ZGV2OworCWNkbnMt Pmhvc3RfZGV2ID0geGhjaTsKKworCXJldCA9IHBsYXRmb3JtX2RldmljZV9hZGRfcmVzb3VyY2Vz KHhoY2ksIGNkbnMtPnhoY2lfcmVzLAorCQkJCQkgICAgQ0ROUzNfWEhDSV9SRVNPVVJDRVNfTlVN KTsKKwlpZiAocmV0KSB7CisJCWRldl9lcnIoY2Rucy0+ZGV2LCAiY291bGRuJ3QgYWRkIHJlc291 cmNlcyB0byB4SENJIGRldmljZVxuIik7CisJCWdvdG8gZXJyMTsKKwl9CisKKwlyZXQgPSBwbGF0 Zm9ybV9kZXZpY2VfYWRkKHhoY2kpOworCWlmIChyZXQpIHsKKwkJZGV2X2VycihjZG5zLT5kZXYs ICJmYWlsZWQgdG8gcmVnaXN0ZXIgeEhDSSBkZXZpY2VcbiIpOworCQlnb3RvIGVycjE7CisJfQor CisJcmV0dXJuIDA7CitlcnIxOgorCXBsYXRmb3JtX2RldmljZV9wdXQoeGhjaSk7CisJcmV0dXJu IHJldDsKK30KKworc3RhdGljIHZvaWQgY2RuczNfaG9zdF9leGl0KHN0cnVjdCBjZG5zMyAqY2Ru cykKK3sKKwlwbGF0Zm9ybV9kZXZpY2VfdW5yZWdpc3RlcihjZG5zLT5ob3N0X2Rldik7CisJY2Ru cy0+aG9zdF9kZXYgPSBOVUxMOworfQorCitpbnQgY2RuczNfaG9zdF9pbml0KHN0cnVjdCBjZG5z MyAqY2RucykKK3sKKwlzdHJ1Y3QgY2RuczNfcm9sZV9kcml2ZXIgKnJkcnY7CisKKwlyZHJ2ID0g ZGV2bV9remFsbG9jKGNkbnMtPmRldiwgc2l6ZW9mKCpyZHJ2KSwgR0ZQX0tFUk5FTCk7CisJaWYg KCFyZHJ2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXJkcnYtPnN0YXJ0CT0gX19jZG5zM19ob3N0 X2luaXQ7CisJcmRydi0+c3RvcAk9IGNkbnMzX2hvc3RfZXhpdDsKKwlyZHJ2LT5zdGF0ZQk9IENE TlMzX1JPTEVfU1RBVEVfSU5BQ1RJVkU7CisjaWYgQ09ORklHX1BNCisJcmRydi0+c3VzcGVuZAk9 IE5VTEw7CisJcmRydi0+cmVzdW1lCT0gTlVMTDsKKyNlbmRpZiAvKiBDT05GSUdfUE0gKi8KKwly ZHJ2LT5uYW1lCT0gImhvc3QiOworCisJY2Rucy0+cm9sZXNbQ0ROUzNfUk9MRV9IT1NUXSA9IHJk cnY7CisKKwlyZXR1cm4gMDsKK30KZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNiL2NkbnMzL3RyYWNl LmMgYi9kcml2ZXJzL3VzYi9jZG5zMy90cmFjZS5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4 IDAwMDAwMDAwMDAwMC4uNTg3YWUwOGUwMTlkCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy91 c2IvY2RuczMvdHJhY2UuYwpAQCAtMCwwICsxLDExIEBACisvLyBTUERYLUxpY2Vuc2UtSWRlbnRp ZmllcjogR1BMLTIuMAorLyoKKyAqIFVTQlNTIGRldmljZSBjb250cm9sbGVyIGRyaXZlciBUcmFj ZSBTdXBwb3J0CisgKgorICogQ29weXJpZ2h0IChDKSAyMDE4IENhZGVuY2UuCisgKgorICogQXV0 aG9yOiBQYXdlbCBMYXN6Y3phayA8cGF3ZWxsQGNhZGVuY2UuY29tPgorICovCisKKyNkZWZpbmUg Q1JFQVRFX1RSQUNFX1BPSU5UUworI2luY2x1ZGUgInRyYWNlLmgiCmRpZmYgLS1naXQgYS9kcml2 ZXJzL3VzYi9jZG5zMy90cmFjZS5oIGIvZHJpdmVycy91c2IvY2RuczMvdHJhY2UuaApuZXcgZmls ZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwMDAwMDAuLmE1YzhiMmE3NTZiNAotLS0gL2Rldi9u dWxsCisrKyBiL2RyaXZlcnMvdXNiL2NkbnMzL3RyYWNlLmgKQEAgLTAsMCArMSwzNDMgQEAKKy8q IFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wICovCisvKgorICogVVNCU1MgZGV2aWNl IGNvbnRyb2xsZXIgZHJpdmVyLgorICogVHJhY2Ugc3VwcG9ydCBoZWFkZXIgZmlsZS4KKyAqCisg KiBDb3B5cmlnaHQgKEMpIDIwMTggQ2FkZW5jZS4KKyAqCisgKiBBdXRob3I6IFBhd2VsIExhc3pj emFrIDxwYXdlbGxAY2FkZW5jZS5jb20+CisgKi8KKworI3VuZGVmIFRSQUNFX1NZU1RFTQorI2Rl ZmluZSBUUkFDRV9TWVNURU0gY2RuczMKKworI2lmICFkZWZpbmVkKF9fTElOVVhfQ0ROUzNfVFJB Q0UpIHx8IGRlZmluZWQoVFJBQ0VfSEVBREVSX01VTFRJX1JFQUQpCisjZGVmaW5lIF9fTElOVVhf Q0ROUzNfVFJBQ0UKKworI2luY2x1ZGUgPGxpbnV4L3R5cGVzLmg+CisjaW5jbHVkZSA8bGludXgv dHJhY2Vwb2ludC5oPgorI2luY2x1ZGUgPGFzbS9ieXRlb3JkZXIuaD4KKyNpbmNsdWRlICJjb3Jl LmgiCisjaW5jbHVkZSAiZ2FkZ2V0LmgiCisjaW5jbHVkZSAiZGVidWcuaCIKKworI2RlZmluZSBD RE5TM19NU0dfTUFYCTUwMAorCitERUNMQVJFX0VWRU5UX0NMQVNTKGNkbnMzX2xvZ19kb29yYmVs bCwKKwlUUF9QUk9UTyhjb25zdCBjaGFyICplcF9uYW1lKSwKKwlUUF9BUkdTKGVwX25hbWUpLAor CVRQX1NUUlVDVF9fZW50cnkoCisJCV9fZmllbGQoY29uc3QgY2hhciAqLCBlcF9uYW1lKQorCSks CisJVFBfZmFzdF9hc3NpZ24oCisJCV9fZW50cnktPmVwX25hbWUgPSBlcF9uYW1lOworCSksCisJ VFBfcHJpbnRrKCIvL0RpbmcgRG9uZyAlcyIsIF9fZW50cnktPmVwX25hbWUpCispOworCitERUZJ TkVfRVZFTlQoY2RuczNfbG9nX2Rvb3JiZWxsLCBjZG5zM19kb29yYmVsbF9lcDAsCisJVFBfUFJP VE8oY29uc3QgY2hhciAqZXBfbmFtZSksCisJVFBfQVJHUyhlcF9uYW1lKQorKTsKKworREVGSU5F X0VWRU5UKGNkbnMzX2xvZ19kb29yYmVsbCwgY2RuczNfZG9vcmJlbGxfZXB4LAorCVRQX1BST1RP KGNvbnN0IGNoYXIgKmVwX25hbWUpLAorCVRQX0FSR1MoZXBfbmFtZSkKKyk7CisKK0RFQ0xBUkVf RVZFTlRfQ0xBU1MoY2RuczNfbG9nX3VzYl9pcnEsCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX2Rl dmljZSAqcHJpdl9kZXYsIHUzMiB1c2JfaXN0cyksCisJVFBfQVJHUyhwcml2X2RldiwgdXNiX2lz dHMpLAorCVRQX1NUUlVDVF9fZW50cnkoCisJCV9fZmllbGQoc3RydWN0IGNkbnMzX2RldmljZSAq LCBwcml2X2RldikKKwkJX19maWVsZCh1MzIsIHVzYl9pc3RzKQorCSksCisJVFBfZmFzdF9hc3Np Z24oCisJCV9fZW50cnktPnByaXZfZGV2ID0gcHJpdl9kZXY7CisJCV9fZW50cnktPnVzYl9pc3Rz ID0gdXNiX2lzdHM7CisJKSwKKwlUUF9wcmludGsoIiVzIiwgY2RuczNfZGVjb2RlX3VzYl9pcnEo X19lbnRyeS0+cHJpdl9kZXYsCisJCQkJCSAgICAgX19lbnRyeS0+dXNiX2lzdHMpKQorKTsKKwor REVGSU5FX0VWRU5UKGNkbnMzX2xvZ191c2JfaXJxLCBjZG5zM191c2JfaXJxLAorCVRQX1BST1RP KHN0cnVjdCBjZG5zM19kZXZpY2UgKnByaXZfZGV2LCB1MzIgdXNiX2lzdHMpLAorCVRQX0FSR1Mo cHJpdl9kZXYsIHVzYl9pc3RzKQorKTsKKworREVDTEFSRV9FVkVOVF9DTEFTUyhjZG5zM19sb2df ZXB4X2lycSwKKwlUUF9QUk9UTyhzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXApLAorCVRQ X0FSR1MocHJpdl9lcCksCisJVFBfU1RSVUNUX19lbnRyeSgKKwkJX19maWVsZChzdHJ1Y3QgY2Ru czNfZW5kcG9pbnQgKiwgcHJpdl9lcCkKKwkpLAorCVRQX2Zhc3RfYXNzaWduKAorCQlfX2VudHJ5 LT5wcml2X2VwID0gcHJpdl9lcDsKKwkpLAorCVRQX3ByaW50aygiJXMiLCBjZG5zM19kZWNvZGVf ZXB4X2lycShfX2VudHJ5LT5wcml2X2VwKSkKKyk7CisKK0RFRklORV9FVkVOVChjZG5zM19sb2df ZXB4X2lycSwgY2RuczNfZXB4X2lycSwKKwlUUF9QUk9UTyhzdHJ1Y3QgY2RuczNfZW5kcG9pbnQg KnByaXZfZXApLAorCVRQX0FSR1MocHJpdl9lcCkKKyk7CisKK0RFQ0xBUkVfRVZFTlRfQ0xBU1Mo Y2RuczNfbG9nX2VwMF9pcnEsCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX2RldmljZSAqcHJpdl9k ZXYpLAorCVRQX0FSR1MocHJpdl9kZXYpLAorCVRQX1NUUlVDVF9fZW50cnkoCisJCV9fZmllbGQo c3RydWN0IGNkbnMzX2RldmljZSAqLCBwcml2X2RldikKKwkpLAorCVRQX2Zhc3RfYXNzaWduKAor CQlfX2VudHJ5LT5wcml2X2RldiA9IHByaXZfZGV2OworCSksCisJVFBfcHJpbnRrKCIlcyIsIGNk bnMzX2RlY29kZV9lcDBfaXJxKF9fZW50cnktPnByaXZfZGV2KSkKKyk7CisKK0RFRklORV9FVkVO VChjZG5zM19sb2dfZXAwX2lycSwgY2RuczNfZXAwX2lycSwKKwlUUF9QUk9UTyhzdHJ1Y3QgY2Ru czNfZGV2aWNlICpwcml2X2RldiksCisJVFBfQVJHUyhwcml2X2RldikKKyk7CisKK0RFQ0xBUkVf RVZFTlRfQ0xBU1MoY2RuczNfbG9nX2N0cmwsCisJVFBfUFJPVE8oc3RydWN0IHVzYl9jdHJscmVx dWVzdCAqY3RybCksCisJVFBfQVJHUyhjdHJsKSwKKwlUUF9TVFJVQ1RfX2VudHJ5KAorCQlfX2Zp ZWxkKHU4LCBiUmVxdWVzdFR5cGUpCisJCV9fZmllbGQodTgsIGJSZXF1ZXN0KQorCQlfX2ZpZWxk KHUxNiwgd1ZhbHVlKQorCQlfX2ZpZWxkKHUxNiwgd0luZGV4KQorCQlfX2ZpZWxkKHUxNiwgd0xl bmd0aCkKKwkJX19keW5hbWljX2FycmF5KGNoYXIsIHN0ciwgQ0ROUzNfTVNHX01BWCkKKwkpLAor CVRQX2Zhc3RfYXNzaWduKAorCQlfX2VudHJ5LT5iUmVxdWVzdFR5cGUgPSBjdHJsLT5iUmVxdWVz dFR5cGU7CisJCV9fZW50cnktPmJSZXF1ZXN0ID0gY3RybC0+YlJlcXVlc3Q7CisJCV9fZW50cnkt PndWYWx1ZSA9IGxlMTZfdG9fY3B1KGN0cmwtPndWYWx1ZSk7CisJCV9fZW50cnktPndJbmRleCA9 IGxlMTZfdG9fY3B1KGN0cmwtPndJbmRleCk7CisJCV9fZW50cnktPndMZW5ndGggPSBsZTE2X3Rv X2NwdShjdHJsLT53TGVuZ3RoKTsKKwkpLAorCVRQX3ByaW50aygiJXMiLCBjZG5zM19kZWNvZGVf Y3RybChfX2dldF9zdHIoc3RyKSwgX19lbnRyeS0+YlJlcXVlc3RUeXBlLAorCQkJCQlfX2VudHJ5 LT5iUmVxdWVzdCwgX19lbnRyeS0+d1ZhbHVlLAorCQkJCQlfX2VudHJ5LT53SW5kZXgsIF9fZW50 cnktPndMZW5ndGgpCisJKQorKTsKKworREVGSU5FX0VWRU5UKGNkbnMzX2xvZ19jdHJsLCBjZG5z M19jdHJsX3JlcSwKKwlUUF9QUk9UTyhzdHJ1Y3QgdXNiX2N0cmxyZXF1ZXN0ICpjdHJsKSwKKwlU UF9BUkdTKGN0cmwpCispOworCitERUNMQVJFX0VWRU5UX0NMQVNTKGNkbnMzX2xvZ19yZXF1ZXN0 LAorCVRQX1BST1RPKHN0cnVjdCBjZG5zM19yZXF1ZXN0ICpyZXEpLAorCVRQX0FSR1MocmVxKSwK KwlUUF9TVFJVQ1RfX2VudHJ5KAorCQlfX3N0cmluZyhuYW1lLCByZXEtPnByaXZfZXAtPm5hbWUp CisJCV9fZmllbGQoc3RydWN0IGNkbnMzX3JlcXVlc3QgKiwgcmVxKQorCQlfX2ZpZWxkKHVuc2ln bmVkIGludCwgYWN0dWFsKQorCQlfX2ZpZWxkKHVuc2lnbmVkIGludCwgbGVuZ3RoKQorCQlfX2Zp ZWxkKGludCwgc3RhdHVzKQorCQlfX2ZpZWxkKGludCwgemVybykKKwkJX19maWVsZChpbnQsIHNo b3J0X25vdF9vaykKKwkJX19maWVsZChpbnQsIG5vX2ludGVycnVwdCkKKwkJX19maWVsZChpbnQs IHN0YXJ0X3RyYikKKwkJX19maWVsZChpbnQsIGVuZF90cmIpCisJCV9fZmllbGQoc3RydWN0IGNk bnMzX3RyYiAqLCBzdGFydF90cmJfYWRkcikKKwkJX19maWVsZChpbnQsIGZsYWdzKQorCSksCisJ VFBfZmFzdF9hc3NpZ24oCisJCV9fYXNzaWduX3N0cihuYW1lLCByZXEtPnByaXZfZXAtPm5hbWUp OworCQlfX2VudHJ5LT5yZXEgPSByZXE7CisJCV9fZW50cnktPmFjdHVhbCA9IHJlcS0+cmVxdWVz dC5hY3R1YWw7CisJCV9fZW50cnktPmxlbmd0aCA9IHJlcS0+cmVxdWVzdC5sZW5ndGg7CisJCV9f ZW50cnktPnN0YXR1cyA9IHJlcS0+cmVxdWVzdC5zdGF0dXM7CisJCV9fZW50cnktPnplcm8gPSBy ZXEtPnJlcXVlc3QuemVybzsKKwkJX19lbnRyeS0+c2hvcnRfbm90X29rID0gcmVxLT5yZXF1ZXN0 LnNob3J0X25vdF9vazsKKwkJX19lbnRyeS0+bm9faW50ZXJydXB0ID0gcmVxLT5yZXF1ZXN0Lm5v X2ludGVycnVwdDsKKwkJX19lbnRyeS0+c3RhcnRfdHJiID0gcmVxLT5zdGFydF90cmI7CisJCV9f ZW50cnktPmVuZF90cmIgPSByZXEtPmVuZF90cmI7CisJCV9fZW50cnktPnN0YXJ0X3RyYl9hZGRy ID0gcmVxLT50cmI7CisJCV9fZW50cnktPmZsYWdzID0gcmVxLT5mbGFnczsKKwkpLAorCVRQX3By aW50aygiJXM6IHJlcTogJXAsIGxlbmd0aDogJXUvJXUgJXMlcyVzLCBzdGF0dXM6ICVkLCIKKwkJ ICAiIHRyYjogW3N0YXJ0OiVkLCBlbmQ6JWQ6IHZpcnQgYWRkciAlcGFdLCBmbGFnczoleCAiLAor CQlfX2dldF9zdHIobmFtZSksIF9fZW50cnktPnJlcSwgX19lbnRyeS0+YWN0dWFsLCBfX2VudHJ5 LT5sZW5ndGgsCisJCV9fZW50cnktPnplcm8gPyAiemVybyB8ICIgOiAiIiwKKwkJX19lbnRyeS0+ c2hvcnRfbm90X29rID8gInNob3J0IHwgIiA6ICIiLAorCQlfX2VudHJ5LT5ub19pbnRlcnJ1cHQg PyAibm8gaW50IiA6ICIiLAorCQlfX2VudHJ5LT5zdGF0dXMsCisJCV9fZW50cnktPnN0YXJ0X3Ry YiwKKwkJX19lbnRyeS0+ZW5kX3RyYiwKKwkJX19lbnRyeS0+c3RhcnRfdHJiX2FkZHIsCisJCV9f ZW50cnktPmZsYWdzCisJKQorKTsKKworREVGSU5FX0VWRU5UKGNkbnMzX2xvZ19yZXF1ZXN0LCBj ZG5zM19hbGxvY19yZXF1ZXN0LAorCVRQX1BST1RPKHN0cnVjdCBjZG5zM19yZXF1ZXN0ICpyZXEp LAorCVRQX0FSR1MocmVxKQorKTsKKworREVGSU5FX0VWRU5UKGNkbnMzX2xvZ19yZXF1ZXN0LCBj ZG5zM19mcmVlX3JlcXVlc3QsCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX3JlcXVlc3QgKnJlcSks CisJVFBfQVJHUyhyZXEpCispOworCitERUZJTkVfRVZFTlQoY2RuczNfbG9nX3JlcXVlc3QsIGNk bnMzX2VwX3F1ZXVlLAorCVRQX1BST1RPKHN0cnVjdCBjZG5zM19yZXF1ZXN0ICpyZXEpLAorCVRQ X0FSR1MocmVxKQorKTsKKworREVGSU5FX0VWRU5UKGNkbnMzX2xvZ19yZXF1ZXN0LCBjZG5zM19l cF9kZXF1ZXVlLAorCVRQX1BST1RPKHN0cnVjdCBjZG5zM19yZXF1ZXN0ICpyZXEpLAorCVRQX0FS R1MocmVxKQorKTsKKworREVGSU5FX0VWRU5UKGNkbnMzX2xvZ19yZXF1ZXN0LCBjZG5zM19nYWRn ZXRfZ2l2ZWJhY2ssCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX3JlcXVlc3QgKnJlcSksCisJVFBf QVJHUyhyZXEpCispOworCitERUNMQVJFX0VWRU5UX0NMQVNTKGNkbnMzX2xvZ190cmIsCisJVFBf UFJPVE8oc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLCBzdHJ1Y3QgY2RuczNfdHJiICp0 cmIpLAorCVRQX0FSR1MocHJpdl9lcCwgdHJiKSwKKwlUUF9TVFJVQ1RfX2VudHJ5KAorCQlfX3N0 cmluZyhuYW1lLCBwcml2X2VwLT5uYW1lKQorCQlfX2ZpZWxkKHN0cnVjdCBjZG5zM190cmIgKiwg dHJiKQorCQlfX2ZpZWxkKHUzMiwgYnVmZmVyKQorCQlfX2ZpZWxkKHUzMiwgbGVuZ3RoKQorCQlf X2ZpZWxkKHUzMiwgY29udHJvbCkKKwkJX19maWVsZCh1MzIsIHR5cGUpCisJKSwKKwlUUF9mYXN0 X2Fzc2lnbigKKwkJX19hc3NpZ25fc3RyKG5hbWUsIHByaXZfZXAtPm5hbWUpOworCQlfX2VudHJ5 LT50cmIgPSB0cmI7CisJCV9fZW50cnktPmJ1ZmZlciA9IHRyYi0+YnVmZmVyOworCQlfX2VudHJ5 LT5sZW5ndGggPSB0cmItPmxlbmd0aDsKKwkJX19lbnRyeS0+Y29udHJvbCA9IHRyYi0+Y29udHJv bDsKKwkJX19lbnRyeS0+dHlwZSA9IHVzYl9lbmRwb2ludF90eXBlKHByaXZfZXAtPmVuZHBvaW50 LmRlc2MpOworCSksCisJVFBfcHJpbnRrKCIlczogdHJiIDB4JXBhLCBkbWEgYnVmOiAweCUwOHgs IHNpemU6ICVsZCwgY3RybDogMHglMDh4ICglcyVzJXMlcyVzJXMlcykiLAorCQlfX2dldF9zdHIo bmFtZSksIF9fZW50cnktPnRyYiwgX19lbnRyeS0+YnVmZmVyLAorCQlUUkJfTEVOKF9fZW50cnkt Pmxlbmd0aCksIF9fZW50cnktPmNvbnRyb2wsCisJCV9fZW50cnktPmNvbnRyb2wgJiBUUkJfQ1lD TEUgPyAiQz0xLCAiIDogIkM9MCwgIiwKKwkJX19lbnRyeS0+Y29udHJvbCAmIFRSQl9UT0dHTEUg PyAiVD0xLCAiIDogIlQ9MCwgIiwKKwkJX19lbnRyeS0+Y29udHJvbCAmIFRSQl9JU1AgPyAiSVNQ LCAiIDogIiIsCisJCV9fZW50cnktPmNvbnRyb2wgJiBUUkJfRklGT19NT0RFID8gIkZJRk8sICIg OiAiIiwKKwkJX19lbnRyeS0+Y29udHJvbCAmIFRSQl9DSEFJTiA/ICJDSEFJTiwgIiA6ICIiLAor CQlfX2VudHJ5LT5jb250cm9sICYgVFJCX0lPQyA/ICJJT0MsICIgOiAiIiwKKwkJICBUUkJfRklF TERfVE9fVFlQRShfX2VudHJ5LT5jb250cm9sKSA9PSBUUkJfTk9STUFMID8gIk5vcm1hbCIgOiAi TElOSyIKKwkpCispOworCitERUZJTkVfRVZFTlQoY2RuczNfbG9nX3RyYiwgY2RuczNfcHJlcGFy ZV90cmIsCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwLCBzdHJ1Y3Qg Y2RuczNfdHJiICp0cmIpLAorCVRQX0FSR1MocHJpdl9lcCwgdHJiKQorKTsKKworREVGSU5FX0VW RU5UKGNkbnMzX2xvZ190cmIsIGNkbnMzX2NvbXBsZXRlX3RyYiwKKwlUUF9QUk9UTyhzdHJ1Y3Qg Y2RuczNfZW5kcG9pbnQgKnByaXZfZXAsIHN0cnVjdCBjZG5zM190cmIgKnRyYiksCisJVFBfQVJH Uyhwcml2X2VwLCB0cmIpCispOworCitERUNMQVJFX0VWRU5UX0NMQVNTKGNkbnMzX2xvZ19yaW5n LAorCVRQX1BST1RPKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCksCisJVFBfQVJHUyhw cml2X2VwKSwKKwlUUF9TVFJVQ1RfX2VudHJ5KAorCQlfX2ZpZWxkKHN0cnVjdCBjZG5zM19lbmRw b2ludCAqLCBwcml2X2VwKQorCQlfX2ZpZWxkKGludCwgZnJlZV90cmJzKQorCQlfX2ZpZWxkKHU4 LCBwY3MpCisJCV9fZmllbGQodTgsIGNjcykKKwkJX19maWVsZChpbnQsIGVucXVldWUpCisJCV9f ZmllbGQoaW50LCBkZXF1ZXVlKQorCQlfX2R5bmFtaWNfYXJyYXkodTMyLCByaW5nLCBUUkJfUklO R19TSVpFKQorCQlfX2R5bmFtaWNfYXJyYXkoY2hhciwgYnVmZmVyLAorCQkJCShUUkJTX1BFUl9T RUdNRU5UICogNjUpICsgQ0ROUzNfTVNHX01BWCkKKwkpLAorCVRQX2Zhc3RfYXNzaWduKAorCQlf X2VudHJ5LT5wcml2X2VwID0gcHJpdl9lcDsKKwkJX19lbnRyeS0+ZnJlZV90cmJzID0gcHJpdl9l cC0+ZnJlZV90cmJzOworCQlfX2VudHJ5LT5wY3MgPSBwcml2X2VwLT5wY3M7CisJCV9fZW50cnkt PmNjcyA9IHByaXZfZXAtPmNjczsKKwkJX19lbnRyeS0+ZW5xdWV1ZSA9IHByaXZfZXAtPmVucXVl dWU7CisJCV9fZW50cnktPmRlcXVldWUgPSBwcml2X2VwLT5kZXF1ZXVlOworCQltZW1jcHkoX19n ZXRfZHluYW1pY19hcnJheShyaW5nKSwgcHJpdl9lcC0+dHJiX3Bvb2wsCisJCSAgICAgICBUUkJf UklOR19TSVpFKTsKKwkpLAorCisJVFBfcHJpbnRrKCIlcyIsCisJCSAgY2RuczNfZGJnX3Jpbmco X19lbnRyeS0+cHJpdl9lcCwgX19lbnRyeS0+ZnJlZV90cmJzLAorCQkJCSBfX2VudHJ5LT5wY3Ms IF9fZW50cnktPmNjcywKKwkJCQkgX19lbnRyeS0+ZW5xdWV1ZSwgX19lbnRyeS0+ZGVxdWV1ZSwK KwkJCQkgKHN0cnVjdCBjZG5zM190cmIgKilfX2dldF9zdHIocmluZyksCisJCQkJIF9fZ2V0X3N0 cihidWZmZXIpKSkKKyk7CisKK0RFRklORV9FVkVOVChjZG5zM19sb2dfcmluZywgY2RuczNfcmlu ZywKKwlUUF9QUk9UTyhzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnByaXZfZXApLAorCVRQX0FSR1Mo cHJpdl9lcCkKKyk7CisKK0RFQ0xBUkVfRVZFTlRfQ0xBU1MoY2RuczNfbG9nX2VwLAorCVRQX1BS T1RPKHN0cnVjdCBjZG5zM19lbmRwb2ludCAqcHJpdl9lcCksCisJVFBfQVJHUyhwcml2X2VwKSwK KwlUUF9TVFJVQ1RfX2VudHJ5KAorCQlfX3N0cmluZyhuYW1lLCBwcml2X2VwLT5uYW1lKQorCQlf X2ZpZWxkKHVuc2lnbmVkIGludCwgbWF4cGFja2V0KQorCQlfX2ZpZWxkKHVuc2lnbmVkIGludCwg bWF4cGFja2V0X2xpbWl0KQorCQlfX2ZpZWxkKHVuc2lnbmVkIGludCwgbWF4X3N0cmVhbXMpCisJ CV9fZmllbGQodW5zaWduZWQgaW50LCBtYXhidXJzdCkKKwkJX19maWVsZCh1bnNpZ25lZCBpbnQs IGZsYWdzKQorCQlfX2ZpZWxkKHVuc2lnbmVkIGludCwgZGlyKQorCQlfX2ZpZWxkKHU4LCBlbnF1 ZXVlKQorCQlfX2ZpZWxkKHU4LCBkZXF1ZXVlKQorCSksCisJVFBfZmFzdF9hc3NpZ24oCisJCV9f YXNzaWduX3N0cihuYW1lLCBwcml2X2VwLT5uYW1lKTsKKwkJX19lbnRyeS0+bWF4cGFja2V0ID0g cHJpdl9lcC0+ZW5kcG9pbnQubWF4cGFja2V0OworCQlfX2VudHJ5LT5tYXhwYWNrZXRfbGltaXQg PSBwcml2X2VwLT5lbmRwb2ludC5tYXhwYWNrZXRfbGltaXQ7CisJCV9fZW50cnktPm1heF9zdHJl YW1zID0gcHJpdl9lcC0+ZW5kcG9pbnQubWF4X3N0cmVhbXM7CisJCV9fZW50cnktPm1heGJ1cnN0 ID0gcHJpdl9lcC0+ZW5kcG9pbnQubWF4YnVyc3Q7CisJCV9fZW50cnktPmZsYWdzID0gcHJpdl9l cC0+ZmxhZ3M7CisJCV9fZW50cnktPmRpciA9IHByaXZfZXAtPmRpcjsKKwkJX19lbnRyeS0+ZW5x dWV1ZSA9IHByaXZfZXAtPmVucXVldWU7CisJCV9fZW50cnktPmRlcXVldWUgPSBwcml2X2VwLT5k ZXF1ZXVlOworCSksCisJVFBfcHJpbnRrKCIlczogbXBzOiAlZC8lZC4gc3RyZWFtczogJWQsIGJ1 cnN0OiAlZCwgZW5xIGlkeDogJWQsICIKKwkJICAiZGVxIGlkeDogJWQsIGZsYWdzICVzJXMlcyVz JXMlcyVzJXMsIGRpcjogJXMiLAorCQlfX2dldF9zdHIobmFtZSksIF9fZW50cnktPm1heHBhY2tl dCwKKwkJX19lbnRyeS0+bWF4cGFja2V0X2xpbWl0LCBfX2VudHJ5LT5tYXhfc3RyZWFtcywKKwkJ X19lbnRyeS0+bWF4YnVyc3QsIF9fZW50cnktPmVucXVldWUsCisJCV9fZW50cnktPmRlcXVldWUs CisJCV9fZW50cnktPmZsYWdzICYgRVBfRU5BQkxFRCA/ICJFTiB8ICIgOiAiIiwKKwkJX19lbnRy eS0+ZmxhZ3MgJiBFUF9TVEFMTCA/ICJTVEFMTCB8ICIgOiAiIiwKKwkJX19lbnRyeS0+ZmxhZ3Mg JiBFUF9XRURHRSA/ICJXRURHRSB8ICIgOiAiIiwKKwkJX19lbnRyeS0+ZmxhZ3MgJiBFUF9UUkFO U0ZFUl9TVEFSVEVEID8gIlNUQVJURUQgfCAiIDogIiIsCisJCV9fZW50cnktPmZsYWdzICYgRVBf VVBEQVRFX0VQX1RSQkFERFIgPyAiVVBEIFRSQiB8ICIgOiAiIiwKKwkJX19lbnRyeS0+ZmxhZ3Mg JiBFUF9QRU5ESU5HX1JFUVVFU1QgPyAiUkVRIFBFTiB8ICIgOiAiIiwKKwkJX19lbnRyeS0+Zmxh Z3MgJiBFUF9SSU5HX0ZVTEwgPyAiUklORyBGVUxMIHwiIDogIiIsCisJCV9fZW50cnktPmZsYWdz ICYgRVBfQ0xBSU1FRCA/ICAiQ0xBSU1FRCAiIDogIiIsCisJCV9fZW50cnktPmRpciA/ICJJTiIg OiAiT1VUIgorCSkKKyk7CisKK0RFRklORV9FVkVOVChjZG5zM19sb2dfZXAsIGNkbnMzX2dhZGdl dF9lcF9lbmFibGUsCisJVFBfUFJPVE8oc3RydWN0IGNkbnMzX2VuZHBvaW50ICpwcml2X2VwKSwK KwlUUF9BUkdTKHByaXZfZXApCispOworCitERUZJTkVfRVZFTlQoY2RuczNfbG9nX2VwLCBjZG5z M19nYWRnZXRfZXBfZGlzYWJsZSwKKwlUUF9QUk9UTyhzdHJ1Y3QgY2RuczNfZW5kcG9pbnQgKnBy aXZfZXApLAorCVRQX0FSR1MocHJpdl9lcCkKKyk7CisjZW5kaWYgLyogX19MSU5VWF9DRE5TM19U UkFDRSAqLworCisvKiB0aGlzIHBhcnQgbXVzdCBiZSBvdXRzaWRlIGhlYWRlciBndWFyZCAqLwor CisjdW5kZWYgVFJBQ0VfSU5DTFVERV9QQVRICisjZGVmaW5lIFRSQUNFX0lOQ0xVREVfUEFUSCAu CisKKyN1bmRlZiBUUkFDRV9JTkNMVURFX0ZJTEUKKyNkZWZpbmUgVFJBQ0VfSU5DTFVERV9GSUxF IHRyYWNlCisKKyNpbmNsdWRlIDx0cmFjZS9kZWZpbmVfdHJhY2UuaD4K