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=-13.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, USER_AGENT_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 2FE06C4346E for ; Sun, 27 Sep 2020 07:49:09 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 828702399C for ; Sun, 27 Sep 2020 07:49:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="CO54rfcF"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="pLnJ4P3c" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 828702399C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-ID:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=VxUm7S3Oag9DXQObSOZRJTYFFJOQLtEEyFxYRoNA35M=; b=CO54rfcFuxskrI549UW86Iv7S PxXwJGoDPH8zX5xRyL/vstvrxliwCPs+eEqnfxw65T/Gb+J3O1AFtM4noyeGaCAXp4KLJpr9iZ18i GNw1hhXK8OSJ4wmwGKyJpt+EOAt1RqEdOERgyxdCn5id2Q6AevL33ACIDfK7V58pPo9SI+RLJWhc4 8n04e/RfRSUSI0VkcW7HWN9zq2W5GD1VHLRnvrDWqHOiUjK6OTrSMaYB2BfSCQgbBIibDXqTFn1KI 3Z7lP7M1UC5UXGSdwDZfiZ7Qpxf1rbEqdTzca6jc78Z7RKA0eBhNAYW6giCPliF1AnxFC46bKLUAo +O5Vv8qnA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kMRQV-00044f-Tv; Sun, 27 Sep 2020 07:48:55 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kMRQP-00041J-Hs; Sun, 27 Sep 2020 07:48:51 +0000 X-UUID: 4b595df23e3d4876b490316098e79752-20200926 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=8P68Afz/ttPvRDRRLqb82ic0H6eAnH0ZNO25vf3BPBg=; b=pLnJ4P3c+GTDaMPLkUfLoo3tR8wjyPWYyE2IMsRqxMopPXPuerBkgB4zNGGfEEQQB+KkH4ylh/0I3VQUvYWAVl5cUZzKbIpreFMtoT5mYAemFFSU4wEe4A/0nsiqNL5LHsFHwcRuCd/qOByhZrUiWanD9YGBEbCOPYpUapRpKNs=; X-UUID: 4b595df23e3d4876b490316098e79752-20200926 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 695693604; Sat, 26 Sep 2020 23:48:42 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 27 Sep 2020 00:48:41 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 27 Sep 2020 15:48:28 +0800 Received: from localhost.localdomain (10.17.3.153) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 27 Sep 2020 15:48:27 +0800 From: Jianjun Wang To: Bjorn Helgaas , Rob Herring , Lorenzo Pieralisi , Ryder Lee Subject: [v3,2/3] PCI: mediatek: Add new generation controller support Date: Sun, 27 Sep 2020 15:45:54 +0800 Message-ID: <20200927074555.4155-3-jianjun.wang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20200927074555.4155-1-jianjun.wang@mediatek.com> References: <20200927074555.4155-1-jianjun.wang@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: CC715FDA7CA61A0D39C583CB7A33E73384677ABBE66BC3B01B721855B82A588D2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200927_034849_866014_5EC399EF X-CRM114-Status: GOOD ( 19.99 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: youlin.pei@mediatek.com, devicetree@vger.kernel.org, qizhong.cheng@mediatek.com, chuanjia.liu@mediatek.com, Mauro Carvalho Chehab , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, Jianjun Wang , sin_jieyang@mediatek.com, Sj Huang , linux-mediatek@lists.infradead.org, Philipp Zabel , Matthias Brugger , davem@davemloft.net, linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org MediaTek's PCIe host controller has three generation HWs, the new generation HW is an individual bridge, it supoorts Gen3 speed and up to 256 MSI interrupt numbers for multi-function devices. Add support for new Gen3 controller which can be found on MT8192. Signed-off-by: Jianjun Wang Acked-by: Ryder Lee --- drivers/pci/controller/Kconfig | 14 + drivers/pci/controller/Makefile | 1 + drivers/pci/controller/pcie-mediatek-gen3.c | 1024 +++++++++++++++++++ 3 files changed, 1039 insertions(+) create mode 100644 drivers/pci/controller/pcie-mediatek-gen3.c diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index f18c3725ef80..83daa772595b 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -239,6 +239,20 @@ config PCIE_MEDIATEK Say Y here if you want to enable PCIe controller support on MediaTek SoCs. +config PCIE_MEDIATEK_GEN3 + tristate "MediaTek GEN3 PCIe controller" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + depends on PCI_MSI_IRQ_DOMAIN + help + Adds support for PCIe Gen3 MAC controller for MediaTek SoCs. + This PCIe controller provides the capable of Gen3, Gen2 and + Gen1 speed, and support up to 256 MSI interrupt numbers for + multi-function devices. + + Say Y here if you want to enable Gen3 PCIe controller support on + MediaTek SoCs. + config PCIE_TANGO_SMP8759 bool "Tango SMP8759 PCIe controller (DANGEROUS)" depends on ARCH_TANGO && PCI_MSI && OF diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index bcdbf49ab1e4..9c1b96777597 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o +obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie-mediatek-gen3.o obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c new file mode 100644 index 000000000000..ad69c789b24d --- /dev/null +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -0,0 +1,1024 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek PCIe host controller driver. + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Jianjun Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" + +#define PCIE_SETTING_REG 0x80 +#define PCIE_PCI_IDS_1 0x9c +#define PCI_CLASS(class) (class << 8) +#define PCIE_RC_MODE BIT(0) + +#define PCIE_CFGNUM_REG 0x140 +#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0)) +#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8)) +#define PCIE_CFG_BYTE_EN(bytes) (((bytes) << 16) & GENMASK(19, 16)) +#define PCIE_CFG_FORCE_BYTE_EN BIT(20) +#define PCIE_CFG_OFFSET_ADDR 0x1000 +#define PCIE_CFG_HEADER(devfn, bus) \ + (PCIE_CFG_DEVFN(devfn) | PCIE_CFG_BUS(bus)) + +#define PCIE_CFG_HEADER_FORCE_BE(devfn, bus, bytes) \ + (PCIE_CFG_HEADER(devfn, bus) | PCIE_CFG_BYTE_EN(bytes) \ + | PCIE_CFG_FORCE_BYTE_EN) + +#define PCIE_RST_CTRL_REG 0x148 +#define PCIE_MAC_RSTB BIT(0) +#define PCIE_PHY_RSTB BIT(1) +#define PCIE_BRG_RSTB BIT(2) +#define PCIE_PE_RSTB BIT(3) + +#define PCIE_MISC_STATUS_REG 0x14C +#define PCIE_LTR_MSG_RECEIVED BIT(0) +#define PCIE_PCIE_MSG_RECEIVED BIT(1) + +#define PCIE_LTSSM_STATUS_REG 0x150 +#define PCIE_LTSSM_STATE_MASK GENMASK(28, 24) +#define PCIE_LTSSM_STATE(val) ((val & PCIE_LTSSM_STATE_MASK) >> 24) +#define PCIE_LTSSM_STATE_L0 0x10 +#define PCIE_LTSSM_STATE_L1_IDLE 0x13 +#define PCIE_LTSSM_STATE_L2_IDLE 0x14 + +#define PCIE_LINK_STATUS_REG 0x154 +#define PCIE_PORT_LINKUP BIT(8) + +#define PCIE_MSI_SET_NUM 8 +#define PCIE_MSI_IRQS_PER_SET 32 +#define PCIE_MSI_IRQS_NUM \ + (PCIE_MSI_IRQS_PER_SET * (PCIE_MSI_SET_NUM)) + +#define PCIE_INT_ENABLE_REG 0x180 +#define PCIE_MSI_MASK GENMASK(PCIE_MSI_SET_NUM + 8 - 1, 8) +#define PCIE_MSI_SHIFT 8 +#define PCIE_INTX_SHIFT 24 +#define PCIE_INTX_MASK GENMASK(27, 24) +#define PCIE_MSG_MASK BIT(28) +#define PCIE_AER_MASK BIT(29) +#define PCIE_PM_MASK BIT(30) + +#define PCIE_INT_STATUS_REG 0x184 +#define PCIE_MSI_SET_ENABLE_REG 0x190 + +#define PCIE_LOW_POWER_CTRL_REG 0x194 +#define PCIE_DIS_LOWPWR_MASK GENMASK(3, 0) +#define PCIE_DIS_L0S_MASK BIT(0) +#define PCIE_DIS_L1_MASK BIT(1) +#define PCIE_DIS_L11_MASK BIT(2) +#define PCIE_DIS_L12_MASK BIT(3) +#define PCIE_FORCE_DIS_LOWPWR GENMASK(11, 8) +#define PCIE_FORCE_DIS_L0S BIT(8) +#define PCIE_FORCE_DIS_L1 BIT(9) +#define PCIE_FORCE_DIS_L11 BIT(10) +#define PCIE_FORCE_DIS_L12 BIT(11) + +#define PCIE_ICMD_PM_REG 0x198 +#define PCIE_TURN_OFF_LINK BIT(4) + +#define PCIE_MSI_ADDR_BASE_REG 0xc00 +#define PCIE_MSI_SET_OFFSET 0x10 +#define PCIE_MSI_STATUS_OFFSET 0x04 +#define PCIE_MSI_ENABLE_OFFSET 0x08 + +#define PCIE_TRANS_TABLE_BASE_REG 0x800 +#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4 +#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8 +#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc +#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10 +#define PCIE_ATR_TLB_SET_OFFSET 0x20 + +#define PCIE_MAX_TRANS_TABLES 8 +#define ATR_EN BIT(0) +#define ATR_SIZE(size) ((((size) - 1) << 1) & GENMASK(6, 1)) +#define ATR_ID(id) (id & GENMASK(3, 0)) +#define ATR_PARAM(param) (((param) << 16) & GENMASK(27, 16)) + +/** + * struct mtk_pcie_msi - MSI information for each set + * @base: IO mapped register base + * @hwirq: Hardware interrupt number + * @irq: MSI set Interrupt number + * @index: MSI set number + * @msg_addr: MSI message address + * @domain: IRQ domain + */ +struct mtk_pcie_msi { + void __iomem *base; + int hwirq; + int irq; + int index; + phys_addr_t msg_addr; + struct irq_domain *domain; +}; + +/** + * struct mtk_pcie_port - PCIe port information + * @dev: PCIe device + * @base: IO mapped register base + * @reg_base: Physical register base + * @mac_reset: mac reset control + * @phy_reset: phy reset control + * @phy: PHY controller block + * @clks: PCIe clocks + * @num_clks: PCIe clocks count for this port + * @is_suspended: device suspend state + * @irq: PCIe controller interrupt number + * @intx_domain: legacy INTx IRQ domain + * @msi_domain: MSI IRQ domain + * @msi_top_domain: MSI IRQ top domain + * @msi_info: MSI sets information + * @lock: lock protecting IRQ bit map + * @msi_irq_in_use: bit map for assigned MSI IRQ + */ +struct mtk_pcie_port { + struct device *dev; + void __iomem *base; + phys_addr_t reg_base; + struct reset_control *mac_reset; + struct reset_control *phy_reset; + struct phy *phy; + struct clk_bulk_data *clks; + int num_clks; + bool is_suspended; + + int irq; + struct irq_domain *intx_domain; + struct irq_domain *msi_domain; + struct irq_domain *msi_top_domain; + struct mtk_pcie_msi **msi_info; + struct mutex lock; + DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM); +}; + +static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct mtk_pcie_port *port = bus->sysdata; + int bytes; + + bytes = ((1 << size) - 1) << (where & 0x3); + writel(PCIE_CFG_HEADER_FORCE_BE(devfn, bus->number, bytes), + port->base + PCIE_CFGNUM_REG); + + *val = readl(port->base + PCIE_CFG_OFFSET_ADDR + (where & ~0x3)); + + if (size <= 2) + *val = (*val >> (8 * (where & 0x3))) & ((1 << (size * 8)) - 1); + + return PCIBIOS_SUCCESSFUL; +} + +static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct mtk_pcie_port *port = bus->sysdata; + int bytes; + + bytes = ((1 << size) - 1) << (where & 0x3); + writel(PCIE_CFG_HEADER_FORCE_BE(devfn, bus->number, bytes), + port->base + PCIE_CFGNUM_REG); + + if (size <= 2) + val = (val & ((1 << (size * 8)) - 1)) << ((where & 0x3) * 8); + + writel(val, port->base + PCIE_CFG_OFFSET_ADDR + (where & ~0x3)); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops mtk_pcie_ops = { + .read = mtk_pcie_config_read, + .write = mtk_pcie_config_write, +}; + +static void mtk_pcie_set_trans_window(void __iomem *reg, + resource_size_t cpu_addr, + resource_size_t pci_addr, size_t size) +{ + writel(lower_32_bits(cpu_addr) | ATR_SIZE(fls(size) - 1) | ATR_EN, reg); + writel(upper_32_bits(cpu_addr), reg + PCIE_ATR_SRC_ADDR_MSB_OFFSET); + writel(lower_32_bits(pci_addr), reg + PCIE_ATR_TRSL_ADDR_LSB_OFFSET); + writel(upper_32_bits(pci_addr), reg + PCIE_ATR_TRSL_ADDR_MSB_OFFSET); + writel(ATR_ID(0) | ATR_PARAM(0), reg + PCIE_ATR_TRSL_PARAM_OFFSET); +} + +static int mtk_pcie_set_trans_table(void __iomem *reg, + resource_size_t cpu_addr, + resource_size_t pci_addr, size_t size, + int num) +{ + void __iomem *table_base; + + if (num > PCIE_MAX_TRANS_TABLES) + return -ENODEV; + + table_base = reg + num * PCIE_ATR_TLB_SET_OFFSET; + mtk_pcie_set_trans_window(table_base, cpu_addr, pci_addr, size); + + return 0; +} + +static int mtk_pcie_startup_port(struct mtk_pcie_port *port) +{ + struct resource_entry *entry; + struct pci_host_bridge *host = pci_host_bridge_from_priv(port); + u32 val; + int err = 0, table_index = 0; + + /* Set as RC mode */ + val = readl(port->base + PCIE_SETTING_REG); + val |= PCIE_RC_MODE; + writel(val, port->base + PCIE_SETTING_REG); + + /* Set class code */ + val = readl(port->base + PCIE_PCI_IDS_1); + val &= ~GENMASK(31, 8); + val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8); + writel(val, port->base + PCIE_PCI_IDS_1); + + /* Assert all reset signals */ + val = readl(port->base + PCIE_RST_CTRL_REG); + val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* De-assert reset signals*/ + val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB); + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* Delay 100ms to wait the reference clocks become stable */ + usleep_range(100 * 1000, 120 * 1000); + + /* De-assert pe reset*/ + val &= ~PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* Check if the link is up or not */ + err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_REG, val, + !!(val & PCIE_PORT_LINKUP), 20, + 50 * USEC_PER_MSEC); + if (err) + return err; + + /* Set PCIe translation windows */ + resource_list_for_each_entry(entry, &host->windows) { + unsigned long type = resource_type(entry->res); + struct resource *res = NULL; + resource_size_t cpu_addr; + resource_size_t pci_addr; + + if (!(type & (IORESOURCE_MEM | IORESOURCE_IO))) + continue; + + res = entry->res; + cpu_addr = res->start; + pci_addr = res->start - entry->offset; + mtk_pcie_set_trans_table(port->base + PCIE_TRANS_TABLE_BASE_REG, + cpu_addr, pci_addr, resource_size(res), + table_index); + + dev_dbg(port->dev, "Set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n", + (!!(type & IORESOURCE_MEM) ? "MEM" : "IO"), table_index, + cpu_addr, pci_addr, resource_size(res)); + + table_index++; + } + + return 0; +} + +static inline struct mtk_pcie_msi *mtk_get_msi_info(struct mtk_pcie_port *port, + unsigned int hwirq) +{ + return port->msi_info[hwirq / PCIE_MSI_IRQS_PER_SET]; +} + +static int mtk_pcie_set_affinity(struct irq_data *data, + const struct cpumask *mask, bool force) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int ret; + + ret = irq_set_affinity_hint(port->irq, mask); + if (ret) + return ret; + + irq_data_update_effective_affinity(data, mask); + + return 0; +} + +static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + + msi_info = mtk_get_msi_info(port, data->hwirq); + + msg->address_hi = 0; + msg->address_lo = lower_32_bits(msi_info->msg_addr); + + msg->data = data->hwirq; + dev_dbg(port->dev, "msi#%#lx address_hi %#x address_lo %#x data %d\n", + data->hwirq, msg->address_hi, msg->address_lo, msg->data); +} + +static void mtk_msi_irq_ack(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int hwirq; + + msi_info = mtk_get_msi_info(port, data->hwirq); + + hwirq = data->hwirq % PCIE_MSI_IRQS_PER_SET; + + writel(1 << hwirq, msi_info->base + PCIE_MSI_STATUS_OFFSET); +} + +static void mtk_msi_irq_mask(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + msi_info = mtk_get_msi_info(port, data->hwirq); + val = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + val &= ~(1 << data->hwirq); + writel(val, msi_info->base + PCIE_MSI_ENABLE_OFFSET); + + pci_msi_mask_irq(data); +} + +static void mtk_msi_irq_unmask(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + msi_info = mtk_get_msi_info(port, data->hwirq); + val = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + val |= (1 << data->hwirq); + writel(val, msi_info->base + PCIE_MSI_ENABLE_OFFSET); + + pci_msi_unmask_irq(data); +} + +static struct irq_chip mtk_msi_irq_chip = { + .irq_ack = mtk_msi_irq_ack, + .irq_compose_msi_msg = mtk_compose_msi_msg, + .irq_mask = mtk_msi_irq_mask, + .irq_unmask = mtk_msi_irq_unmask, + .irq_set_affinity = mtk_pcie_set_affinity, + .name = "PCIe", +}; + +static irq_hw_number_t mtk_pcie_msi_get_hwirq(struct msi_domain_info *info, + msi_alloc_info_t *arg) +{ + struct msi_desc *entry = arg->desc; + struct mtk_pcie_port *port = info->chip_data; + int hwirq; + + mutex_lock(&port->lock); + + hwirq = bitmap_find_free_region(port->msi_irq_in_use, PCIE_MSI_IRQS_NUM, + order_base_2(entry->nvec_used)); + if (hwirq < 0) { + mutex_unlock(&port->lock); + return -ENOSPC; + } + + mutex_unlock(&port->lock); + + return hwirq; +} + +static void mtk_pcie_msi_free(struct irq_domain *domain, + struct msi_domain_info *info, unsigned int virq) +{ + struct irq_data *data = irq_domain_get_irq_data(domain, virq); + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + + mutex_lock(&port->lock); + + bitmap_clear(port->msi_irq_in_use, data->hwirq, 1); + + mutex_unlock(&port->lock); +} + +static struct msi_domain_ops mtk_msi_domain_ops = { + .get_hwirq = mtk_pcie_msi_get_hwirq, + .msi_free = mtk_pcie_msi_free, +}; + +static struct msi_domain_info mtk_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_PCI_MSIX | + MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI), + .chip = &mtk_msi_irq_chip, + .ops = &mtk_msi_domain_ops, + .handler = handle_edge_irq, + .handler_name = "MSI", +}; + +static void mtk_msi_top_irq_eoi(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int msi_irq = data->hwirq + PCIE_MSI_SHIFT; + + writel(1 << msi_irq, port->base + PCIE_INT_STATUS_REG); +} + +static struct irq_chip mtk_msi_top_irq_chip = { + .irq_eoi = mtk_msi_top_irq_eoi, + .name = "PCIe", +}; + +static void mtk_pcie_msi_handler(struct irq_desc *desc) +{ + struct mtk_pcie_msi *msi_info = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long msi_enable, msi_status; + u32 virq, bit, hwirq; + + chained_irq_enter(irqchip, desc); + + msi_enable = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + while ((msi_status = readl(msi_info->base + PCIE_MSI_STATUS_OFFSET))) { + msi_status &= msi_enable; + for_each_set_bit(bit, &msi_status, PCIE_MSI_IRQS_PER_SET) { + hwirq = bit + msi_info->index * PCIE_MSI_IRQS_PER_SET; + virq = irq_find_mapping(msi_info->domain, hwirq); + generic_handle_irq(virq); + } + } + + chained_irq_exit(irqchip, desc); +} + +static int mtk_msi_top_domain_map(struct irq_domain *domain, + unsigned int virq, irq_hw_number_t hwirq) +{ + struct mtk_pcie_port *port = domain->host_data; + struct mtk_pcie_msi *msi_info = port->msi_info[hwirq]; + + irq_domain_set_info(domain, virq, hwirq, + &mtk_msi_top_irq_chip, domain->host_data, + mtk_pcie_msi_handler, msi_info, NULL); + + return 0; +} + +static const struct irq_domain_ops mtk_msi_top_domain_ops = { + .map = mtk_msi_top_domain_map, +}; + +static void mtk_intx_mask(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val &= ~(1 << (data->hwirq + PCIE_INTX_SHIFT)); + writel(val, port->base + PCIE_INT_ENABLE_REG); +} + +static void mtk_intx_unmask(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val |= 1 << (data->hwirq + PCIE_INTX_SHIFT); + writel(val, port->base + PCIE_INT_ENABLE_REG); +} + +static void mtk_intx_eoi(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int hwirq; + + /** + * As an emulated level irq, its interrupt status will be remained + * until receive the corresponding message of de-assert, hence that + * the status can only be cleared when the interrupt has been serviced. + */ + hwirq = data->hwirq + PCIE_INTX_SHIFT; + writel(1 << hwirq, port->base + PCIE_INT_STATUS_REG); +} + +static struct irq_chip mtk_intx_irq_chip = { + .irq_mask = mtk_intx_mask, + .irq_unmask = mtk_intx_unmask, + .irq_eoi = mtk_intx_eoi, + .irq_set_affinity = mtk_pcie_set_affinity, + .name = "PCIe", +}; + +static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler_name(irq, &mtk_intx_irq_chip, + handle_fasteoi_irq, "INTx"); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = mtk_pcie_intx_map, +}; + +static int mtk_pcie_init_irq_domains(struct mtk_pcie_port *port, + struct device_node *node) +{ + struct device *dev = port->dev; + struct device_node *intc_node; + struct fwnode_handle *fwnode = of_node_to_fwnode(node); + struct mtk_pcie_msi *msi_info; + struct msi_domain_info *info; + int i, val, ret; + + /* Setup INTx */ + intc_node = of_get_child_by_name(node, "interrupt-controller"); + if (!intc_node) { + dev_notice(dev, "Missing PCIe Intc node\n"); + return -ENODEV; + } + + port->intx_domain = irq_domain_add_linear(intc_node, PCI_NUM_INTX, + &intx_domain_ops, port); + if (!port->intx_domain) { + dev_notice(dev, "failed to get INTx IRQ domain\n"); + return -ENODEV; + } + + /* Setup MSI */ + mutex_init(&port->lock); + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memcpy(info, &mtk_msi_domain_info, sizeof(*info)); + info->chip_data = port; + + port->msi_domain = pci_msi_create_irq_domain(fwnode, info, NULL); + if (!port->msi_domain) { + dev_info(dev, "failed to create msi domain\n"); + ret = -ENODEV; + goto err_msi_domain; + } + + /* Enable MSI and setup pcie domains */ + port->msi_top_domain = irq_domain_add_hierarchy(NULL, 0, 0, node, + &mtk_msi_top_domain_ops, + port); + if (!port->msi_top_domain) { + dev_info(dev, "failed to create msi top domain\n"); + ret = -ENODEV; + goto err_msi_top_domain; + } + + port->msi_info = devm_kzalloc(dev, PCIE_MSI_SET_NUM, GFP_KERNEL); + if (!port->msi_info) { + ret = -ENOMEM; + goto err_msi_info; + } + + for (i = 0; i < PCIE_MSI_SET_NUM; i++) { + int offset = i * PCIE_MSI_SET_OFFSET; + + msi_info = devm_kzalloc(dev, sizeof(*msi_info), GFP_KERNEL); + if (!msi_info) { + ret = -ENOMEM; + goto err_msi_set; + } + + msi_info->base = port->base + PCIE_MSI_ADDR_BASE_REG + offset; + msi_info->msg_addr = port->reg_base + PCIE_MSI_ADDR_BASE_REG + + offset; + + writel(lower_32_bits(msi_info->msg_addr), msi_info->base); + + msi_info->hwirq = i; + msi_info->index = i; + msi_info->domain = port->msi_domain; + + port->msi_info[i] = msi_info; + + /* Alloc irq for each msi set */ + msi_info->irq = irq_create_mapping(port->msi_top_domain, i); + if (msi_info->irq < 0) { + dev_info(dev, "allocate msi top irq failed\n"); + ret = -ENOSPC; + goto err_msi_set; + } + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val |= (1 << (i + PCIE_MSI_SHIFT)); + writel(val, port->base + PCIE_INT_ENABLE_REG); + + val = readl(port->base + PCIE_MSI_SET_ENABLE_REG); + val |= (1 << i); + writel(val, port->base + PCIE_MSI_SET_ENABLE_REG); + } + + return 0; + +err_msi_set: + while (--i >= 0) { + msi_info = port->msi_info[i]; + irq_dispose_mapping(msi_info->irq); + } +err_msi_info: + irq_domain_remove(port->msi_top_domain); +err_msi_top_domain: + irq_domain_remove(port->msi_domain); +err_msi_domain: + irq_domain_remove(port->intx_domain); + + return ret; +} + +static void mtk_pcie_irq_teardown(struct mtk_pcie_port *port) +{ + struct mtk_pcie_msi *msi_info; + int i; + + irq_set_chained_handler_and_data(port->irq, NULL, NULL); + + if (port->intx_domain) + irq_domain_remove(port->intx_domain); + + if (port->msi_domain) + irq_domain_remove(port->msi_domain); + + if (port->msi_top_domain) { + for (i = 0; i < PCIE_MSI_SET_NUM; i++) { + msi_info = port->msi_info[i]; + irq_dispose_mapping(msi_info->irq); + } + + irq_domain_remove(port->msi_top_domain); + } + + irq_dispose_mapping(port->irq); +} + +static void mtk_pcie_irq_handler(struct irq_desc *desc) +{ + struct mtk_pcie_port *port = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long status; + u32 virq; + u32 irq_bit = PCIE_INTX_SHIFT; + + chained_irq_enter(irqchip, desc); + + status = readl(port->base + PCIE_INT_STATUS_REG); + if (status & PCIE_INTX_MASK) { + for_each_set_bit_from(irq_bit, &status, PCI_NUM_INTX + + PCIE_INTX_SHIFT) { + virq = irq_find_mapping(port->intx_domain, + irq_bit - PCIE_INTX_SHIFT); + generic_handle_irq(virq); + } + } + + if (status & PCIE_MSI_MASK) { + irq_bit = PCIE_MSI_SHIFT; + for_each_set_bit_from(irq_bit, &status, PCIE_MSI_SET_NUM + + PCIE_MSI_SHIFT) { + virq = irq_find_mapping(port->msi_top_domain, + irq_bit - PCIE_MSI_SHIFT); + generic_handle_irq(virq); + } + } + + chained_irq_exit(irqchip, desc); +} + +static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, + struct device_node *node) +{ + struct device *dev = port->dev; + struct platform_device *pdev = to_platform_device(dev); + int err; + + err = mtk_pcie_init_irq_domains(port, node); + if (err) { + dev_notice(dev, "failed to init PCIe IRQ domain\n"); + return err; + } + + port->irq = platform_get_irq(pdev, 0); + if (port->irq < 0) + return port->irq; + + irq_set_chained_handler_and_data(port->irq, mtk_pcie_irq_handler, port); + + return 0; +} + +static int mtk_pcie_clk_init(struct mtk_pcie_port *port) +{ + int ret; + + port->num_clks = devm_clk_bulk_get_all(port->dev, &port->clks); + if (port->num_clks < 0) { + dev_notice(port->dev, "failed to get pcie clock\n"); + return port->num_clks; + } + + ret = clk_bulk_prepare_enable(port->num_clks, port->clks); + if (ret) { + dev_notice(port->dev, "failed to enable pcie clocks\n"); + return ret; + } + + return 0; +} + +static int mtk_pcie_power_up(struct mtk_pcie_port *port) +{ + struct device *dev = port->dev; + int err; + + port->phy_reset = devm_reset_control_get_optional_exclusive(dev, + "phy-rst"); + if (IS_ERR(port->phy_reset)) + return PTR_ERR(port->phy_reset); + + reset_control_deassert(port->phy_reset); + + /* PHY power on and enable pipe clock */ + port->phy = devm_phy_optional_get(dev, "pcie-phy"); + if (IS_ERR(port->phy)) + return PTR_ERR(port->phy); + + err = phy_init(port->phy); + if (err) { + dev_notice(dev, "failed to initialize pcie phy\n"); + return err; + } + + err = phy_power_on(port->phy); + if (err) { + dev_notice(dev, "failed to power on pcie phy\n"); + goto err_phy_on; + } + + port->mac_reset = devm_reset_control_get_optional_exclusive(dev, + "mac-rst"); + if (IS_ERR(port->mac_reset)) + return PTR_ERR(port->mac_reset); + + reset_control_deassert(port->mac_reset); + + /* MAC power on and enable transaction layer clocks */ + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + err = mtk_pcie_clk_init(port); + if (err) { + dev_notice(dev, "clock init failed\n"); + goto err_clk_init; + } + + return 0; + +err_clk_init: + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + reset_control_assert(port->mac_reset); + phy_power_off(port->phy); +err_phy_on: + phy_exit(port->phy); + reset_control_assert(port->phy_reset); + + return -EBUSY; +} + +static void mtk_pcie_power_down(struct mtk_pcie_port *port) +{ + phy_power_off(port->phy); + phy_exit(port->phy); + + clk_bulk_disable_unprepare(port->num_clks, port->clks); + + pm_runtime_put_sync(port->dev); + pm_runtime_disable(port->dev); +} + +static int mtk_pcie_setup(struct mtk_pcie_port *port) +{ + struct device *dev = port->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *regs; + int err; + + regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac"); + port->base = devm_ioremap_resource(dev, regs); + if (IS_ERR(port->base)) { + dev_notice(dev, "failed to map register base\n"); + return PTR_ERR(port->base); + } + + port->reg_base = regs->start; + + /* Don't touch the hardware registers before power up */ + err = mtk_pcie_power_up(port); + if (err) + return err; + + /* Try link up */ + err = mtk_pcie_startup_port(port); + if (err) { + dev_notice(dev, "PCIe link down\n"); + goto err_setup; + } + + err = mtk_pcie_setup_irq(port, dev->of_node); + if (err) + goto err_setup; + + dev_info(dev, "PCIe link up success!\n"); + + return 0; + +err_setup: + mtk_pcie_power_down(port); + + return err; +} + +static int mtk_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_pcie_port *port; + struct pci_host_bridge *host; + int err; + + host = devm_pci_alloc_host_bridge(dev, sizeof(*port)); + if (!host) + return -ENOMEM; + + port = pci_host_bridge_priv(host); + + port->dev = dev; + platform_set_drvdata(pdev, port); + + err = mtk_pcie_setup(port); + if (err) + return err; + + host->ops = &mtk_pcie_ops; + host->sysdata = port; + + err = pci_host_probe(host); + if (err) { + mtk_pcie_power_down(port); + return err; + } + + return 0; +} + +static int mtk_pcie_remove(struct platform_device *pdev) +{ + struct mtk_pcie_port *port = platform_get_drvdata(pdev); + struct pci_host_bridge *host = pci_host_bridge_from_priv(port); + + pci_lock_rescan_remove(); + pci_stop_root_bus(host->bus); + pci_remove_root_bus(host->bus); + pci_unlock_rescan_remove(); + + mtk_pcie_irq_teardown(port); + mtk_pcie_power_down(port); + + return 0; +} + +static int __maybe_unused mtk_pcie_turn_off_link(struct mtk_pcie_port *port) +{ + int val; + + val = readl(port->base + PCIE_ICMD_PM_REG); + val |= PCIE_TURN_OFF_LINK; + writel(val, port->base + PCIE_ICMD_PM_REG); + + /* Check the link is L2 */ + return readl_poll_timeout(port->base + PCIE_LTSSM_STATUS_REG, val, + (PCIE_LTSSM_STATE(val) == + PCIE_LTSSM_STATE_L2_IDLE), 20, + 50 * USEC_PER_MSEC); +} + +static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) +{ + struct mtk_pcie_port *port = dev_get_drvdata(dev); + int err, val; + + if (port->is_suspended) + return 0; + + /* Trigger link to L2 state */ + err = mtk_pcie_turn_off_link(port); + if (err) { + dev_notice(port->dev, "can not enter L2 state\n"); + goto power_off; + } + + /* Pull down the PERST# pin */ + val = readl(port->base + PCIE_RST_CTRL_REG); + val |= PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + dev_info(port->dev, "enter L2 state success"); + +power_off: + phy_power_off(port->phy); + + clk_bulk_disable_unprepare(port->num_clks, port->clks); + + port->is_suspended = true; + + return 0; +} + +static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) +{ + struct mtk_pcie_port *port = dev_get_drvdata(dev); + int err; + + if (!port->is_suspended) + return 0; + + phy_power_on(port->phy); + + err = clk_bulk_prepare_enable(port->num_clks, port->clks); + if (err) { + dev_dbg(dev, "failed to enable pcie clocks\n"); + return err; + } + + err = mtk_pcie_startup_port(port); + if (err) { + dev_notice(port->dev, "resume failed\n"); + return err; + } + + port->is_suspended = false; + + dev_info(port->dev, "resume done\n"); + + return 0; +} + +static const struct dev_pm_ops mtk_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq, + mtk_pcie_resume_noirq) +}; + +static const struct of_device_id mtk_pcie_of_match[] = { + { .compatible = "mediatek,gen3-pcie" }, + { .compatible = "mediatek,mt8192-pcie" }, + {}, +}; + +static struct platform_driver mtk_pcie_driver = { + .probe = mtk_pcie_probe, + .remove = mtk_pcie_remove, + .driver = { + .name = "mtk-pcie", + .of_match_table = mtk_pcie_of_match, + .pm = &mtk_pcie_pm_ops, + }, +}; + +module_platform_driver(mtk_pcie_driver); +MODULE_LICENSE("GPL v2"); -- 2.25.1 _______________________________________________ Linux-mediatek mailing list Linux-mediatek@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-mediatek From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.3 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,MIME_BASE64_TEXT,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY,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 AD318C4346E for ; Sun, 27 Sep 2020 07:48:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4912C239E5 for ; Sun, 27 Sep 2020 07:48:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="MwIaLWvT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730351AbgI0Hsu (ORCPT ); Sun, 27 Sep 2020 03:48:50 -0400 Received: from mailgw01.mediatek.com ([210.61.82.183]:38737 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727364AbgI0Hst (ORCPT ); Sun, 27 Sep 2020 03:48:49 -0400 X-UUID: 3820b31f577d4622b2463073d748d05b-20200927 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=8P68Afz/ttPvRDRRLqb82ic0H6eAnH0ZNO25vf3BPBg=; b=MwIaLWvTqg0GHQpUqlJpCU+wX2Alzz5TRpQMLUrwuuKhvEXMI6U0ZEY5nh1rmTAE7wYkhrpxEawUjvIzNurJm+glnTtLuKLDJ9BrJuCNoRruRQwrEBz76yDDylqEWFP7ldfFB6mNvTp2JMrrZVoejPLq7+QHQ3X+7kQw3MQOv58=; X-UUID: 3820b31f577d4622b2463073d748d05b-20200927 Received: from mtkcas08.mediatek.inc [(172.21.101.126)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.14 Build 0819 with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1834240930; Sun, 27 Sep 2020 15:48:30 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 27 Sep 2020 15:48:28 +0800 Received: from localhost.localdomain (10.17.3.153) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 27 Sep 2020 15:48:27 +0800 From: Jianjun Wang To: Bjorn Helgaas , Rob Herring , Lorenzo Pieralisi , Ryder Lee CC: Philipp Zabel , Matthias Brugger , Mauro Carvalho Chehab , , , , , , , Sj Huang , Jianjun Wang , , , , Subject: [v3,2/3] PCI: mediatek: Add new generation controller support Date: Sun, 27 Sep 2020 15:45:54 +0800 Message-ID: <20200927074555.4155-3-jianjun.wang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20200927074555.4155-1-jianjun.wang@mediatek.com> References: <20200927074555.4155-1-jianjun.wang@mediatek.com> MIME-Version: 1.0 Content-Type: text/plain X-TM-SNTS-SMTP: CC715FDA7CA61A0D39C583CB7A33E73384677ABBE66BC3B01B721855B82A588D2000:8 X-MTK: N Content-Transfer-Encoding: base64 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org TWVkaWFUZWsncyBQQ0llIGhvc3QgY29udHJvbGxlciBoYXMgdGhyZWUgZ2VuZXJhdGlvbiBIV3Ms IHRoZSBuZXcNCmdlbmVyYXRpb24gSFcgaXMgYW4gaW5kaXZpZHVhbCBicmlkZ2UsIGl0IHN1cG9v cnRzIEdlbjMgc3BlZWQgYW5kDQp1cCB0byAyNTYgTVNJIGludGVycnVwdCBudW1iZXJzIGZvciBt dWx0aS1mdW5jdGlvbiBkZXZpY2VzLg0KDQpBZGQgc3VwcG9ydCBmb3IgbmV3IEdlbjMgY29udHJv bGxlciB3aGljaCBjYW4gYmUgZm91bmQgb24gTVQ4MTkyLg0KDQpTaWduZWQtb2ZmLWJ5OiBKaWFu anVuIFdhbmcgPGppYW5qdW4ud2FuZ0BtZWRpYXRlay5jb20+DQpBY2tlZC1ieTogUnlkZXIgTGVl IDxyeWRlci5sZWVAbWVkaWF0ZWsuY29tPg0KLS0tDQogZHJpdmVycy9wY2kvY29udHJvbGxlci9L Y29uZmlnICAgICAgICAgICAgICB8ICAgMTQgKw0KIGRyaXZlcnMvcGNpL2NvbnRyb2xsZXIvTWFr ZWZpbGUgICAgICAgICAgICAgfCAgICAxICsNCiBkcml2ZXJzL3BjaS9jb250cm9sbGVyL3BjaWUt bWVkaWF0ZWstZ2VuMy5jIHwgMTAyNCArKysrKysrKysrKysrKysrKysrDQogMyBmaWxlcyBjaGFu Z2VkLCAxMDM5IGluc2VydGlvbnMoKykNCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9wY2kv Y29udHJvbGxlci9wY2llLW1lZGlhdGVrLWdlbjMuYw0KDQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9w Y2kvY29udHJvbGxlci9LY29uZmlnIGIvZHJpdmVycy9wY2kvY29udHJvbGxlci9LY29uZmlnDQpp bmRleCBmMThjMzcyNWVmODAuLjgzZGFhNzcyNTk1YiAxMDA2NDQNCi0tLSBhL2RyaXZlcnMvcGNp L2NvbnRyb2xsZXIvS2NvbmZpZw0KKysrIGIvZHJpdmVycy9wY2kvY29udHJvbGxlci9LY29uZmln DQpAQCAtMjM5LDYgKzIzOSwyMCBAQCBjb25maWcgUENJRV9NRURJQVRFSw0KIAkgIFNheSBZIGhl cmUgaWYgeW91IHdhbnQgdG8gZW5hYmxlIFBDSWUgY29udHJvbGxlciBzdXBwb3J0IG9uDQogCSAg TWVkaWFUZWsgU29Dcy4NCiANCitjb25maWcgUENJRV9NRURJQVRFS19HRU4zDQorCXRyaXN0YXRl ICJNZWRpYVRlayBHRU4zIFBDSWUgY29udHJvbGxlciINCisJZGVwZW5kcyBvbiBBUkNIX01FRElB VEVLIHx8IENPTVBJTEVfVEVTVA0KKwlkZXBlbmRzIG9uIE9GDQorCWRlcGVuZHMgb24gUENJX01T SV9JUlFfRE9NQUlODQorCWhlbHANCisJICBBZGRzIHN1cHBvcnQgZm9yIFBDSWUgR2VuMyBNQUMg Y29udHJvbGxlciBmb3IgTWVkaWFUZWsgU29Dcy4NCisJICBUaGlzIFBDSWUgY29udHJvbGxlciBw cm92aWRlcyB0aGUgY2FwYWJsZSBvZiBHZW4zLCBHZW4yIGFuZA0KKwkgIEdlbjEgc3BlZWQsIGFu ZCBzdXBwb3J0IHVwIHRvIDI1NiBNU0kgaW50ZXJydXB0IG51bWJlcnMgZm9yDQorCSAgbXVsdGkt ZnVuY3Rpb24gZGV2aWNlcy4NCisNCisJICBTYXkgWSBoZXJlIGlmIHlvdSB3YW50IHRvIGVuYWJs ZSBHZW4zIFBDSWUgY29udHJvbGxlciBzdXBwb3J0IG9uDQorCSAgTWVkaWFUZWsgU29Dcy4NCisN CiBjb25maWcgUENJRV9UQU5HT19TTVA4NzU5DQogCWJvb2wgIlRhbmdvIFNNUDg3NTkgUENJZSBj b250cm9sbGVyIChEQU5HRVJPVVMpIg0KIAlkZXBlbmRzIG9uIEFSQ0hfVEFOR08gJiYgUENJX01T SSAmJiBPRg0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvcGNpL2NvbnRyb2xsZXIvTWFrZWZpbGUgYi9k cml2ZXJzL3BjaS9jb250cm9sbGVyL01ha2VmaWxlDQppbmRleCBiY2RiZjQ5YWIxZTQuLjljMWI5 Njc3NzU5NyAxMDA2NDQNCi0tLSBhL2RyaXZlcnMvcGNpL2NvbnRyb2xsZXIvTWFrZWZpbGUNCisr KyBiL2RyaXZlcnMvcGNpL2NvbnRyb2xsZXIvTWFrZWZpbGUNCkBAIC0yNyw2ICsyNyw3IEBAIG9i ai0kKENPTkZJR19QQ0lFX1JPQ0tDSElQKSArPSBwY2llLXJvY2tjaGlwLm8NCiBvYmotJChDT05G SUdfUENJRV9ST0NLQ0hJUF9FUCkgKz0gcGNpZS1yb2NrY2hpcC1lcC5vDQogb2JqLSQoQ09ORklH X1BDSUVfUk9DS0NISVBfSE9TVCkgKz0gcGNpZS1yb2NrY2hpcC1ob3N0Lm8NCiBvYmotJChDT05G SUdfUENJRV9NRURJQVRFSykgKz0gcGNpZS1tZWRpYXRlay5vDQorb2JqLSQoQ09ORklHX1BDSUVf TUVESUFURUtfR0VOMykgKz0gcGNpZS1tZWRpYXRlay1nZW4zLm8NCiBvYmotJChDT05GSUdfUENJ RV9UQU5HT19TTVA4NzU5KSArPSBwY2llLXRhbmdvLm8NCiBvYmotJChDT05GSUdfVk1EKSArPSB2 bWQubw0KIG9iai0kKENPTkZJR19QQ0lFX0JSQ01TVEIpICs9IHBjaWUtYnJjbXN0Yi5vDQpkaWZm IC0tZ2l0IGEvZHJpdmVycy9wY2kvY29udHJvbGxlci9wY2llLW1lZGlhdGVrLWdlbjMuYyBiL2Ry aXZlcnMvcGNpL2NvbnRyb2xsZXIvcGNpZS1tZWRpYXRlay1nZW4zLmMNCm5ldyBmaWxlIG1vZGUg MTAwNjQ0DQppbmRleCAwMDAwMDAwMDAwMDAuLmFkNjljNzg5YjI0ZA0KLS0tIC9kZXYvbnVsbA0K KysrIGIvZHJpdmVycy9wY2kvY29udHJvbGxlci9wY2llLW1lZGlhdGVrLWdlbjMuYw0KQEAgLTAs MCArMSwxMDI0IEBADQorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjANCisvKg0K KyAqIE1lZGlhVGVrIFBDSWUgaG9zdCBjb250cm9sbGVyIGRyaXZlci4NCisgKg0KKyAqIENvcHly aWdodCAoYykgMjAyMCBNZWRpYVRlayBJbmMuDQorICogQXV0aG9yOiBKaWFuanVuIFdhbmcgPGpp YW5qdW4ud2FuZ0BtZWRpYXRlay5jb20+DQorICovDQorDQorI2luY2x1ZGUgPGxpbnV4L2Nsay5o Pg0KKyNpbmNsdWRlIDxsaW51eC9kZWxheS5oPg0KKyNpbmNsdWRlIDxsaW51eC9pb3BvbGwuaD4N CisjaW5jbHVkZSA8bGludXgvaXJxLmg+DQorI2luY2x1ZGUgPGxpbnV4L2lycWNoaXAvY2hhaW5l ZF9pcnEuaD4NCisjaW5jbHVkZSA8bGludXgvaXJxZG9tYWluLmg+DQorI2luY2x1ZGUgPGxpbnV4 L2tlcm5lbC5oPg0KKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4NCisjaW5jbHVkZSA8bGludXgv bXNpLmg+DQorI2luY2x1ZGUgPGxpbnV4L29mX2FkZHJlc3MuaD4NCisjaW5jbHVkZSA8bGludXgv b2ZfY2xrLmg+DQorI2luY2x1ZGUgPGxpbnV4L29mX3BjaS5oPg0KKyNpbmNsdWRlIDxsaW51eC9v Zl9wbGF0Zm9ybS5oPg0KKyNpbmNsdWRlIDxsaW51eC9wY2kuaD4NCisjaW5jbHVkZSA8bGludXgv cGh5L3BoeS5oPg0KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4NCisjaW5jbHVk ZSA8bGludXgvcG1fZG9tYWluLmg+DQorI2luY2x1ZGUgPGxpbnV4L3BtX3J1bnRpbWUuaD4NCisj aW5jbHVkZSA8bGludXgvcmVzZXQuaD4NCisNCisjaW5jbHVkZSAiLi4vcGNpLmgiDQorDQorI2Rl ZmluZSBQQ0lFX1NFVFRJTkdfUkVHCQkweDgwDQorI2RlZmluZSBQQ0lFX1BDSV9JRFNfMQkJCTB4 OWMNCisjZGVmaW5lIFBDSV9DTEFTUyhjbGFzcykJCShjbGFzcyA8PCA4KQ0KKyNkZWZpbmUgUENJ RV9SQ19NT0RFCQkJQklUKDApDQorDQorI2RlZmluZSBQQ0lFX0NGR05VTV9SRUcJCQkweDE0MA0K KyNkZWZpbmUgUENJRV9DRkdfREVWRk4oZGV2Zm4pCQkoKGRldmZuKSAmIEdFTk1BU0soNywgMCkp DQorI2RlZmluZSBQQ0lFX0NGR19CVVMoYnVzKQkJKCgoYnVzKSA8PCA4KSAmIEdFTk1BU0soMTUs IDgpKQ0KKyNkZWZpbmUgUENJRV9DRkdfQllURV9FTihieXRlcykJCSgoKGJ5dGVzKSA8PCAxNikg JiBHRU5NQVNLKDE5LCAxNikpDQorI2RlZmluZSBQQ0lFX0NGR19GT1JDRV9CWVRFX0VOCQlCSVQo MjApDQorI2RlZmluZSBQQ0lFX0NGR19PRkZTRVRfQUREUgkJMHgxMDAwDQorI2RlZmluZSBQQ0lF X0NGR19IRUFERVIoZGV2Zm4sIGJ1cykgXA0KKwkoUENJRV9DRkdfREVWRk4oZGV2Zm4pIHwgUENJ RV9DRkdfQlVTKGJ1cykpDQorDQorI2RlZmluZSBQQ0lFX0NGR19IRUFERVJfRk9SQ0VfQkUoZGV2 Zm4sIGJ1cywgYnl0ZXMpIFwNCisJKFBDSUVfQ0ZHX0hFQURFUihkZXZmbiwgYnVzKSB8IFBDSUVf Q0ZHX0JZVEVfRU4oYnl0ZXMpIFwNCisJIHwgUENJRV9DRkdfRk9SQ0VfQllURV9FTikNCisNCisj ZGVmaW5lIFBDSUVfUlNUX0NUUkxfUkVHCQkweDE0OA0KKyNkZWZpbmUgUENJRV9NQUNfUlNUQgkJ CUJJVCgwKQ0KKyNkZWZpbmUgUENJRV9QSFlfUlNUQgkJCUJJVCgxKQ0KKyNkZWZpbmUgUENJRV9C UkdfUlNUQgkJCUJJVCgyKQ0KKyNkZWZpbmUgUENJRV9QRV9SU1RCCQkJQklUKDMpDQorDQorI2Rl ZmluZSBQQ0lFX01JU0NfU1RBVFVTX1JFRwkJMHgxNEMNCisjZGVmaW5lIFBDSUVfTFRSX01TR19S RUNFSVZFRAkJQklUKDApDQorI2RlZmluZSBQQ0lFX1BDSUVfTVNHX1JFQ0VJVkVECQlCSVQoMSkN CisNCisjZGVmaW5lIFBDSUVfTFRTU01fU1RBVFVTX1JFRwkJMHgxNTANCisjZGVmaW5lIFBDSUVf TFRTU01fU1RBVEVfTUFTSwkJR0VOTUFTSygyOCwgMjQpDQorI2RlZmluZSBQQ0lFX0xUU1NNX1NU QVRFKHZhbCkJCSgodmFsICYgUENJRV9MVFNTTV9TVEFURV9NQVNLKSA+PiAyNCkNCisjZGVmaW5l IFBDSUVfTFRTU01fU1RBVEVfTDAJCTB4MTANCisjZGVmaW5lIFBDSUVfTFRTU01fU1RBVEVfTDFf SURMRQkweDEzDQorI2RlZmluZSBQQ0lFX0xUU1NNX1NUQVRFX0wyX0lETEUJMHgxNA0KKw0KKyNk ZWZpbmUgUENJRV9MSU5LX1NUQVRVU19SRUcJCTB4MTU0DQorI2RlZmluZSBQQ0lFX1BPUlRfTElO S1VQCQlCSVQoOCkNCisNCisjZGVmaW5lIFBDSUVfTVNJX1NFVF9OVU0JCTgNCisjZGVmaW5lIFBD SUVfTVNJX0lSUVNfUEVSX1NFVAkJMzINCisjZGVmaW5lIFBDSUVfTVNJX0lSUVNfTlVNIFwNCisJ KFBDSUVfTVNJX0lSUVNfUEVSX1NFVCAqIChQQ0lFX01TSV9TRVRfTlVNKSkNCisNCisjZGVmaW5l IFBDSUVfSU5UX0VOQUJMRV9SRUcJCTB4MTgwDQorI2RlZmluZSBQQ0lFX01TSV9NQVNLCQkJR0VO TUFTSyhQQ0lFX01TSV9TRVRfTlVNICsgOCAtIDEsIDgpDQorI2RlZmluZSBQQ0lFX01TSV9TSElG VAkJCTgNCisjZGVmaW5lIFBDSUVfSU5UWF9TSElGVAkJCTI0DQorI2RlZmluZSBQQ0lFX0lOVFhf TUFTSwkJCUdFTk1BU0soMjcsIDI0KQ0KKyNkZWZpbmUgUENJRV9NU0dfTUFTSwkJCUJJVCgyOCkN CisjZGVmaW5lIFBDSUVfQUVSX01BU0sJCQlCSVQoMjkpDQorI2RlZmluZSBQQ0lFX1BNX01BU0sJ CQlCSVQoMzApDQorDQorI2RlZmluZSBQQ0lFX0lOVF9TVEFUVVNfUkVHCQkweDE4NA0KKyNkZWZp bmUgUENJRV9NU0lfU0VUX0VOQUJMRV9SRUcJCTB4MTkwDQorDQorI2RlZmluZSBQQ0lFX0xPV19Q T1dFUl9DVFJMX1JFRwkJMHgxOTQNCisjZGVmaW5lIFBDSUVfRElTX0xPV1BXUl9NQVNLCQlHRU5N QVNLKDMsIDApDQorI2RlZmluZSBQQ0lFX0RJU19MMFNfTUFTSwkJQklUKDApDQorI2RlZmluZSBQ Q0lFX0RJU19MMV9NQVNLCQlCSVQoMSkNCisjZGVmaW5lIFBDSUVfRElTX0wxMV9NQVNLCQlCSVQo MikNCisjZGVmaW5lIFBDSUVfRElTX0wxMl9NQVNLCQlCSVQoMykNCisjZGVmaW5lIFBDSUVfRk9S Q0VfRElTX0xPV1BXUgkJR0VOTUFTSygxMSwgOCkNCisjZGVmaW5lIFBDSUVfRk9SQ0VfRElTX0ww UwkJQklUKDgpDQorI2RlZmluZSBQQ0lFX0ZPUkNFX0RJU19MMQkJQklUKDkpDQorI2RlZmluZSBQ Q0lFX0ZPUkNFX0RJU19MMTEJCUJJVCgxMCkNCisjZGVmaW5lIFBDSUVfRk9SQ0VfRElTX0wxMgkJ QklUKDExKQ0KKw0KKyNkZWZpbmUgUENJRV9JQ01EX1BNX1JFRwkJMHgxOTgNCisjZGVmaW5lIFBD SUVfVFVSTl9PRkZfTElOSwkJQklUKDQpDQorDQorI2RlZmluZSBQQ0lFX01TSV9BRERSX0JBU0Vf UkVHCQkweGMwMA0KKyNkZWZpbmUgUENJRV9NU0lfU0VUX09GRlNFVAkJMHgxMA0KKyNkZWZpbmUg UENJRV9NU0lfU1RBVFVTX09GRlNFVAkJMHgwNA0KKyNkZWZpbmUgUENJRV9NU0lfRU5BQkxFX09G RlNFVAkJMHgwOA0KKw0KKyNkZWZpbmUgUENJRV9UUkFOU19UQUJMRV9CQVNFX1JFRwkweDgwMA0K KyNkZWZpbmUgUENJRV9BVFJfU1JDX0FERFJfTVNCX09GRlNFVAkweDQNCisjZGVmaW5lIFBDSUVf QVRSX1RSU0xfQUREUl9MU0JfT0ZGU0VUCTB4OA0KKyNkZWZpbmUgUENJRV9BVFJfVFJTTF9BRERS X01TQl9PRkZTRVQJMHhjDQorI2RlZmluZSBQQ0lFX0FUUl9UUlNMX1BBUkFNX09GRlNFVAkweDEw DQorI2RlZmluZSBQQ0lFX0FUUl9UTEJfU0VUX09GRlNFVAkJMHgyMA0KKw0KKyNkZWZpbmUgUENJ RV9NQVhfVFJBTlNfVEFCTEVTCQk4DQorI2RlZmluZSBBVFJfRU4JCQkJQklUKDApDQorI2RlZmlu ZSBBVFJfU0laRShzaXplKQkJCSgoKChzaXplKSAtIDEpIDw8IDEpICYgR0VOTUFTSyg2LCAxKSkN CisjZGVmaW5lIEFUUl9JRChpZCkJCQkoaWQgJiBHRU5NQVNLKDMsIDApKQ0KKyNkZWZpbmUgQVRS X1BBUkFNKHBhcmFtKQkJKCgocGFyYW0pIDw8IDE2KSAmIEdFTk1BU0soMjcsIDE2KSkNCisNCisv KioNCisgKiBzdHJ1Y3QgbXRrX3BjaWVfbXNpIC0gTVNJIGluZm9ybWF0aW9uIGZvciBlYWNoIHNl dA0KKyAqIEBiYXNlOiBJTyBtYXBwZWQgcmVnaXN0ZXIgYmFzZQ0KKyAqIEBod2lycTogSGFyZHdh cmUgaW50ZXJydXB0IG51bWJlcg0KKyAqIEBpcnE6IE1TSSBzZXQgSW50ZXJydXB0IG51bWJlcg0K KyAqIEBpbmRleDogTVNJIHNldCBudW1iZXINCisgKiBAbXNnX2FkZHI6IE1TSSBtZXNzYWdlIGFk ZHJlc3MNCisgKiBAZG9tYWluOiBJUlEgZG9tYWluDQorICovDQorc3RydWN0IG10a19wY2llX21z aSB7DQorCXZvaWQgX19pb21lbSAqYmFzZTsNCisJaW50IGh3aXJxOw0KKwlpbnQgaXJxOw0KKwlp bnQgaW5kZXg7DQorCXBoeXNfYWRkcl90IG1zZ19hZGRyOw0KKwlzdHJ1Y3QgaXJxX2RvbWFpbiAq ZG9tYWluOw0KK307DQorDQorLyoqDQorICogc3RydWN0IG10a19wY2llX3BvcnQgLSBQQ0llIHBv cnQgaW5mb3JtYXRpb24NCisgKiBAZGV2OiBQQ0llIGRldmljZQ0KKyAqIEBiYXNlOiBJTyBtYXBw ZWQgcmVnaXN0ZXIgYmFzZQ0KKyAqIEByZWdfYmFzZTogUGh5c2ljYWwgcmVnaXN0ZXIgYmFzZQ0K KyAqIEBtYWNfcmVzZXQ6IG1hYyByZXNldCBjb250cm9sDQorICogQHBoeV9yZXNldDogcGh5IHJl c2V0IGNvbnRyb2wNCisgKiBAcGh5OiBQSFkgY29udHJvbGxlciBibG9jaw0KKyAqIEBjbGtzOiBQ Q0llIGNsb2Nrcw0KKyAqIEBudW1fY2xrczogUENJZSBjbG9ja3MgY291bnQgZm9yIHRoaXMgcG9y dA0KKyAqIEBpc19zdXNwZW5kZWQ6IGRldmljZSBzdXNwZW5kIHN0YXRlDQorICogQGlycTogUENJ ZSBjb250cm9sbGVyIGludGVycnVwdCBudW1iZXINCisgKiBAaW50eF9kb21haW46IGxlZ2FjeSBJ TlR4IElSUSBkb21haW4NCisgKiBAbXNpX2RvbWFpbjogTVNJIElSUSBkb21haW4NCisgKiBAbXNp X3RvcF9kb21haW46IE1TSSBJUlEgdG9wIGRvbWFpbg0KKyAqIEBtc2lfaW5mbzogTVNJIHNldHMg aW5mb3JtYXRpb24NCisgKiBAbG9jazogbG9jayBwcm90ZWN0aW5nIElSUSBiaXQgbWFwDQorICog QG1zaV9pcnFfaW5fdXNlOiBiaXQgbWFwIGZvciBhc3NpZ25lZCBNU0kgSVJRDQorICovDQorc3Ry dWN0IG10a19wY2llX3BvcnQgew0KKwlzdHJ1Y3QgZGV2aWNlICpkZXY7DQorCXZvaWQgX19pb21l bSAqYmFzZTsNCisJcGh5c19hZGRyX3QgcmVnX2Jhc2U7DQorCXN0cnVjdCByZXNldF9jb250cm9s ICptYWNfcmVzZXQ7DQorCXN0cnVjdCByZXNldF9jb250cm9sICpwaHlfcmVzZXQ7DQorCXN0cnVj dCBwaHkgKnBoeTsNCisJc3RydWN0IGNsa19idWxrX2RhdGEgKmNsa3M7DQorCWludCBudW1fY2xr czsNCisJYm9vbCBpc19zdXNwZW5kZWQ7DQorDQorCWludCBpcnE7DQorCXN0cnVjdCBpcnFfZG9t YWluICppbnR4X2RvbWFpbjsNCisJc3RydWN0IGlycV9kb21haW4gKm1zaV9kb21haW47DQorCXN0 cnVjdCBpcnFfZG9tYWluICptc2lfdG9wX2RvbWFpbjsNCisJc3RydWN0IG10a19wY2llX21zaSAq Km1zaV9pbmZvOw0KKwlzdHJ1Y3QgbXV0ZXggbG9jazsNCisJREVDTEFSRV9CSVRNQVAobXNpX2ly cV9pbl91c2UsIFBDSUVfTVNJX0lSUVNfTlVNKTsNCit9Ow0KKw0KK3N0YXRpYyBpbnQgbXRrX3Bj aWVfY29uZmlnX3JlYWQoc3RydWN0IHBjaV9idXMgKmJ1cywgdW5zaWduZWQgaW50IGRldmZuLA0K KwkJCQkgICAgaW50IHdoZXJlLCBpbnQgc2l6ZSwgdTMyICp2YWwpDQorew0KKwlzdHJ1Y3QgbXRr X3BjaWVfcG9ydCAqcG9ydCA9IGJ1cy0+c3lzZGF0YTsNCisJaW50IGJ5dGVzOw0KKw0KKwlieXRl cyA9ICgoMSA8PCBzaXplKSAtIDEpIDw8ICh3aGVyZSAmIDB4Myk7DQorCXdyaXRlbChQQ0lFX0NG R19IRUFERVJfRk9SQ0VfQkUoZGV2Zm4sIGJ1cy0+bnVtYmVyLCBieXRlcyksDQorCSAgICAgICBw b3J0LT5iYXNlICsgUENJRV9DRkdOVU1fUkVHKTsNCisNCisJKnZhbCA9IHJlYWRsKHBvcnQtPmJh c2UgKyBQQ0lFX0NGR19PRkZTRVRfQUREUiArICh3aGVyZSAmIH4weDMpKTsNCisNCisJaWYgKHNp emUgPD0gMikNCisJCSp2YWwgPSAoKnZhbCA+PiAoOCAqICh3aGVyZSAmIDB4MykpKSAmICgoMSA8 PCAoc2l6ZSAqIDgpKSAtIDEpOw0KKw0KKwlyZXR1cm4gUENJQklPU19TVUNDRVNTRlVMOw0KK30N CisNCitzdGF0aWMgaW50IG10a19wY2llX2NvbmZpZ193cml0ZShzdHJ1Y3QgcGNpX2J1cyAqYnVz LCB1bnNpZ25lZCBpbnQgZGV2Zm4sDQorCQkJCSAgICAgaW50IHdoZXJlLCBpbnQgc2l6ZSwgdTMy IHZhbCkNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0ID0gYnVzLT5zeXNkYXRhOw0K KwlpbnQgYnl0ZXM7DQorDQorCWJ5dGVzID0gKCgxIDw8IHNpemUpIC0gMSkgPDwgKHdoZXJlICYg MHgzKTsNCisJd3JpdGVsKFBDSUVfQ0ZHX0hFQURFUl9GT1JDRV9CRShkZXZmbiwgYnVzLT5udW1i ZXIsIGJ5dGVzKSwNCisJICAgICAgIHBvcnQtPmJhc2UgKyBQQ0lFX0NGR05VTV9SRUcpOw0KKw0K KwlpZiAoc2l6ZSA8PSAyKQ0KKwkJdmFsID0gKHZhbCAmICgoMSA8PCAoc2l6ZSAqIDgpKSAtIDEp KSA8PCAoKHdoZXJlICYgMHgzKSAqIDgpOw0KKw0KKwl3cml0ZWwodmFsLCBwb3J0LT5iYXNlICsg UENJRV9DRkdfT0ZGU0VUX0FERFIgKyAod2hlcmUgJiB+MHgzKSk7DQorDQorCXJldHVybiBQQ0lC SU9TX1NVQ0NFU1NGVUw7DQorfQ0KKw0KK3N0YXRpYyBzdHJ1Y3QgcGNpX29wcyBtdGtfcGNpZV9v cHMgPSB7DQorCS5yZWFkICA9IG10a19wY2llX2NvbmZpZ19yZWFkLA0KKwkud3JpdGUgPSBtdGtf cGNpZV9jb25maWdfd3JpdGUsDQorfTsNCisNCitzdGF0aWMgdm9pZCBtdGtfcGNpZV9zZXRfdHJh bnNfd2luZG93KHZvaWQgX19pb21lbSAqcmVnLA0KKwkJCQkgICAgICByZXNvdXJjZV9zaXplX3Qg Y3B1X2FkZHIsDQorCQkJCSAgICAgIHJlc291cmNlX3NpemVfdCBwY2lfYWRkciwgc2l6ZV90IHNp emUpDQorew0KKwl3cml0ZWwobG93ZXJfMzJfYml0cyhjcHVfYWRkcikgfCBBVFJfU0laRShmbHMo c2l6ZSkgLSAxKSB8IEFUUl9FTiwgcmVnKTsNCisJd3JpdGVsKHVwcGVyXzMyX2JpdHMoY3B1X2Fk ZHIpLCByZWcgKyBQQ0lFX0FUUl9TUkNfQUREUl9NU0JfT0ZGU0VUKTsNCisJd3JpdGVsKGxvd2Vy XzMyX2JpdHMocGNpX2FkZHIpLCByZWcgKyBQQ0lFX0FUUl9UUlNMX0FERFJfTFNCX09GRlNFVCk7 DQorCXdyaXRlbCh1cHBlcl8zMl9iaXRzKHBjaV9hZGRyKSwgcmVnICsgUENJRV9BVFJfVFJTTF9B RERSX01TQl9PRkZTRVQpOw0KKwl3cml0ZWwoQVRSX0lEKDApIHwgQVRSX1BBUkFNKDApLCByZWcg KyBQQ0lFX0FUUl9UUlNMX1BBUkFNX09GRlNFVCk7DQorfQ0KKw0KK3N0YXRpYyBpbnQgbXRrX3Bj aWVfc2V0X3RyYW5zX3RhYmxlKHZvaWQgX19pb21lbSAqcmVnLA0KKwkJCQkgICAgcmVzb3VyY2Vf c2l6ZV90IGNwdV9hZGRyLA0KKwkJCQkgICAgcmVzb3VyY2Vfc2l6ZV90IHBjaV9hZGRyLCBzaXpl X3Qgc2l6ZSwNCisJCQkJICAgIGludCBudW0pDQorew0KKwl2b2lkIF9faW9tZW0gKnRhYmxlX2Jh c2U7DQorDQorCWlmIChudW0gPiBQQ0lFX01BWF9UUkFOU19UQUJMRVMpDQorCQlyZXR1cm4gLUVO T0RFVjsNCisNCisJdGFibGVfYmFzZSA9IHJlZyArIG51bSAqIFBDSUVfQVRSX1RMQl9TRVRfT0ZG U0VUOw0KKwltdGtfcGNpZV9zZXRfdHJhbnNfd2luZG93KHRhYmxlX2Jhc2UsIGNwdV9hZGRyLCBw Y2lfYWRkciwgc2l6ZSk7DQorDQorCXJldHVybiAwOw0KK30NCisNCitzdGF0aWMgaW50IG10a19w Y2llX3N0YXJ0dXBfcG9ydChzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCkNCit7DQorCXN0cnVj dCByZXNvdXJjZV9lbnRyeSAqZW50cnk7DQorCXN0cnVjdCBwY2lfaG9zdF9icmlkZ2UgKmhvc3Qg PSBwY2lfaG9zdF9icmlkZ2VfZnJvbV9wcml2KHBvcnQpOw0KKwl1MzIgdmFsOw0KKwlpbnQgZXJy ID0gMCwgdGFibGVfaW5kZXggPSAwOw0KKw0KKwkvKiBTZXQgYXMgUkMgbW9kZSAqLw0KKwl2YWwg PSByZWFkbChwb3J0LT5iYXNlICsgUENJRV9TRVRUSU5HX1JFRyk7DQorCXZhbCB8PSBQQ0lFX1JD X01PREU7DQorCXdyaXRlbCh2YWwsIHBvcnQtPmJhc2UgKyBQQ0lFX1NFVFRJTkdfUkVHKTsNCisN CisJLyogU2V0IGNsYXNzIGNvZGUgKi8NCisJdmFsID0gcmVhZGwocG9ydC0+YmFzZSArIFBDSUVf UENJX0lEU18xKTsNCisJdmFsICY9IH5HRU5NQVNLKDMxLCA4KTsNCisJdmFsIHw9IFBDSV9DTEFT UyhQQ0lfQ0xBU1NfQlJJREdFX1BDSSA8PCA4KTsNCisJd3JpdGVsKHZhbCwgcG9ydC0+YmFzZSAr IFBDSUVfUENJX0lEU18xKTsNCisNCisJLyogQXNzZXJ0IGFsbCByZXNldCBzaWduYWxzICovDQor CXZhbCA9IHJlYWRsKHBvcnQtPmJhc2UgKyBQQ0lFX1JTVF9DVFJMX1JFRyk7DQorCXZhbCB8PSBQ Q0lFX01BQ19SU1RCIHwgUENJRV9QSFlfUlNUQiB8IFBDSUVfQlJHX1JTVEIgfCBQQ0lFX1BFX1JT VEI7DQorCXdyaXRlbCh2YWwsIHBvcnQtPmJhc2UgKyBQQ0lFX1JTVF9DVFJMX1JFRyk7DQorDQor CS8qIERlLWFzc2VydCByZXNldCBzaWduYWxzKi8NCisJdmFsICY9IH4oUENJRV9NQUNfUlNUQiB8 IFBDSUVfUEhZX1JTVEIgfCBQQ0lFX0JSR19SU1RCKTsNCisJd3JpdGVsKHZhbCwgcG9ydC0+YmFz ZSArIFBDSUVfUlNUX0NUUkxfUkVHKTsNCisNCisJLyogRGVsYXkgMTAwbXMgdG8gd2FpdCB0aGUg cmVmZXJlbmNlIGNsb2NrcyBiZWNvbWUgc3RhYmxlICovDQorCXVzbGVlcF9yYW5nZSgxMDAgKiAx MDAwLCAxMjAgKiAxMDAwKTsNCisNCisJLyogRGUtYXNzZXJ0IHBlIHJlc2V0Ki8NCisJdmFsICY9 IH5QQ0lFX1BFX1JTVEI7DQorCXdyaXRlbCh2YWwsIHBvcnQtPmJhc2UgKyBQQ0lFX1JTVF9DVFJM X1JFRyk7DQorDQorCS8qIENoZWNrIGlmIHRoZSBsaW5rIGlzIHVwIG9yIG5vdCAqLw0KKwllcnIg PSByZWFkbF9wb2xsX3RpbWVvdXQocG9ydC0+YmFzZSArIFBDSUVfTElOS19TVEFUVVNfUkVHLCB2 YWwsDQorCQkJISEodmFsICYgUENJRV9QT1JUX0xJTktVUCksIDIwLA0KKwkJCTUwICogVVNFQ19Q RVJfTVNFQyk7DQorCWlmIChlcnIpDQorCQlyZXR1cm4gZXJyOw0KKw0KKwkvKiBTZXQgUENJZSB0 cmFuc2xhdGlvbiB3aW5kb3dzICovDQorCXJlc291cmNlX2xpc3RfZm9yX2VhY2hfZW50cnkoZW50 cnksICZob3N0LT53aW5kb3dzKSB7DQorCQl1bnNpZ25lZCBsb25nIHR5cGUgPSByZXNvdXJjZV90 eXBlKGVudHJ5LT5yZXMpOw0KKwkJc3RydWN0IHJlc291cmNlICpyZXMgPSBOVUxMOw0KKwkJcmVz b3VyY2Vfc2l6ZV90IGNwdV9hZGRyOw0KKwkJcmVzb3VyY2Vfc2l6ZV90IHBjaV9hZGRyOw0KKw0K KwkJaWYgKCEodHlwZSAmIChJT1JFU09VUkNFX01FTSB8IElPUkVTT1VSQ0VfSU8pKSkNCisJCQlj b250aW51ZTsNCisNCisJCXJlcyA9IGVudHJ5LT5yZXM7DQorCQljcHVfYWRkciA9IHJlcy0+c3Rh cnQ7DQorCQlwY2lfYWRkciA9IHJlcy0+c3RhcnQgLSBlbnRyeS0+b2Zmc2V0Ow0KKwkJbXRrX3Bj aWVfc2V0X3RyYW5zX3RhYmxlKHBvcnQtPmJhc2UgKyBQQ0lFX1RSQU5TX1RBQkxFX0JBU0VfUkVH LA0KKwkJCQkJIGNwdV9hZGRyLCBwY2lfYWRkciwgcmVzb3VyY2Vfc2l6ZShyZXMpLA0KKwkJCQkJ IHRhYmxlX2luZGV4KTsNCisNCisJCWRldl9kYmcocG9ydC0+ZGV2LCAiU2V0ICVzIHRyYW5zIHdp bmRvd1slZF06IGNwdV9hZGRyID0gJSNsbHgsIHBjaV9hZGRyID0gJSNsbHgsIHNpemUgPSAlI2xs eFxuIiwNCisJCQkoISEodHlwZSAmIElPUkVTT1VSQ0VfTUVNKSA/ICJNRU0iIDogIklPIiksIHRh YmxlX2luZGV4LA0KKwkJCWNwdV9hZGRyLCBwY2lfYWRkciwgcmVzb3VyY2Vfc2l6ZShyZXMpKTsN CisNCisJCXRhYmxlX2luZGV4Kys7DQorCX0NCisNCisJcmV0dXJuIDA7DQorfQ0KKw0KK3N0YXRp YyBpbmxpbmUgc3RydWN0IG10a19wY2llX21zaSAqbXRrX2dldF9tc2lfaW5mbyhzdHJ1Y3QgbXRr X3BjaWVfcG9ydCAqcG9ydCwNCisJCQkJCSAgICAgdW5zaWduZWQgaW50IGh3aXJxKQ0KK3sNCisJ cmV0dXJuIHBvcnQtPm1zaV9pbmZvW2h3aXJxIC8gUENJRV9NU0lfSVJRU19QRVJfU0VUXTsNCit9 DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9zZXRfYWZmaW5pdHkoc3RydWN0IGlycV9kYXRhICpk YXRhLA0KKwkJCQkgY29uc3Qgc3RydWN0IGNwdW1hc2sgKm1hc2ssIGJvb2wgZm9yY2UpDQorew0K KwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9IGlycV9kYXRhX2dldF9pcnFfY2hpcF9kYXRh KGRhdGEpOw0KKwlpbnQgcmV0Ow0KKw0KKwlyZXQgPSBpcnFfc2V0X2FmZmluaXR5X2hpbnQocG9y dC0+aXJxLCBtYXNrKTsNCisJaWYgKHJldCkNCisJCXJldHVybiByZXQ7DQorDQorCWlycV9kYXRh X3VwZGF0ZV9lZmZlY3RpdmVfYWZmaW5pdHkoZGF0YSwgbWFzayk7DQorDQorCXJldHVybiAwOw0K K30NCisNCitzdGF0aWMgdm9pZCBtdGtfY29tcG9zZV9tc2lfbXNnKHN0cnVjdCBpcnFfZGF0YSAq ZGF0YSwgc3RydWN0IG1zaV9tc2cgKm1zZykNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9tc2kgKm1z aV9pbmZvOw0KKwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9IGlycV9kYXRhX2dldF9pcnFf Y2hpcF9kYXRhKGRhdGEpOw0KKw0KKwltc2lfaW5mbyA9IG10a19nZXRfbXNpX2luZm8ocG9ydCwg ZGF0YS0+aHdpcnEpOw0KKw0KKwltc2ctPmFkZHJlc3NfaGkgPSAwOw0KKwltc2ctPmFkZHJlc3Nf bG8gPSBsb3dlcl8zMl9iaXRzKG1zaV9pbmZvLT5tc2dfYWRkcik7DQorDQorCW1zZy0+ZGF0YSA9 IGRhdGEtPmh3aXJxOw0KKwlkZXZfZGJnKHBvcnQtPmRldiwgIm1zaSMlI2x4IGFkZHJlc3NfaGkg JSN4IGFkZHJlc3NfbG8gJSN4IGRhdGEgJWRcbiIsDQorCQlkYXRhLT5od2lycSwgbXNnLT5hZGRy ZXNzX2hpLCBtc2ctPmFkZHJlc3NfbG8sIG1zZy0+ZGF0YSk7DQorfQ0KKw0KK3N0YXRpYyB2b2lk IG10a19tc2lfaXJxX2FjayhzdHJ1Y3QgaXJxX2RhdGEgKmRhdGEpDQorew0KKwlzdHJ1Y3QgbXRr X3BjaWVfbXNpICptc2lfaW5mbzsNCisJc3RydWN0IG10a19wY2llX3BvcnQgKnBvcnQgPSBpcnFf ZGF0YV9nZXRfaXJxX2NoaXBfZGF0YShkYXRhKTsNCisJaW50IGh3aXJxOw0KKw0KKwltc2lfaW5m byA9IG10a19nZXRfbXNpX2luZm8ocG9ydCwgZGF0YS0+aHdpcnEpOw0KKw0KKwlod2lycSA9CWRh dGEtPmh3aXJxICUgUENJRV9NU0lfSVJRU19QRVJfU0VUOw0KKw0KKwl3cml0ZWwoMSA8PCBod2ly cSwgbXNpX2luZm8tPmJhc2UgKyBQQ0lFX01TSV9TVEFUVVNfT0ZGU0VUKTsNCit9DQorDQorc3Rh dGljIHZvaWQgbXRrX21zaV9pcnFfbWFzayhzdHJ1Y3QgaXJxX2RhdGEgKmRhdGEpDQorew0KKwlz dHJ1Y3QgbXRrX3BjaWVfbXNpICptc2lfaW5mbzsNCisJc3RydWN0IG10a19wY2llX3BvcnQgKnBv cnQgPSBpcnFfZGF0YV9nZXRfaXJxX2NoaXBfZGF0YShkYXRhKTsNCisJaW50IHZhbDsNCisNCisJ bXNpX2luZm8gPSBtdGtfZ2V0X21zaV9pbmZvKHBvcnQsIGRhdGEtPmh3aXJxKTsNCisJdmFsID0g cmVhZGwobXNpX2luZm8tPmJhc2UgKyBQQ0lFX01TSV9FTkFCTEVfT0ZGU0VUKTsNCisJdmFsICY9 IH4oMSA8PCBkYXRhLT5od2lycSk7DQorCXdyaXRlbCh2YWwsIG1zaV9pbmZvLT5iYXNlICsgUENJ RV9NU0lfRU5BQkxFX09GRlNFVCk7DQorDQorCXBjaV9tc2lfbWFza19pcnEoZGF0YSk7DQorfQ0K Kw0KK3N0YXRpYyB2b2lkIG10a19tc2lfaXJxX3VubWFzayhzdHJ1Y3QgaXJxX2RhdGEgKmRhdGEp DQorew0KKwlzdHJ1Y3QgbXRrX3BjaWVfbXNpICptc2lfaW5mbzsNCisJc3RydWN0IG10a19wY2ll X3BvcnQgKnBvcnQgPSBpcnFfZGF0YV9nZXRfaXJxX2NoaXBfZGF0YShkYXRhKTsNCisJaW50IHZh bDsNCisNCisJbXNpX2luZm8gPSBtdGtfZ2V0X21zaV9pbmZvKHBvcnQsIGRhdGEtPmh3aXJxKTsN CisJdmFsID0gcmVhZGwobXNpX2luZm8tPmJhc2UgKyBQQ0lFX01TSV9FTkFCTEVfT0ZGU0VUKTsN CisJdmFsIHw9ICgxIDw8IGRhdGEtPmh3aXJxKTsNCisJd3JpdGVsKHZhbCwgbXNpX2luZm8tPmJh c2UgKyBQQ0lFX01TSV9FTkFCTEVfT0ZGU0VUKTsNCisNCisJcGNpX21zaV91bm1hc2tfaXJxKGRh dGEpOw0KK30NCisNCitzdGF0aWMgc3RydWN0IGlycV9jaGlwIG10a19tc2lfaXJxX2NoaXAgPSB7 DQorCS5pcnFfYWNrCQk9IG10a19tc2lfaXJxX2FjaywNCisJLmlycV9jb21wb3NlX21zaV9tc2cJ PSBtdGtfY29tcG9zZV9tc2lfbXNnLA0KKwkuaXJxX21hc2sJCT0gbXRrX21zaV9pcnFfbWFzaywN CisJLmlycV91bm1hc2sJCT0gbXRrX21zaV9pcnFfdW5tYXNrLA0KKwkuaXJxX3NldF9hZmZpbml0 eQk9IG10a19wY2llX3NldF9hZmZpbml0eSwNCisJLm5hbWUJCQk9ICJQQ0llIiwNCit9Ow0KKw0K K3N0YXRpYyBpcnFfaHdfbnVtYmVyX3QgbXRrX3BjaWVfbXNpX2dldF9od2lycShzdHJ1Y3QgbXNp X2RvbWFpbl9pbmZvICppbmZvLA0KKwkJCQkJICAgICAgbXNpX2FsbG9jX2luZm9fdCAqYXJnKQ0K K3sNCisJc3RydWN0IG1zaV9kZXNjICplbnRyeSA9IGFyZy0+ZGVzYzsNCisJc3RydWN0IG10a19w Y2llX3BvcnQgKnBvcnQgPSBpbmZvLT5jaGlwX2RhdGE7DQorCWludCBod2lycTsNCisNCisJbXV0 ZXhfbG9jaygmcG9ydC0+bG9jayk7DQorDQorCWh3aXJxID0gYml0bWFwX2ZpbmRfZnJlZV9yZWdp b24ocG9ydC0+bXNpX2lycV9pbl91c2UsIFBDSUVfTVNJX0lSUVNfTlVNLA0KKwkJCW9yZGVyX2Jh c2VfMihlbnRyeS0+bnZlY191c2VkKSk7DQorCWlmIChod2lycSA8IDApIHsNCisJCW11dGV4X3Vu bG9jaygmcG9ydC0+bG9jayk7DQorCQlyZXR1cm4gLUVOT1NQQzsNCisJfQ0KKw0KKwltdXRleF91 bmxvY2soJnBvcnQtPmxvY2spOw0KKw0KKwlyZXR1cm4gaHdpcnE7DQorfQ0KKw0KK3N0YXRpYyB2 b2lkIG10a19wY2llX21zaV9mcmVlKHN0cnVjdCBpcnFfZG9tYWluICpkb21haW4sDQorCQkJICAg ICAgc3RydWN0IG1zaV9kb21haW5faW5mbyAqaW5mbywgdW5zaWduZWQgaW50IHZpcnEpDQorew0K KwlzdHJ1Y3QgaXJxX2RhdGEgKmRhdGEgPSBpcnFfZG9tYWluX2dldF9pcnFfZGF0YShkb21haW4s IHZpcnEpOw0KKwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9IGlycV9kYXRhX2dldF9pcnFf Y2hpcF9kYXRhKGRhdGEpOw0KKw0KKwltdXRleF9sb2NrKCZwb3J0LT5sb2NrKTsNCisNCisJYml0 bWFwX2NsZWFyKHBvcnQtPm1zaV9pcnFfaW5fdXNlLCBkYXRhLT5od2lycSwgMSk7DQorDQorCW11 dGV4X3VubG9jaygmcG9ydC0+bG9jayk7DQorfQ0KKw0KK3N0YXRpYyBzdHJ1Y3QgbXNpX2RvbWFp bl9vcHMgbXRrX21zaV9kb21haW5fb3BzID0gew0KKwkuZ2V0X2h3aXJxCT0gbXRrX3BjaWVfbXNp X2dldF9od2lycSwNCisJLm1zaV9mcmVlCT0gbXRrX3BjaWVfbXNpX2ZyZWUsDQorfTsNCisNCitz dGF0aWMgc3RydWN0IG1zaV9kb21haW5faW5mbyBtdGtfbXNpX2RvbWFpbl9pbmZvID0gew0KKwku ZmxhZ3MJCT0gKE1TSV9GTEFHX1VTRV9ERUZfRE9NX09QUyB8IE1TSV9GTEFHX1BDSV9NU0lYIHwN CisJCQkgICBNU0lfRkxBR19VU0VfREVGX0NISVBfT1BTIHwgTVNJX0ZMQUdfTVVMVElfUENJX01T SSksDQorCS5jaGlwCQk9ICZtdGtfbXNpX2lycV9jaGlwLA0KKwkub3BzCQk9ICZtdGtfbXNpX2Rv bWFpbl9vcHMsDQorCS5oYW5kbGVyCT0gaGFuZGxlX2VkZ2VfaXJxLA0KKwkuaGFuZGxlcl9uYW1l CT0gIk1TSSIsDQorfTsNCisNCitzdGF0aWMgdm9pZCBtdGtfbXNpX3RvcF9pcnFfZW9pKHN0cnVj dCBpcnFfZGF0YSAqZGF0YSkNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0ID0gaXJx X2RhdGFfZ2V0X2lycV9jaGlwX2RhdGEoZGF0YSk7DQorCWludCBtc2lfaXJxID0gZGF0YS0+aHdp cnEgKyBQQ0lFX01TSV9TSElGVDsNCisNCisJd3JpdGVsKDEgPDwgbXNpX2lycSwgcG9ydC0+YmFz ZSArIFBDSUVfSU5UX1NUQVRVU19SRUcpOw0KK30NCisNCitzdGF0aWMgc3RydWN0IGlycV9jaGlw IG10a19tc2lfdG9wX2lycV9jaGlwID0gew0KKwkuaXJxX2VvaQk9IG10a19tc2lfdG9wX2lycV9l b2ksDQorCS5uYW1lCQk9ICJQQ0llIiwNCit9Ow0KKw0KK3N0YXRpYyB2b2lkIG10a19wY2llX21z aV9oYW5kbGVyKHN0cnVjdCBpcnFfZGVzYyAqZGVzYykNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9t c2kgKm1zaV9pbmZvID0gaXJxX2Rlc2NfZ2V0X2hhbmRsZXJfZGF0YShkZXNjKTsNCisJc3RydWN0 IGlycV9jaGlwICppcnFjaGlwID0gaXJxX2Rlc2NfZ2V0X2NoaXAoZGVzYyk7DQorCXVuc2lnbmVk IGxvbmcgbXNpX2VuYWJsZSwgbXNpX3N0YXR1czsNCisJdTMyIHZpcnEsIGJpdCwgaHdpcnE7DQor DQorCWNoYWluZWRfaXJxX2VudGVyKGlycWNoaXAsIGRlc2MpOw0KKw0KKwltc2lfZW5hYmxlID0g cmVhZGwobXNpX2luZm8tPmJhc2UgKyBQQ0lFX01TSV9FTkFCTEVfT0ZGU0VUKTsNCisJd2hpbGUg KChtc2lfc3RhdHVzID0gcmVhZGwobXNpX2luZm8tPmJhc2UgKyBQQ0lFX01TSV9TVEFUVVNfT0ZG U0VUKSkpIHsNCisJCW1zaV9zdGF0dXMgJj0gbXNpX2VuYWJsZTsNCisJCWZvcl9lYWNoX3NldF9i aXQoYml0LCAmbXNpX3N0YXR1cywgUENJRV9NU0lfSVJRU19QRVJfU0VUKSB7DQorCQkJaHdpcnEg PSBiaXQgKyBtc2lfaW5mby0+aW5kZXggKiBQQ0lFX01TSV9JUlFTX1BFUl9TRVQ7DQorCQkJdmly cSA9IGlycV9maW5kX21hcHBpbmcobXNpX2luZm8tPmRvbWFpbiwgaHdpcnEpOw0KKwkJCWdlbmVy aWNfaGFuZGxlX2lycSh2aXJxKTsNCisJCX0NCisJfQ0KKw0KKwljaGFpbmVkX2lycV9leGl0KGly cWNoaXAsIGRlc2MpOw0KK30NCisNCitzdGF0aWMgaW50IG10a19tc2lfdG9wX2RvbWFpbl9tYXAo c3RydWN0IGlycV9kb21haW4gKmRvbWFpbiwNCisJCQkJICAgIHVuc2lnbmVkIGludCB2aXJxLCBp cnFfaHdfbnVtYmVyX3QgaHdpcnEpDQorew0KKwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9 IGRvbWFpbi0+aG9zdF9kYXRhOw0KKwlzdHJ1Y3QgbXRrX3BjaWVfbXNpICptc2lfaW5mbyA9IHBv cnQtPm1zaV9pbmZvW2h3aXJxXTsNCisNCisJaXJxX2RvbWFpbl9zZXRfaW5mbyhkb21haW4sIHZp cnEsIGh3aXJxLA0KKwkJCSAgICAmbXRrX21zaV90b3BfaXJxX2NoaXAsIGRvbWFpbi0+aG9zdF9k YXRhLA0KKwkJCSAgICBtdGtfcGNpZV9tc2lfaGFuZGxlciwgbXNpX2luZm8sIE5VTEwpOw0KKw0K KwlyZXR1cm4gMDsNCit9DQorDQorc3RhdGljIGNvbnN0IHN0cnVjdCBpcnFfZG9tYWluX29wcyBt dGtfbXNpX3RvcF9kb21haW5fb3BzID0gew0KKwkubWFwID0gbXRrX21zaV90b3BfZG9tYWluX21h cCwNCit9Ow0KKw0KK3N0YXRpYyB2b2lkIG10a19pbnR4X21hc2soc3RydWN0IGlycV9kYXRhICpk YXRhKQ0KK3sNCisJc3RydWN0IG10a19wY2llX3BvcnQgKnBvcnQgPSBpcnFfZGF0YV9nZXRfaXJx X2NoaXBfZGF0YShkYXRhKTsNCisJaW50IHZhbDsNCisNCisJdmFsID0gcmVhZGwocG9ydC0+YmFz ZSArIFBDSUVfSU5UX0VOQUJMRV9SRUcpOw0KKwl2YWwgJj0gfigxIDw8IChkYXRhLT5od2lycSAr IFBDSUVfSU5UWF9TSElGVCkpOw0KKwl3cml0ZWwodmFsLCBwb3J0LT5iYXNlICsgUENJRV9JTlRf RU5BQkxFX1JFRyk7DQorfQ0KKw0KK3N0YXRpYyB2b2lkIG10a19pbnR4X3VubWFzayhzdHJ1Y3Qg aXJxX2RhdGEgKmRhdGEpDQorew0KKwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9IGlycV9k YXRhX2dldF9pcnFfY2hpcF9kYXRhKGRhdGEpOw0KKwlpbnQgdmFsOw0KKw0KKwl2YWwgPSByZWFk bChwb3J0LT5iYXNlICsgUENJRV9JTlRfRU5BQkxFX1JFRyk7DQorCXZhbCB8PSAxIDw8IChkYXRh LT5od2lycSArIFBDSUVfSU5UWF9TSElGVCk7DQorCXdyaXRlbCh2YWwsIHBvcnQtPmJhc2UgKyBQ Q0lFX0lOVF9FTkFCTEVfUkVHKTsNCit9DQorDQorc3RhdGljIHZvaWQgbXRrX2ludHhfZW9pKHN0 cnVjdCBpcnFfZGF0YSAqZGF0YSkNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0ID0g aXJxX2RhdGFfZ2V0X2lycV9jaGlwX2RhdGEoZGF0YSk7DQorCWludCBod2lycTsNCisNCisJLyoq DQorCSAqIEFzIGFuIGVtdWxhdGVkIGxldmVsIGlycSwgaXRzIGludGVycnVwdCBzdGF0dXMgd2ls bCBiZSByZW1haW5lZA0KKwkgKiB1bnRpbCByZWNlaXZlIHRoZSBjb3JyZXNwb25kaW5nIG1lc3Nh Z2Ugb2YgZGUtYXNzZXJ0LCBoZW5jZSB0aGF0DQorCSAqIHRoZSBzdGF0dXMgY2FuIG9ubHkgYmUg Y2xlYXJlZCB3aGVuIHRoZSBpbnRlcnJ1cHQgaGFzIGJlZW4gc2VydmljZWQuDQorCSAqLw0KKwlo d2lycSA9IGRhdGEtPmh3aXJxICsgUENJRV9JTlRYX1NISUZUOw0KKwl3cml0ZWwoMSA8PCBod2ly cSwgcG9ydC0+YmFzZSArIFBDSUVfSU5UX1NUQVRVU19SRUcpOw0KK30NCisNCitzdGF0aWMgc3Ry dWN0IGlycV9jaGlwIG10a19pbnR4X2lycV9jaGlwID0gew0KKwkuaXJxX21hc2sJCT0gbXRrX2lu dHhfbWFzaywNCisJLmlycV91bm1hc2sJCT0gbXRrX2ludHhfdW5tYXNrLA0KKwkuaXJxX2VvaQkJ PSBtdGtfaW50eF9lb2ksDQorCS5pcnFfc2V0X2FmZmluaXR5CT0gbXRrX3BjaWVfc2V0X2FmZmlu aXR5LA0KKwkubmFtZQkJCT0gIlBDSWUiLA0KK307DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9p bnR4X21hcChzdHJ1Y3QgaXJxX2RvbWFpbiAqZG9tYWluLCB1bnNpZ25lZCBpbnQgaXJxLA0KKwkJ CSAgICAgaXJxX2h3X251bWJlcl90IGh3aXJxKQ0KK3sNCisJaXJxX3NldF9jaGlwX2FuZF9oYW5k bGVyX25hbWUoaXJxLCAmbXRrX2ludHhfaXJxX2NoaXAsDQorCQkJCSAgICAgIGhhbmRsZV9mYXN0 ZW9pX2lycSwgIklOVHgiKTsNCisJaXJxX3NldF9jaGlwX2RhdGEoaXJxLCBkb21haW4tPmhvc3Rf ZGF0YSk7DQorDQorCXJldHVybiAwOw0KK30NCisNCitzdGF0aWMgY29uc3Qgc3RydWN0IGlycV9k b21haW5fb3BzIGludHhfZG9tYWluX29wcyA9IHsNCisJLm1hcCA9IG10a19wY2llX2ludHhfbWFw LA0KK307DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9pbml0X2lycV9kb21haW5zKHN0cnVjdCBt dGtfcGNpZV9wb3J0ICpwb3J0LA0KKwkJCQkgICAgIHN0cnVjdCBkZXZpY2Vfbm9kZSAqbm9kZSkN Cit7DQorCXN0cnVjdCBkZXZpY2UgKmRldiA9IHBvcnQtPmRldjsNCisJc3RydWN0IGRldmljZV9u b2RlICppbnRjX25vZGU7DQorCXN0cnVjdCBmd25vZGVfaGFuZGxlICpmd25vZGUgPSBvZl9ub2Rl X3RvX2Z3bm9kZShub2RlKTsNCisJc3RydWN0IG10a19wY2llX21zaSAqbXNpX2luZm87DQorCXN0 cnVjdCBtc2lfZG9tYWluX2luZm8gKmluZm87DQorCWludCBpLCB2YWwsIHJldDsNCisNCisJLyog U2V0dXAgSU5UeCAqLw0KKwlpbnRjX25vZGUgPSBvZl9nZXRfY2hpbGRfYnlfbmFtZShub2RlLCAi aW50ZXJydXB0LWNvbnRyb2xsZXIiKTsNCisJaWYgKCFpbnRjX25vZGUpIHsNCisJCWRldl9ub3Rp Y2UoZGV2LCAiTWlzc2luZyBQQ0llIEludGMgbm9kZVxuIik7DQorCQlyZXR1cm4gLUVOT0RFVjsN CisJfQ0KKw0KKwlwb3J0LT5pbnR4X2RvbWFpbiA9IGlycV9kb21haW5fYWRkX2xpbmVhcihpbnRj X25vZGUsIFBDSV9OVU1fSU5UWCwNCisJCQkJCQkgICZpbnR4X2RvbWFpbl9vcHMsIHBvcnQpOw0K KwlpZiAoIXBvcnQtPmludHhfZG9tYWluKSB7DQorCQlkZXZfbm90aWNlKGRldiwgImZhaWxlZCB0 byBnZXQgSU5UeCBJUlEgZG9tYWluXG4iKTsNCisJCXJldHVybiAtRU5PREVWOw0KKwl9DQorDQor CS8qIFNldHVwIE1TSSAqLw0KKwltdXRleF9pbml0KCZwb3J0LT5sb2NrKTsNCisNCisJaW5mbyA9 IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqaW5mbyksIEdGUF9LRVJORUwpOw0KKwlpZiAoIWlu Zm8pDQorCQlyZXR1cm4gLUVOT01FTTsNCisNCisJbWVtY3B5KGluZm8sICZtdGtfbXNpX2RvbWFp bl9pbmZvLCBzaXplb2YoKmluZm8pKTsNCisJaW5mby0+Y2hpcF9kYXRhID0gcG9ydDsNCisNCisJ cG9ydC0+bXNpX2RvbWFpbiA9IHBjaV9tc2lfY3JlYXRlX2lycV9kb21haW4oZndub2RlLCBpbmZv LCBOVUxMKTsNCisJaWYgKCFwb3J0LT5tc2lfZG9tYWluKSB7DQorCQlkZXZfaW5mbyhkZXYsICJm YWlsZWQgdG8gY3JlYXRlIG1zaSBkb21haW5cbiIpOw0KKwkJcmV0ID0gLUVOT0RFVjsNCisJCWdv dG8gZXJyX21zaV9kb21haW47DQorCX0NCisNCisJLyogRW5hYmxlIE1TSSBhbmQgc2V0dXAgcGNp ZSBkb21haW5zICovDQorCXBvcnQtPm1zaV90b3BfZG9tYWluID0gaXJxX2RvbWFpbl9hZGRfaGll cmFyY2h5KE5VTEwsIDAsIDAsIG5vZGUsDQorCQkJCQkJCSZtdGtfbXNpX3RvcF9kb21haW5fb3Bz LA0KKwkJCQkJCQlwb3J0KTsNCisJaWYgKCFwb3J0LT5tc2lfdG9wX2RvbWFpbikgew0KKwkJZGV2 X2luZm8oZGV2LCAiZmFpbGVkIHRvIGNyZWF0ZSBtc2kgdG9wIGRvbWFpblxuIik7DQorCQlyZXQg PSAtRU5PREVWOw0KKwkJZ290byBlcnJfbXNpX3RvcF9kb21haW47DQorCX0NCisNCisJcG9ydC0+ bXNpX2luZm8gPSBkZXZtX2t6YWxsb2MoZGV2LCBQQ0lFX01TSV9TRVRfTlVNLCBHRlBfS0VSTkVM KTsNCisJaWYgKCFwb3J0LT5tc2lfaW5mbykgew0KKwkJcmV0ID0gLUVOT01FTTsNCisJCWdvdG8g ZXJyX21zaV9pbmZvOw0KKwl9DQorDQorCWZvciAoaSA9IDA7IGkgPCBQQ0lFX01TSV9TRVRfTlVN OyBpKyspIHsNCisJCWludCBvZmZzZXQgPSBpICogUENJRV9NU0lfU0VUX09GRlNFVDsNCisNCisJ CW1zaV9pbmZvID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCptc2lfaW5mbyksIEdGUF9LRVJO RUwpOw0KKwkJaWYgKCFtc2lfaW5mbykgew0KKwkJCXJldCA9IC1FTk9NRU07DQorCQkJZ290byBl cnJfbXNpX3NldDsNCisJCX0NCisNCisJCW1zaV9pbmZvLT5iYXNlID0gcG9ydC0+YmFzZSArIFBD SUVfTVNJX0FERFJfQkFTRV9SRUcgKyBvZmZzZXQ7DQorCQltc2lfaW5mby0+bXNnX2FkZHIgPSBw b3J0LT5yZWdfYmFzZSArIFBDSUVfTVNJX0FERFJfQkFTRV9SRUcgKw0KKwkJCQkgICAgIG9mZnNl dDsNCisNCisJCXdyaXRlbChsb3dlcl8zMl9iaXRzKG1zaV9pbmZvLT5tc2dfYWRkciksIG1zaV9p bmZvLT5iYXNlKTsNCisNCisJCW1zaV9pbmZvLT5od2lycSA9IGk7DQorCQltc2lfaW5mby0+aW5k ZXggPSBpOw0KKwkJbXNpX2luZm8tPmRvbWFpbiA9IHBvcnQtPm1zaV9kb21haW47DQorDQorCQlw b3J0LT5tc2lfaW5mb1tpXSA9IG1zaV9pbmZvOw0KKw0KKwkJLyogQWxsb2MgaXJxIGZvciBlYWNo IG1zaSBzZXQgKi8NCisJCW1zaV9pbmZvLT5pcnEgPSBpcnFfY3JlYXRlX21hcHBpbmcocG9ydC0+ bXNpX3RvcF9kb21haW4sIGkpOw0KKwkJaWYgKG1zaV9pbmZvLT5pcnEgPCAwKSB7DQorCQkJZGV2 X2luZm8oZGV2LCAiYWxsb2NhdGUgbXNpIHRvcCBpcnEgZmFpbGVkXG4iKTsNCisJCQlyZXQgPSAt RU5PU1BDOw0KKwkJCWdvdG8gZXJyX21zaV9zZXQ7DQorCQl9DQorDQorCQl2YWwgPSByZWFkbChw b3J0LT5iYXNlICsgUENJRV9JTlRfRU5BQkxFX1JFRyk7DQorCQl2YWwgfD0gKDEgPDwgKGkgKyBQ Q0lFX01TSV9TSElGVCkpOw0KKwkJd3JpdGVsKHZhbCwgcG9ydC0+YmFzZSArIFBDSUVfSU5UX0VO QUJMRV9SRUcpOw0KKw0KKwkJdmFsID0gcmVhZGwocG9ydC0+YmFzZSArIFBDSUVfTVNJX1NFVF9F TkFCTEVfUkVHKTsNCisJCXZhbCB8PSAoMSA8PCBpKTsNCisJCXdyaXRlbCh2YWwsIHBvcnQtPmJh c2UgKyBQQ0lFX01TSV9TRVRfRU5BQkxFX1JFRyk7DQorCX0NCisNCisJcmV0dXJuIDA7DQorDQor ZXJyX21zaV9zZXQ6DQorCXdoaWxlICgtLWkgPj0gMCkgew0KKwkJbXNpX2luZm8gPSBwb3J0LT5t c2lfaW5mb1tpXTsNCisJCWlycV9kaXNwb3NlX21hcHBpbmcobXNpX2luZm8tPmlycSk7DQorCX0N CitlcnJfbXNpX2luZm86DQorCWlycV9kb21haW5fcmVtb3ZlKHBvcnQtPm1zaV90b3BfZG9tYWlu KTsNCitlcnJfbXNpX3RvcF9kb21haW46DQorCWlycV9kb21haW5fcmVtb3ZlKHBvcnQtPm1zaV9k b21haW4pOw0KK2Vycl9tc2lfZG9tYWluOg0KKwlpcnFfZG9tYWluX3JlbW92ZShwb3J0LT5pbnR4 X2RvbWFpbik7DQorDQorCXJldHVybiByZXQ7DQorfQ0KKw0KK3N0YXRpYyB2b2lkIG10a19wY2ll X2lycV90ZWFyZG93bihzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCkNCit7DQorCXN0cnVjdCBt dGtfcGNpZV9tc2kgKm1zaV9pbmZvOw0KKwlpbnQgaTsNCisNCisJaXJxX3NldF9jaGFpbmVkX2hh bmRsZXJfYW5kX2RhdGEocG9ydC0+aXJxLCBOVUxMLCBOVUxMKTsNCisNCisJaWYgKHBvcnQtPmlu dHhfZG9tYWluKQ0KKwkJaXJxX2RvbWFpbl9yZW1vdmUocG9ydC0+aW50eF9kb21haW4pOw0KKw0K KwlpZiAocG9ydC0+bXNpX2RvbWFpbikNCisJCWlycV9kb21haW5fcmVtb3ZlKHBvcnQtPm1zaV9k b21haW4pOw0KKw0KKwlpZiAocG9ydC0+bXNpX3RvcF9kb21haW4pIHsNCisJCWZvciAoaSA9IDA7 IGkgPCBQQ0lFX01TSV9TRVRfTlVNOyBpKyspIHsNCisJCQltc2lfaW5mbyA9IHBvcnQtPm1zaV9p bmZvW2ldOw0KKwkJCWlycV9kaXNwb3NlX21hcHBpbmcobXNpX2luZm8tPmlycSk7DQorCQl9DQor DQorCQlpcnFfZG9tYWluX3JlbW92ZShwb3J0LT5tc2lfdG9wX2RvbWFpbik7DQorCX0NCisNCisJ aXJxX2Rpc3Bvc2VfbWFwcGluZyhwb3J0LT5pcnEpOw0KK30NCisNCitzdGF0aWMgdm9pZCBtdGtf cGNpZV9pcnFfaGFuZGxlcihzdHJ1Y3QgaXJxX2Rlc2MgKmRlc2MpDQorew0KKwlzdHJ1Y3QgbXRr X3BjaWVfcG9ydCAqcG9ydCA9IGlycV9kZXNjX2dldF9oYW5kbGVyX2RhdGEoZGVzYyk7DQorCXN0 cnVjdCBpcnFfY2hpcCAqaXJxY2hpcCA9IGlycV9kZXNjX2dldF9jaGlwKGRlc2MpOw0KKwl1bnNp Z25lZCBsb25nIHN0YXR1czsNCisJdTMyIHZpcnE7DQorCXUzMiBpcnFfYml0ID0gUENJRV9JTlRY X1NISUZUOw0KKw0KKwljaGFpbmVkX2lycV9lbnRlcihpcnFjaGlwLCBkZXNjKTsNCisNCisJc3Rh dHVzID0gcmVhZGwocG9ydC0+YmFzZSArIFBDSUVfSU5UX1NUQVRVU19SRUcpOw0KKwlpZiAoc3Rh dHVzICYgUENJRV9JTlRYX01BU0spIHsNCisJCWZvcl9lYWNoX3NldF9iaXRfZnJvbShpcnFfYml0 LCAmc3RhdHVzLCBQQ0lfTlVNX0lOVFggKw0KKwkJCQkgICAgICBQQ0lFX0lOVFhfU0hJRlQpIHsN CisJCQl2aXJxID0gaXJxX2ZpbmRfbWFwcGluZyhwb3J0LT5pbnR4X2RvbWFpbiwNCisJCQkJCQlp cnFfYml0IC0gUENJRV9JTlRYX1NISUZUKTsNCisJCQlnZW5lcmljX2hhbmRsZV9pcnEodmlycSk7 DQorCQl9DQorCX0NCisNCisJaWYgKHN0YXR1cyAmIFBDSUVfTVNJX01BU0spIHsNCisJCWlycV9i aXQgPSBQQ0lFX01TSV9TSElGVDsNCisJCWZvcl9lYWNoX3NldF9iaXRfZnJvbShpcnFfYml0LCAm c3RhdHVzLCBQQ0lFX01TSV9TRVRfTlVNICsNCisJCQkJICAgICAgUENJRV9NU0lfU0hJRlQpIHsN CisJCQl2aXJxID0gaXJxX2ZpbmRfbWFwcGluZyhwb3J0LT5tc2lfdG9wX2RvbWFpbiwNCisJCQkJ CQlpcnFfYml0IC0gUENJRV9NU0lfU0hJRlQpOw0KKwkJCWdlbmVyaWNfaGFuZGxlX2lycSh2aXJx KTsNCisJCX0NCisJfQ0KKw0KKwljaGFpbmVkX2lycV9leGl0KGlycWNoaXAsIGRlc2MpOw0KK30N CisNCitzdGF0aWMgaW50IG10a19wY2llX3NldHVwX2lycShzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAq cG9ydCwNCisJCQkgICAgICBzdHJ1Y3QgZGV2aWNlX25vZGUgKm5vZGUpDQorew0KKwlzdHJ1Y3Qg ZGV2aWNlICpkZXYgPSBwb3J0LT5kZXY7DQorCXN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYg PSB0b19wbGF0Zm9ybV9kZXZpY2UoZGV2KTsNCisJaW50IGVycjsNCisNCisJZXJyID0gbXRrX3Bj aWVfaW5pdF9pcnFfZG9tYWlucyhwb3J0LCBub2RlKTsNCisJaWYgKGVycikgew0KKwkJZGV2X25v dGljZShkZXYsICJmYWlsZWQgdG8gaW5pdCBQQ0llIElSUSBkb21haW5cbiIpOw0KKwkJcmV0dXJu IGVycjsNCisJfQ0KKw0KKwlwb3J0LT5pcnEgPSBwbGF0Zm9ybV9nZXRfaXJxKHBkZXYsIDApOw0K KwlpZiAocG9ydC0+aXJxIDwgMCkNCisJCXJldHVybiBwb3J0LT5pcnE7DQorDQorCWlycV9zZXRf Y2hhaW5lZF9oYW5kbGVyX2FuZF9kYXRhKHBvcnQtPmlycSwgbXRrX3BjaWVfaXJxX2hhbmRsZXIs IHBvcnQpOw0KKw0KKwlyZXR1cm4gMDsNCit9DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9jbGtf aW5pdChzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCkNCit7DQorCWludCByZXQ7DQorDQorCXBv cnQtPm51bV9jbGtzID0gZGV2bV9jbGtfYnVsa19nZXRfYWxsKHBvcnQtPmRldiwgJnBvcnQtPmNs a3MpOw0KKwlpZiAocG9ydC0+bnVtX2Nsa3MgPCAwKSB7DQorCQlkZXZfbm90aWNlKHBvcnQtPmRl diwgImZhaWxlZCB0byBnZXQgcGNpZSBjbG9ja1xuIik7DQorCQlyZXR1cm4gcG9ydC0+bnVtX2Ns a3M7DQorCX0NCisNCisJcmV0ID0gY2xrX2J1bGtfcHJlcGFyZV9lbmFibGUocG9ydC0+bnVtX2Ns a3MsIHBvcnQtPmNsa3MpOw0KKwlpZiAocmV0KSB7DQorCQlkZXZfbm90aWNlKHBvcnQtPmRldiwg ImZhaWxlZCB0byBlbmFibGUgcGNpZSBjbG9ja3NcbiIpOw0KKwkJcmV0dXJuIHJldDsNCisJfQ0K Kw0KKwlyZXR1cm4gMDsNCit9DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9wb3dlcl91cChzdHJ1 Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCkNCit7DQorCXN0cnVjdCBkZXZpY2UgKmRldiA9IHBvcnQt PmRldjsNCisJaW50IGVycjsNCisNCisJcG9ydC0+cGh5X3Jlc2V0ID0gZGV2bV9yZXNldF9jb250 cm9sX2dldF9vcHRpb25hbF9leGNsdXNpdmUoZGV2LA0KKwkJCQkJCQkJICAgICJwaHktcnN0Iik7 DQorCWlmIChJU19FUlIocG9ydC0+cGh5X3Jlc2V0KSkNCisJCXJldHVybiBQVFJfRVJSKHBvcnQt PnBoeV9yZXNldCk7DQorDQorCXJlc2V0X2NvbnRyb2xfZGVhc3NlcnQocG9ydC0+cGh5X3Jlc2V0 KTsNCisNCisJLyogUEhZIHBvd2VyIG9uIGFuZCBlbmFibGUgcGlwZSBjbG9jayAqLw0KKwlwb3J0 LT5waHkgPSBkZXZtX3BoeV9vcHRpb25hbF9nZXQoZGV2LCAicGNpZS1waHkiKTsNCisJaWYgKElT X0VSUihwb3J0LT5waHkpKQ0KKwkJcmV0dXJuIFBUUl9FUlIocG9ydC0+cGh5KTsNCisNCisJZXJy ID0gcGh5X2luaXQocG9ydC0+cGh5KTsNCisJaWYgKGVycikgew0KKwkJZGV2X25vdGljZShkZXYs ICJmYWlsZWQgdG8gaW5pdGlhbGl6ZSBwY2llIHBoeVxuIik7DQorCQlyZXR1cm4gZXJyOw0KKwl9 DQorDQorCWVyciA9IHBoeV9wb3dlcl9vbihwb3J0LT5waHkpOw0KKwlpZiAoZXJyKSB7DQorCQlk ZXZfbm90aWNlKGRldiwgImZhaWxlZCB0byBwb3dlciBvbiBwY2llIHBoeVxuIik7DQorCQlnb3Rv IGVycl9waHlfb247DQorCX0NCisNCisJcG9ydC0+bWFjX3Jlc2V0ID0gZGV2bV9yZXNldF9jb250 cm9sX2dldF9vcHRpb25hbF9leGNsdXNpdmUoZGV2LA0KKwkJCQkJCQkJICAgICJtYWMtcnN0Iik7 DQorCWlmIChJU19FUlIocG9ydC0+bWFjX3Jlc2V0KSkNCisJCXJldHVybiBQVFJfRVJSKHBvcnQt Pm1hY19yZXNldCk7DQorDQorCXJlc2V0X2NvbnRyb2xfZGVhc3NlcnQocG9ydC0+bWFjX3Jlc2V0 KTsNCisNCisJLyogTUFDIHBvd2VyIG9uIGFuZCBlbmFibGUgdHJhbnNhY3Rpb24gbGF5ZXIgY2xv Y2tzICovDQorCXBtX3J1bnRpbWVfZW5hYmxlKGRldik7DQorCXBtX3J1bnRpbWVfZ2V0X3N5bmMo ZGV2KTsNCisNCisJZXJyID0gbXRrX3BjaWVfY2xrX2luaXQocG9ydCk7DQorCWlmIChlcnIpIHsN CisJCWRldl9ub3RpY2UoZGV2LCAiY2xvY2sgaW5pdCBmYWlsZWRcbiIpOw0KKwkJZ290byBlcnJf Y2xrX2luaXQ7DQorCX0NCisNCisJcmV0dXJuIDA7DQorDQorZXJyX2Nsa19pbml0Og0KKwlwbV9y dW50aW1lX3B1dF9zeW5jKGRldik7DQorCXBtX3J1bnRpbWVfZGlzYWJsZShkZXYpOw0KKwlyZXNl dF9jb250cm9sX2Fzc2VydChwb3J0LT5tYWNfcmVzZXQpOw0KKwlwaHlfcG93ZXJfb2ZmKHBvcnQt PnBoeSk7DQorZXJyX3BoeV9vbjoNCisJcGh5X2V4aXQocG9ydC0+cGh5KTsNCisJcmVzZXRfY29u dHJvbF9hc3NlcnQocG9ydC0+cGh5X3Jlc2V0KTsNCisNCisJcmV0dXJuIC1FQlVTWTsNCit9DQor DQorc3RhdGljIHZvaWQgbXRrX3BjaWVfcG93ZXJfZG93bihzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAq cG9ydCkNCit7DQorCXBoeV9wb3dlcl9vZmYocG9ydC0+cGh5KTsNCisJcGh5X2V4aXQocG9ydC0+ cGh5KTsNCisNCisJY2xrX2J1bGtfZGlzYWJsZV91bnByZXBhcmUocG9ydC0+bnVtX2Nsa3MsIHBv cnQtPmNsa3MpOw0KKw0KKwlwbV9ydW50aW1lX3B1dF9zeW5jKHBvcnQtPmRldik7DQorCXBtX3J1 bnRpbWVfZGlzYWJsZShwb3J0LT5kZXYpOw0KK30NCisNCitzdGF0aWMgaW50IG10a19wY2llX3Nl dHVwKHN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0KQ0KK3sNCisJc3RydWN0IGRldmljZSAqZGV2 ID0gcG9ydC0+ZGV2Ow0KKwlzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2ID0gdG9fcGxhdGZv cm1fZGV2aWNlKGRldik7DQorCXN0cnVjdCByZXNvdXJjZSAqcmVnczsNCisJaW50IGVycjsNCisN CisJcmVncyA9IHBsYXRmb3JtX2dldF9yZXNvdXJjZV9ieW5hbWUocGRldiwgSU9SRVNPVVJDRV9N RU0sICJwY2llLW1hYyIpOw0KKwlwb3J0LT5iYXNlID0gZGV2bV9pb3JlbWFwX3Jlc291cmNlKGRl diwgcmVncyk7DQorCWlmIChJU19FUlIocG9ydC0+YmFzZSkpIHsNCisJCWRldl9ub3RpY2UoZGV2 LCAiZmFpbGVkIHRvIG1hcCByZWdpc3RlciBiYXNlXG4iKTsNCisJCXJldHVybiBQVFJfRVJSKHBv cnQtPmJhc2UpOw0KKwl9DQorDQorCXBvcnQtPnJlZ19iYXNlID0gcmVncy0+c3RhcnQ7DQorDQor CS8qIERvbid0IHRvdWNoIHRoZSBoYXJkd2FyZSByZWdpc3RlcnMgYmVmb3JlIHBvd2VyIHVwICov DQorCWVyciA9IG10a19wY2llX3Bvd2VyX3VwKHBvcnQpOw0KKwlpZiAoZXJyKQ0KKwkJcmV0dXJu IGVycjsNCisNCisJLyogVHJ5IGxpbmsgdXAgKi8NCisJZXJyID0gbXRrX3BjaWVfc3RhcnR1cF9w b3J0KHBvcnQpOw0KKwlpZiAoZXJyKSB7DQorCQlkZXZfbm90aWNlKGRldiwgIlBDSWUgbGluayBk b3duXG4iKTsNCisJCWdvdG8gZXJyX3NldHVwOw0KKwl9DQorDQorCWVyciA9IG10a19wY2llX3Nl dHVwX2lycShwb3J0LCBkZXYtPm9mX25vZGUpOw0KKwlpZiAoZXJyKQ0KKwkJZ290byBlcnJfc2V0 dXA7DQorDQorCWRldl9pbmZvKGRldiwgIlBDSWUgbGluayB1cCBzdWNjZXNzIVxuIik7DQorDQor CXJldHVybiAwOw0KKw0KK2Vycl9zZXR1cDoNCisJbXRrX3BjaWVfcG93ZXJfZG93bihwb3J0KTsN CisNCisJcmV0dXJuIGVycjsNCit9DQorDQorc3RhdGljIGludCBtdGtfcGNpZV9wcm9iZShzdHJ1 Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KK3sNCisJc3RydWN0IGRldmljZSAqZGV2ID0gJnBk ZXYtPmRldjsNCisJc3RydWN0IG10a19wY2llX3BvcnQgKnBvcnQ7DQorCXN0cnVjdCBwY2lfaG9z dF9icmlkZ2UgKmhvc3Q7DQorCWludCBlcnI7DQorDQorCWhvc3QgPSBkZXZtX3BjaV9hbGxvY19o b3N0X2JyaWRnZShkZXYsIHNpemVvZigqcG9ydCkpOw0KKwlpZiAoIWhvc3QpDQorCQlyZXR1cm4g LUVOT01FTTsNCisNCisJcG9ydCA9IHBjaV9ob3N0X2JyaWRnZV9wcml2KGhvc3QpOw0KKw0KKwlw b3J0LT5kZXYgPSBkZXY7DQorCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIHBvcnQpOw0KKw0K KwllcnIgPSBtdGtfcGNpZV9zZXR1cChwb3J0KTsNCisJaWYgKGVycikNCisJCXJldHVybiBlcnI7 DQorDQorCWhvc3QtPm9wcyA9ICZtdGtfcGNpZV9vcHM7DQorCWhvc3QtPnN5c2RhdGEgPSBwb3J0 Ow0KKw0KKwllcnIgPSBwY2lfaG9zdF9wcm9iZShob3N0KTsNCisJaWYgKGVycikgew0KKwkJbXRr X3BjaWVfcG93ZXJfZG93bihwb3J0KTsNCisJCXJldHVybiBlcnI7DQorCX0NCisNCisJcmV0dXJu IDA7DQorfQ0KKw0KK3N0YXRpYyBpbnQgbXRrX3BjaWVfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9k ZXZpY2UgKnBkZXYpDQorew0KKwlzdHJ1Y3QgbXRrX3BjaWVfcG9ydCAqcG9ydCA9IHBsYXRmb3Jt X2dldF9kcnZkYXRhKHBkZXYpOw0KKwlzdHJ1Y3QgcGNpX2hvc3RfYnJpZGdlICpob3N0ID0gcGNp X2hvc3RfYnJpZGdlX2Zyb21fcHJpdihwb3J0KTsNCisNCisJcGNpX2xvY2tfcmVzY2FuX3JlbW92 ZSgpOw0KKwlwY2lfc3RvcF9yb290X2J1cyhob3N0LT5idXMpOw0KKwlwY2lfcmVtb3ZlX3Jvb3Rf YnVzKGhvc3QtPmJ1cyk7DQorCXBjaV91bmxvY2tfcmVzY2FuX3JlbW92ZSgpOw0KKw0KKwltdGtf cGNpZV9pcnFfdGVhcmRvd24ocG9ydCk7DQorCW10a19wY2llX3Bvd2VyX2Rvd24ocG9ydCk7DQor DQorCXJldHVybiAwOw0KK30NCisNCitzdGF0aWMgaW50IF9fbWF5YmVfdW51c2VkIG10a19wY2ll X3R1cm5fb2ZmX2xpbmsoc3RydWN0IG10a19wY2llX3BvcnQgKnBvcnQpDQorew0KKwlpbnQgdmFs Ow0KKw0KKwl2YWwgPSByZWFkbChwb3J0LT5iYXNlICsgUENJRV9JQ01EX1BNX1JFRyk7DQorCXZh bCB8PSBQQ0lFX1RVUk5fT0ZGX0xJTks7DQorCXdyaXRlbCh2YWwsIHBvcnQtPmJhc2UgKyBQQ0lF X0lDTURfUE1fUkVHKTsNCisNCisJLyogQ2hlY2sgdGhlIGxpbmsgaXMgTDIgKi8NCisJcmV0dXJu IHJlYWRsX3BvbGxfdGltZW91dChwb3J0LT5iYXNlICsgUENJRV9MVFNTTV9TVEFUVVNfUkVHLCB2 YWwsDQorCQkJCSAgKFBDSUVfTFRTU01fU1RBVEUodmFsKSA9PQ0KKwkJCQkgICBQQ0lFX0xUU1NN X1NUQVRFX0wyX0lETEUpLCAyMCwNCisJCQkJICAgNTAgKiBVU0VDX1BFUl9NU0VDKTsNCit9DQor DQorc3RhdGljIGludCBfX21heWJlX3VudXNlZCBtdGtfcGNpZV9zdXNwZW5kX25vaXJxKHN0cnVj dCBkZXZpY2UgKmRldikNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0ID0gZGV2X2dl dF9kcnZkYXRhKGRldik7DQorCWludCBlcnIsIHZhbDsNCisNCisJaWYgKHBvcnQtPmlzX3N1c3Bl bmRlZCkNCisJCXJldHVybiAwOw0KKw0KKwkvKiBUcmlnZ2VyIGxpbmsgdG8gTDIgc3RhdGUgKi8N CisJZXJyID0gbXRrX3BjaWVfdHVybl9vZmZfbGluayhwb3J0KTsNCisJaWYgKGVycikgew0KKwkJ ZGV2X25vdGljZShwb3J0LT5kZXYsICJjYW4gbm90IGVudGVyIEwyIHN0YXRlXG4iKTsNCisJCWdv dG8gcG93ZXJfb2ZmOw0KKwl9DQorDQorCS8qIFB1bGwgZG93biB0aGUgUEVSU1QjIHBpbiAqLw0K Kwl2YWwgPSByZWFkbChwb3J0LT5iYXNlICsgUENJRV9SU1RfQ1RSTF9SRUcpOw0KKwl2YWwgfD0g UENJRV9QRV9SU1RCOw0KKwl3cml0ZWwodmFsLCBwb3J0LT5iYXNlICsgUENJRV9SU1RfQ1RSTF9S RUcpOw0KKw0KKwlkZXZfaW5mbyhwb3J0LT5kZXYsICJlbnRlciBMMiBzdGF0ZSBzdWNjZXNzIik7 DQorDQorcG93ZXJfb2ZmOg0KKwlwaHlfcG93ZXJfb2ZmKHBvcnQtPnBoeSk7DQorDQorCWNsa19i dWxrX2Rpc2FibGVfdW5wcmVwYXJlKHBvcnQtPm51bV9jbGtzLCBwb3J0LT5jbGtzKTsNCisNCisJ cG9ydC0+aXNfc3VzcGVuZGVkID0gdHJ1ZTsNCisNCisJcmV0dXJuIDA7DQorfQ0KKw0KK3N0YXRp YyBpbnQgX19tYXliZV91bnVzZWQgbXRrX3BjaWVfcmVzdW1lX25vaXJxKHN0cnVjdCBkZXZpY2Ug KmRldikNCit7DQorCXN0cnVjdCBtdGtfcGNpZV9wb3J0ICpwb3J0ID0gZGV2X2dldF9kcnZkYXRh KGRldik7DQorCWludCBlcnI7DQorDQorCWlmICghcG9ydC0+aXNfc3VzcGVuZGVkKQ0KKwkJcmV0 dXJuIDA7DQorDQorCXBoeV9wb3dlcl9vbihwb3J0LT5waHkpOw0KKw0KKwllcnIgPSBjbGtfYnVs a19wcmVwYXJlX2VuYWJsZShwb3J0LT5udW1fY2xrcywgcG9ydC0+Y2xrcyk7DQorCWlmIChlcnIp IHsNCisJCWRldl9kYmcoZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSBwY2llIGNsb2Nrc1xuIik7DQor CQlyZXR1cm4gZXJyOw0KKwl9DQorDQorCWVyciA9IG10a19wY2llX3N0YXJ0dXBfcG9ydChwb3J0 KTsNCisJaWYgKGVycikgew0KKwkJZGV2X25vdGljZShwb3J0LT5kZXYsICJyZXN1bWUgZmFpbGVk XG4iKTsNCisJCXJldHVybiBlcnI7DQorCX0NCisNCisJcG9ydC0+aXNfc3VzcGVuZGVkID0gZmFs c2U7DQorDQorCWRldl9pbmZvKHBvcnQtPmRldiwgInJlc3VtZSBkb25lXG4iKTsNCisNCisJcmV0 dXJuIDA7DQorfQ0KKw0KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZGV2X3BtX29wcyBtdGtfcGNpZV9w bV9vcHMgPSB7DQorCVNFVF9OT0lSUV9TWVNURU1fU0xFRVBfUE1fT1BTKG10a19wY2llX3N1c3Bl bmRfbm9pcnEsDQorCQkJCSAgICAgIG10a19wY2llX3Jlc3VtZV9ub2lycSkNCit9Ow0KKw0KK3N0 YXRpYyBjb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIG10a19wY2llX29mX21hdGNoW10gPSB7DQor CXsgLmNvbXBhdGlibGUgPSAibWVkaWF0ZWssZ2VuMy1wY2llIiB9LA0KKwl7IC5jb21wYXRpYmxl ID0gIm1lZGlhdGVrLG10ODE5Mi1wY2llIiB9LA0KKwl7fSwNCit9Ow0KKw0KK3N0YXRpYyBzdHJ1 Y3QgcGxhdGZvcm1fZHJpdmVyIG10a19wY2llX2RyaXZlciA9IHsNCisJLnByb2JlID0gbXRrX3Bj aWVfcHJvYmUsDQorCS5yZW1vdmUgPSBtdGtfcGNpZV9yZW1vdmUsDQorCS5kcml2ZXIgPSB7DQor CQkubmFtZSA9ICJtdGstcGNpZSIsDQorCQkub2ZfbWF0Y2hfdGFibGUgPSBtdGtfcGNpZV9vZl9t YXRjaCwNCisJCS5wbSA9ICZtdGtfcGNpZV9wbV9vcHMsDQorCX0sDQorfTsNCisNCittb2R1bGVf cGxhdGZvcm1fZHJpdmVyKG10a19wY2llX2RyaXZlcik7DQorTU9EVUxFX0xJQ0VOU0UoIkdQTCB2 MiIpOw0KLS0gDQoyLjI1LjENCg== 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=-13.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17340C4346E for ; Sun, 27 Sep 2020 07:50:34 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A0BBE23976 for ; Sun, 27 Sep 2020 07:50:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="JR84rPsl"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mediatek.com header.i=@mediatek.com header.b="pLnJ4P3c" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A0BBE23976 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-ID:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Wd1u+2XQ+zLiPg5fXWyt3PTCugW4CTU87L/eTSEqOg4=; b=JR84rPslSWP8YLsXAHL0TwM/t qgIOA5AQIamPofeFihSn2dKEtIt15Fbzmrk7sdXgCcsJghp0lXZFaO4aeLci/IUYb8XERHhSYE7Bf 1uXvWNFodElgFI2nKCZ+8kMJqfZvRf3GMyMh9ttHot27KJ9Up77rd5HNKpZUvmPa5PMfyoRpTVy3M MW3D1H8jYhCGHOPAzIMYgD/CSU0ewy+MJzuTmWc8ACbX+aVsuVYmO22MdlKlStCurG4sK0E/F+YU4 0lxCnnf1klb8m1nxoS+PSLhTl9brV+UsSIT7x2XdprwHrCkr6jIoRVFUjCfEhJPIgxr5H/diWTtjR I/iXlL32A==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kMRQW-00044t-Ul; Sun, 27 Sep 2020 07:48:57 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kMRQP-00041J-Hs; Sun, 27 Sep 2020 07:48:51 +0000 X-UUID: 4b595df23e3d4876b490316098e79752-20200926 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=8P68Afz/ttPvRDRRLqb82ic0H6eAnH0ZNO25vf3BPBg=; b=pLnJ4P3c+GTDaMPLkUfLoo3tR8wjyPWYyE2IMsRqxMopPXPuerBkgB4zNGGfEEQQB+KkH4ylh/0I3VQUvYWAVl5cUZzKbIpreFMtoT5mYAemFFSU4wEe4A/0nsiqNL5LHsFHwcRuCd/qOByhZrUiWanD9YGBEbCOPYpUapRpKNs=; X-UUID: 4b595df23e3d4876b490316098e79752-20200926 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 695693604; Sat, 26 Sep 2020 23:48:42 -0800 Received: from mtkmbs08n2.mediatek.inc (172.21.101.56) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 27 Sep 2020 00:48:41 -0700 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sun, 27 Sep 2020 15:48:28 +0800 Received: from localhost.localdomain (10.17.3.153) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 27 Sep 2020 15:48:27 +0800 From: Jianjun Wang To: Bjorn Helgaas , Rob Herring , Lorenzo Pieralisi , Ryder Lee Subject: [v3,2/3] PCI: mediatek: Add new generation controller support Date: Sun, 27 Sep 2020 15:45:54 +0800 Message-ID: <20200927074555.4155-3-jianjun.wang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20200927074555.4155-1-jianjun.wang@mediatek.com> References: <20200927074555.4155-1-jianjun.wang@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: CC715FDA7CA61A0D39C583CB7A33E73384677ABBE66BC3B01B721855B82A588D2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200927_034849_866014_5EC399EF X-CRM114-Status: GOOD ( 19.99 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: youlin.pei@mediatek.com, devicetree@vger.kernel.org, qizhong.cheng@mediatek.com, chuanjia.liu@mediatek.com, Mauro Carvalho Chehab , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, Jianjun Wang , sin_jieyang@mediatek.com, Sj Huang , linux-mediatek@lists.infradead.org, Philipp Zabel , Matthias Brugger , davem@davemloft.net, linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org MediaTek's PCIe host controller has three generation HWs, the new generation HW is an individual bridge, it supoorts Gen3 speed and up to 256 MSI interrupt numbers for multi-function devices. Add support for new Gen3 controller which can be found on MT8192. Signed-off-by: Jianjun Wang Acked-by: Ryder Lee --- drivers/pci/controller/Kconfig | 14 + drivers/pci/controller/Makefile | 1 + drivers/pci/controller/pcie-mediatek-gen3.c | 1024 +++++++++++++++++++ 3 files changed, 1039 insertions(+) create mode 100644 drivers/pci/controller/pcie-mediatek-gen3.c diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index f18c3725ef80..83daa772595b 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -239,6 +239,20 @@ config PCIE_MEDIATEK Say Y here if you want to enable PCIe controller support on MediaTek SoCs. +config PCIE_MEDIATEK_GEN3 + tristate "MediaTek GEN3 PCIe controller" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + depends on PCI_MSI_IRQ_DOMAIN + help + Adds support for PCIe Gen3 MAC controller for MediaTek SoCs. + This PCIe controller provides the capable of Gen3, Gen2 and + Gen1 speed, and support up to 256 MSI interrupt numbers for + multi-function devices. + + Say Y here if you want to enable Gen3 PCIe controller support on + MediaTek SoCs. + config PCIE_TANGO_SMP8759 bool "Tango SMP8759 PCIe controller (DANGEROUS)" depends on ARCH_TANGO && PCI_MSI && OF diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index bcdbf49ab1e4..9c1b96777597 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o +obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie-mediatek-gen3.o obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c new file mode 100644 index 000000000000..ad69c789b24d --- /dev/null +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -0,0 +1,1024 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek PCIe host controller driver. + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Jianjun Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" + +#define PCIE_SETTING_REG 0x80 +#define PCIE_PCI_IDS_1 0x9c +#define PCI_CLASS(class) (class << 8) +#define PCIE_RC_MODE BIT(0) + +#define PCIE_CFGNUM_REG 0x140 +#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0)) +#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8)) +#define PCIE_CFG_BYTE_EN(bytes) (((bytes) << 16) & GENMASK(19, 16)) +#define PCIE_CFG_FORCE_BYTE_EN BIT(20) +#define PCIE_CFG_OFFSET_ADDR 0x1000 +#define PCIE_CFG_HEADER(devfn, bus) \ + (PCIE_CFG_DEVFN(devfn) | PCIE_CFG_BUS(bus)) + +#define PCIE_CFG_HEADER_FORCE_BE(devfn, bus, bytes) \ + (PCIE_CFG_HEADER(devfn, bus) | PCIE_CFG_BYTE_EN(bytes) \ + | PCIE_CFG_FORCE_BYTE_EN) + +#define PCIE_RST_CTRL_REG 0x148 +#define PCIE_MAC_RSTB BIT(0) +#define PCIE_PHY_RSTB BIT(1) +#define PCIE_BRG_RSTB BIT(2) +#define PCIE_PE_RSTB BIT(3) + +#define PCIE_MISC_STATUS_REG 0x14C +#define PCIE_LTR_MSG_RECEIVED BIT(0) +#define PCIE_PCIE_MSG_RECEIVED BIT(1) + +#define PCIE_LTSSM_STATUS_REG 0x150 +#define PCIE_LTSSM_STATE_MASK GENMASK(28, 24) +#define PCIE_LTSSM_STATE(val) ((val & PCIE_LTSSM_STATE_MASK) >> 24) +#define PCIE_LTSSM_STATE_L0 0x10 +#define PCIE_LTSSM_STATE_L1_IDLE 0x13 +#define PCIE_LTSSM_STATE_L2_IDLE 0x14 + +#define PCIE_LINK_STATUS_REG 0x154 +#define PCIE_PORT_LINKUP BIT(8) + +#define PCIE_MSI_SET_NUM 8 +#define PCIE_MSI_IRQS_PER_SET 32 +#define PCIE_MSI_IRQS_NUM \ + (PCIE_MSI_IRQS_PER_SET * (PCIE_MSI_SET_NUM)) + +#define PCIE_INT_ENABLE_REG 0x180 +#define PCIE_MSI_MASK GENMASK(PCIE_MSI_SET_NUM + 8 - 1, 8) +#define PCIE_MSI_SHIFT 8 +#define PCIE_INTX_SHIFT 24 +#define PCIE_INTX_MASK GENMASK(27, 24) +#define PCIE_MSG_MASK BIT(28) +#define PCIE_AER_MASK BIT(29) +#define PCIE_PM_MASK BIT(30) + +#define PCIE_INT_STATUS_REG 0x184 +#define PCIE_MSI_SET_ENABLE_REG 0x190 + +#define PCIE_LOW_POWER_CTRL_REG 0x194 +#define PCIE_DIS_LOWPWR_MASK GENMASK(3, 0) +#define PCIE_DIS_L0S_MASK BIT(0) +#define PCIE_DIS_L1_MASK BIT(1) +#define PCIE_DIS_L11_MASK BIT(2) +#define PCIE_DIS_L12_MASK BIT(3) +#define PCIE_FORCE_DIS_LOWPWR GENMASK(11, 8) +#define PCIE_FORCE_DIS_L0S BIT(8) +#define PCIE_FORCE_DIS_L1 BIT(9) +#define PCIE_FORCE_DIS_L11 BIT(10) +#define PCIE_FORCE_DIS_L12 BIT(11) + +#define PCIE_ICMD_PM_REG 0x198 +#define PCIE_TURN_OFF_LINK BIT(4) + +#define PCIE_MSI_ADDR_BASE_REG 0xc00 +#define PCIE_MSI_SET_OFFSET 0x10 +#define PCIE_MSI_STATUS_OFFSET 0x04 +#define PCIE_MSI_ENABLE_OFFSET 0x08 + +#define PCIE_TRANS_TABLE_BASE_REG 0x800 +#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4 +#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8 +#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc +#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10 +#define PCIE_ATR_TLB_SET_OFFSET 0x20 + +#define PCIE_MAX_TRANS_TABLES 8 +#define ATR_EN BIT(0) +#define ATR_SIZE(size) ((((size) - 1) << 1) & GENMASK(6, 1)) +#define ATR_ID(id) (id & GENMASK(3, 0)) +#define ATR_PARAM(param) (((param) << 16) & GENMASK(27, 16)) + +/** + * struct mtk_pcie_msi - MSI information for each set + * @base: IO mapped register base + * @hwirq: Hardware interrupt number + * @irq: MSI set Interrupt number + * @index: MSI set number + * @msg_addr: MSI message address + * @domain: IRQ domain + */ +struct mtk_pcie_msi { + void __iomem *base; + int hwirq; + int irq; + int index; + phys_addr_t msg_addr; + struct irq_domain *domain; +}; + +/** + * struct mtk_pcie_port - PCIe port information + * @dev: PCIe device + * @base: IO mapped register base + * @reg_base: Physical register base + * @mac_reset: mac reset control + * @phy_reset: phy reset control + * @phy: PHY controller block + * @clks: PCIe clocks + * @num_clks: PCIe clocks count for this port + * @is_suspended: device suspend state + * @irq: PCIe controller interrupt number + * @intx_domain: legacy INTx IRQ domain + * @msi_domain: MSI IRQ domain + * @msi_top_domain: MSI IRQ top domain + * @msi_info: MSI sets information + * @lock: lock protecting IRQ bit map + * @msi_irq_in_use: bit map for assigned MSI IRQ + */ +struct mtk_pcie_port { + struct device *dev; + void __iomem *base; + phys_addr_t reg_base; + struct reset_control *mac_reset; + struct reset_control *phy_reset; + struct phy *phy; + struct clk_bulk_data *clks; + int num_clks; + bool is_suspended; + + int irq; + struct irq_domain *intx_domain; + struct irq_domain *msi_domain; + struct irq_domain *msi_top_domain; + struct mtk_pcie_msi **msi_info; + struct mutex lock; + DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM); +}; + +static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct mtk_pcie_port *port = bus->sysdata; + int bytes; + + bytes = ((1 << size) - 1) << (where & 0x3); + writel(PCIE_CFG_HEADER_FORCE_BE(devfn, bus->number, bytes), + port->base + PCIE_CFGNUM_REG); + + *val = readl(port->base + PCIE_CFG_OFFSET_ADDR + (where & ~0x3)); + + if (size <= 2) + *val = (*val >> (8 * (where & 0x3))) & ((1 << (size * 8)) - 1); + + return PCIBIOS_SUCCESSFUL; +} + +static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct mtk_pcie_port *port = bus->sysdata; + int bytes; + + bytes = ((1 << size) - 1) << (where & 0x3); + writel(PCIE_CFG_HEADER_FORCE_BE(devfn, bus->number, bytes), + port->base + PCIE_CFGNUM_REG); + + if (size <= 2) + val = (val & ((1 << (size * 8)) - 1)) << ((where & 0x3) * 8); + + writel(val, port->base + PCIE_CFG_OFFSET_ADDR + (where & ~0x3)); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops mtk_pcie_ops = { + .read = mtk_pcie_config_read, + .write = mtk_pcie_config_write, +}; + +static void mtk_pcie_set_trans_window(void __iomem *reg, + resource_size_t cpu_addr, + resource_size_t pci_addr, size_t size) +{ + writel(lower_32_bits(cpu_addr) | ATR_SIZE(fls(size) - 1) | ATR_EN, reg); + writel(upper_32_bits(cpu_addr), reg + PCIE_ATR_SRC_ADDR_MSB_OFFSET); + writel(lower_32_bits(pci_addr), reg + PCIE_ATR_TRSL_ADDR_LSB_OFFSET); + writel(upper_32_bits(pci_addr), reg + PCIE_ATR_TRSL_ADDR_MSB_OFFSET); + writel(ATR_ID(0) | ATR_PARAM(0), reg + PCIE_ATR_TRSL_PARAM_OFFSET); +} + +static int mtk_pcie_set_trans_table(void __iomem *reg, + resource_size_t cpu_addr, + resource_size_t pci_addr, size_t size, + int num) +{ + void __iomem *table_base; + + if (num > PCIE_MAX_TRANS_TABLES) + return -ENODEV; + + table_base = reg + num * PCIE_ATR_TLB_SET_OFFSET; + mtk_pcie_set_trans_window(table_base, cpu_addr, pci_addr, size); + + return 0; +} + +static int mtk_pcie_startup_port(struct mtk_pcie_port *port) +{ + struct resource_entry *entry; + struct pci_host_bridge *host = pci_host_bridge_from_priv(port); + u32 val; + int err = 0, table_index = 0; + + /* Set as RC mode */ + val = readl(port->base + PCIE_SETTING_REG); + val |= PCIE_RC_MODE; + writel(val, port->base + PCIE_SETTING_REG); + + /* Set class code */ + val = readl(port->base + PCIE_PCI_IDS_1); + val &= ~GENMASK(31, 8); + val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8); + writel(val, port->base + PCIE_PCI_IDS_1); + + /* Assert all reset signals */ + val = readl(port->base + PCIE_RST_CTRL_REG); + val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* De-assert reset signals*/ + val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB); + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* Delay 100ms to wait the reference clocks become stable */ + usleep_range(100 * 1000, 120 * 1000); + + /* De-assert pe reset*/ + val &= ~PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + /* Check if the link is up or not */ + err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_REG, val, + !!(val & PCIE_PORT_LINKUP), 20, + 50 * USEC_PER_MSEC); + if (err) + return err; + + /* Set PCIe translation windows */ + resource_list_for_each_entry(entry, &host->windows) { + unsigned long type = resource_type(entry->res); + struct resource *res = NULL; + resource_size_t cpu_addr; + resource_size_t pci_addr; + + if (!(type & (IORESOURCE_MEM | IORESOURCE_IO))) + continue; + + res = entry->res; + cpu_addr = res->start; + pci_addr = res->start - entry->offset; + mtk_pcie_set_trans_table(port->base + PCIE_TRANS_TABLE_BASE_REG, + cpu_addr, pci_addr, resource_size(res), + table_index); + + dev_dbg(port->dev, "Set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n", + (!!(type & IORESOURCE_MEM) ? "MEM" : "IO"), table_index, + cpu_addr, pci_addr, resource_size(res)); + + table_index++; + } + + return 0; +} + +static inline struct mtk_pcie_msi *mtk_get_msi_info(struct mtk_pcie_port *port, + unsigned int hwirq) +{ + return port->msi_info[hwirq / PCIE_MSI_IRQS_PER_SET]; +} + +static int mtk_pcie_set_affinity(struct irq_data *data, + const struct cpumask *mask, bool force) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int ret; + + ret = irq_set_affinity_hint(port->irq, mask); + if (ret) + return ret; + + irq_data_update_effective_affinity(data, mask); + + return 0; +} + +static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + + msi_info = mtk_get_msi_info(port, data->hwirq); + + msg->address_hi = 0; + msg->address_lo = lower_32_bits(msi_info->msg_addr); + + msg->data = data->hwirq; + dev_dbg(port->dev, "msi#%#lx address_hi %#x address_lo %#x data %d\n", + data->hwirq, msg->address_hi, msg->address_lo, msg->data); +} + +static void mtk_msi_irq_ack(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int hwirq; + + msi_info = mtk_get_msi_info(port, data->hwirq); + + hwirq = data->hwirq % PCIE_MSI_IRQS_PER_SET; + + writel(1 << hwirq, msi_info->base + PCIE_MSI_STATUS_OFFSET); +} + +static void mtk_msi_irq_mask(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + msi_info = mtk_get_msi_info(port, data->hwirq); + val = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + val &= ~(1 << data->hwirq); + writel(val, msi_info->base + PCIE_MSI_ENABLE_OFFSET); + + pci_msi_mask_irq(data); +} + +static void mtk_msi_irq_unmask(struct irq_data *data) +{ + struct mtk_pcie_msi *msi_info; + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + msi_info = mtk_get_msi_info(port, data->hwirq); + val = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + val |= (1 << data->hwirq); + writel(val, msi_info->base + PCIE_MSI_ENABLE_OFFSET); + + pci_msi_unmask_irq(data); +} + +static struct irq_chip mtk_msi_irq_chip = { + .irq_ack = mtk_msi_irq_ack, + .irq_compose_msi_msg = mtk_compose_msi_msg, + .irq_mask = mtk_msi_irq_mask, + .irq_unmask = mtk_msi_irq_unmask, + .irq_set_affinity = mtk_pcie_set_affinity, + .name = "PCIe", +}; + +static irq_hw_number_t mtk_pcie_msi_get_hwirq(struct msi_domain_info *info, + msi_alloc_info_t *arg) +{ + struct msi_desc *entry = arg->desc; + struct mtk_pcie_port *port = info->chip_data; + int hwirq; + + mutex_lock(&port->lock); + + hwirq = bitmap_find_free_region(port->msi_irq_in_use, PCIE_MSI_IRQS_NUM, + order_base_2(entry->nvec_used)); + if (hwirq < 0) { + mutex_unlock(&port->lock); + return -ENOSPC; + } + + mutex_unlock(&port->lock); + + return hwirq; +} + +static void mtk_pcie_msi_free(struct irq_domain *domain, + struct msi_domain_info *info, unsigned int virq) +{ + struct irq_data *data = irq_domain_get_irq_data(domain, virq); + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + + mutex_lock(&port->lock); + + bitmap_clear(port->msi_irq_in_use, data->hwirq, 1); + + mutex_unlock(&port->lock); +} + +static struct msi_domain_ops mtk_msi_domain_ops = { + .get_hwirq = mtk_pcie_msi_get_hwirq, + .msi_free = mtk_pcie_msi_free, +}; + +static struct msi_domain_info mtk_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_PCI_MSIX | + MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI), + .chip = &mtk_msi_irq_chip, + .ops = &mtk_msi_domain_ops, + .handler = handle_edge_irq, + .handler_name = "MSI", +}; + +static void mtk_msi_top_irq_eoi(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int msi_irq = data->hwirq + PCIE_MSI_SHIFT; + + writel(1 << msi_irq, port->base + PCIE_INT_STATUS_REG); +} + +static struct irq_chip mtk_msi_top_irq_chip = { + .irq_eoi = mtk_msi_top_irq_eoi, + .name = "PCIe", +}; + +static void mtk_pcie_msi_handler(struct irq_desc *desc) +{ + struct mtk_pcie_msi *msi_info = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long msi_enable, msi_status; + u32 virq, bit, hwirq; + + chained_irq_enter(irqchip, desc); + + msi_enable = readl(msi_info->base + PCIE_MSI_ENABLE_OFFSET); + while ((msi_status = readl(msi_info->base + PCIE_MSI_STATUS_OFFSET))) { + msi_status &= msi_enable; + for_each_set_bit(bit, &msi_status, PCIE_MSI_IRQS_PER_SET) { + hwirq = bit + msi_info->index * PCIE_MSI_IRQS_PER_SET; + virq = irq_find_mapping(msi_info->domain, hwirq); + generic_handle_irq(virq); + } + } + + chained_irq_exit(irqchip, desc); +} + +static int mtk_msi_top_domain_map(struct irq_domain *domain, + unsigned int virq, irq_hw_number_t hwirq) +{ + struct mtk_pcie_port *port = domain->host_data; + struct mtk_pcie_msi *msi_info = port->msi_info[hwirq]; + + irq_domain_set_info(domain, virq, hwirq, + &mtk_msi_top_irq_chip, domain->host_data, + mtk_pcie_msi_handler, msi_info, NULL); + + return 0; +} + +static const struct irq_domain_ops mtk_msi_top_domain_ops = { + .map = mtk_msi_top_domain_map, +}; + +static void mtk_intx_mask(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val &= ~(1 << (data->hwirq + PCIE_INTX_SHIFT)); + writel(val, port->base + PCIE_INT_ENABLE_REG); +} + +static void mtk_intx_unmask(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int val; + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val |= 1 << (data->hwirq + PCIE_INTX_SHIFT); + writel(val, port->base + PCIE_INT_ENABLE_REG); +} + +static void mtk_intx_eoi(struct irq_data *data) +{ + struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); + int hwirq; + + /** + * As an emulated level irq, its interrupt status will be remained + * until receive the corresponding message of de-assert, hence that + * the status can only be cleared when the interrupt has been serviced. + */ + hwirq = data->hwirq + PCIE_INTX_SHIFT; + writel(1 << hwirq, port->base + PCIE_INT_STATUS_REG); +} + +static struct irq_chip mtk_intx_irq_chip = { + .irq_mask = mtk_intx_mask, + .irq_unmask = mtk_intx_unmask, + .irq_eoi = mtk_intx_eoi, + .irq_set_affinity = mtk_pcie_set_affinity, + .name = "PCIe", +}; + +static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler_name(irq, &mtk_intx_irq_chip, + handle_fasteoi_irq, "INTx"); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = mtk_pcie_intx_map, +}; + +static int mtk_pcie_init_irq_domains(struct mtk_pcie_port *port, + struct device_node *node) +{ + struct device *dev = port->dev; + struct device_node *intc_node; + struct fwnode_handle *fwnode = of_node_to_fwnode(node); + struct mtk_pcie_msi *msi_info; + struct msi_domain_info *info; + int i, val, ret; + + /* Setup INTx */ + intc_node = of_get_child_by_name(node, "interrupt-controller"); + if (!intc_node) { + dev_notice(dev, "Missing PCIe Intc node\n"); + return -ENODEV; + } + + port->intx_domain = irq_domain_add_linear(intc_node, PCI_NUM_INTX, + &intx_domain_ops, port); + if (!port->intx_domain) { + dev_notice(dev, "failed to get INTx IRQ domain\n"); + return -ENODEV; + } + + /* Setup MSI */ + mutex_init(&port->lock); + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memcpy(info, &mtk_msi_domain_info, sizeof(*info)); + info->chip_data = port; + + port->msi_domain = pci_msi_create_irq_domain(fwnode, info, NULL); + if (!port->msi_domain) { + dev_info(dev, "failed to create msi domain\n"); + ret = -ENODEV; + goto err_msi_domain; + } + + /* Enable MSI and setup pcie domains */ + port->msi_top_domain = irq_domain_add_hierarchy(NULL, 0, 0, node, + &mtk_msi_top_domain_ops, + port); + if (!port->msi_top_domain) { + dev_info(dev, "failed to create msi top domain\n"); + ret = -ENODEV; + goto err_msi_top_domain; + } + + port->msi_info = devm_kzalloc(dev, PCIE_MSI_SET_NUM, GFP_KERNEL); + if (!port->msi_info) { + ret = -ENOMEM; + goto err_msi_info; + } + + for (i = 0; i < PCIE_MSI_SET_NUM; i++) { + int offset = i * PCIE_MSI_SET_OFFSET; + + msi_info = devm_kzalloc(dev, sizeof(*msi_info), GFP_KERNEL); + if (!msi_info) { + ret = -ENOMEM; + goto err_msi_set; + } + + msi_info->base = port->base + PCIE_MSI_ADDR_BASE_REG + offset; + msi_info->msg_addr = port->reg_base + PCIE_MSI_ADDR_BASE_REG + + offset; + + writel(lower_32_bits(msi_info->msg_addr), msi_info->base); + + msi_info->hwirq = i; + msi_info->index = i; + msi_info->domain = port->msi_domain; + + port->msi_info[i] = msi_info; + + /* Alloc irq for each msi set */ + msi_info->irq = irq_create_mapping(port->msi_top_domain, i); + if (msi_info->irq < 0) { + dev_info(dev, "allocate msi top irq failed\n"); + ret = -ENOSPC; + goto err_msi_set; + } + + val = readl(port->base + PCIE_INT_ENABLE_REG); + val |= (1 << (i + PCIE_MSI_SHIFT)); + writel(val, port->base + PCIE_INT_ENABLE_REG); + + val = readl(port->base + PCIE_MSI_SET_ENABLE_REG); + val |= (1 << i); + writel(val, port->base + PCIE_MSI_SET_ENABLE_REG); + } + + return 0; + +err_msi_set: + while (--i >= 0) { + msi_info = port->msi_info[i]; + irq_dispose_mapping(msi_info->irq); + } +err_msi_info: + irq_domain_remove(port->msi_top_domain); +err_msi_top_domain: + irq_domain_remove(port->msi_domain); +err_msi_domain: + irq_domain_remove(port->intx_domain); + + return ret; +} + +static void mtk_pcie_irq_teardown(struct mtk_pcie_port *port) +{ + struct mtk_pcie_msi *msi_info; + int i; + + irq_set_chained_handler_and_data(port->irq, NULL, NULL); + + if (port->intx_domain) + irq_domain_remove(port->intx_domain); + + if (port->msi_domain) + irq_domain_remove(port->msi_domain); + + if (port->msi_top_domain) { + for (i = 0; i < PCIE_MSI_SET_NUM; i++) { + msi_info = port->msi_info[i]; + irq_dispose_mapping(msi_info->irq); + } + + irq_domain_remove(port->msi_top_domain); + } + + irq_dispose_mapping(port->irq); +} + +static void mtk_pcie_irq_handler(struct irq_desc *desc) +{ + struct mtk_pcie_port *port = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long status; + u32 virq; + u32 irq_bit = PCIE_INTX_SHIFT; + + chained_irq_enter(irqchip, desc); + + status = readl(port->base + PCIE_INT_STATUS_REG); + if (status & PCIE_INTX_MASK) { + for_each_set_bit_from(irq_bit, &status, PCI_NUM_INTX + + PCIE_INTX_SHIFT) { + virq = irq_find_mapping(port->intx_domain, + irq_bit - PCIE_INTX_SHIFT); + generic_handle_irq(virq); + } + } + + if (status & PCIE_MSI_MASK) { + irq_bit = PCIE_MSI_SHIFT; + for_each_set_bit_from(irq_bit, &status, PCIE_MSI_SET_NUM + + PCIE_MSI_SHIFT) { + virq = irq_find_mapping(port->msi_top_domain, + irq_bit - PCIE_MSI_SHIFT); + generic_handle_irq(virq); + } + } + + chained_irq_exit(irqchip, desc); +} + +static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, + struct device_node *node) +{ + struct device *dev = port->dev; + struct platform_device *pdev = to_platform_device(dev); + int err; + + err = mtk_pcie_init_irq_domains(port, node); + if (err) { + dev_notice(dev, "failed to init PCIe IRQ domain\n"); + return err; + } + + port->irq = platform_get_irq(pdev, 0); + if (port->irq < 0) + return port->irq; + + irq_set_chained_handler_and_data(port->irq, mtk_pcie_irq_handler, port); + + return 0; +} + +static int mtk_pcie_clk_init(struct mtk_pcie_port *port) +{ + int ret; + + port->num_clks = devm_clk_bulk_get_all(port->dev, &port->clks); + if (port->num_clks < 0) { + dev_notice(port->dev, "failed to get pcie clock\n"); + return port->num_clks; + } + + ret = clk_bulk_prepare_enable(port->num_clks, port->clks); + if (ret) { + dev_notice(port->dev, "failed to enable pcie clocks\n"); + return ret; + } + + return 0; +} + +static int mtk_pcie_power_up(struct mtk_pcie_port *port) +{ + struct device *dev = port->dev; + int err; + + port->phy_reset = devm_reset_control_get_optional_exclusive(dev, + "phy-rst"); + if (IS_ERR(port->phy_reset)) + return PTR_ERR(port->phy_reset); + + reset_control_deassert(port->phy_reset); + + /* PHY power on and enable pipe clock */ + port->phy = devm_phy_optional_get(dev, "pcie-phy"); + if (IS_ERR(port->phy)) + return PTR_ERR(port->phy); + + err = phy_init(port->phy); + if (err) { + dev_notice(dev, "failed to initialize pcie phy\n"); + return err; + } + + err = phy_power_on(port->phy); + if (err) { + dev_notice(dev, "failed to power on pcie phy\n"); + goto err_phy_on; + } + + port->mac_reset = devm_reset_control_get_optional_exclusive(dev, + "mac-rst"); + if (IS_ERR(port->mac_reset)) + return PTR_ERR(port->mac_reset); + + reset_control_deassert(port->mac_reset); + + /* MAC power on and enable transaction layer clocks */ + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + err = mtk_pcie_clk_init(port); + if (err) { + dev_notice(dev, "clock init failed\n"); + goto err_clk_init; + } + + return 0; + +err_clk_init: + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + reset_control_assert(port->mac_reset); + phy_power_off(port->phy); +err_phy_on: + phy_exit(port->phy); + reset_control_assert(port->phy_reset); + + return -EBUSY; +} + +static void mtk_pcie_power_down(struct mtk_pcie_port *port) +{ + phy_power_off(port->phy); + phy_exit(port->phy); + + clk_bulk_disable_unprepare(port->num_clks, port->clks); + + pm_runtime_put_sync(port->dev); + pm_runtime_disable(port->dev); +} + +static int mtk_pcie_setup(struct mtk_pcie_port *port) +{ + struct device *dev = port->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *regs; + int err; + + regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac"); + port->base = devm_ioremap_resource(dev, regs); + if (IS_ERR(port->base)) { + dev_notice(dev, "failed to map register base\n"); + return PTR_ERR(port->base); + } + + port->reg_base = regs->start; + + /* Don't touch the hardware registers before power up */ + err = mtk_pcie_power_up(port); + if (err) + return err; + + /* Try link up */ + err = mtk_pcie_startup_port(port); + if (err) { + dev_notice(dev, "PCIe link down\n"); + goto err_setup; + } + + err = mtk_pcie_setup_irq(port, dev->of_node); + if (err) + goto err_setup; + + dev_info(dev, "PCIe link up success!\n"); + + return 0; + +err_setup: + mtk_pcie_power_down(port); + + return err; +} + +static int mtk_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_pcie_port *port; + struct pci_host_bridge *host; + int err; + + host = devm_pci_alloc_host_bridge(dev, sizeof(*port)); + if (!host) + return -ENOMEM; + + port = pci_host_bridge_priv(host); + + port->dev = dev; + platform_set_drvdata(pdev, port); + + err = mtk_pcie_setup(port); + if (err) + return err; + + host->ops = &mtk_pcie_ops; + host->sysdata = port; + + err = pci_host_probe(host); + if (err) { + mtk_pcie_power_down(port); + return err; + } + + return 0; +} + +static int mtk_pcie_remove(struct platform_device *pdev) +{ + struct mtk_pcie_port *port = platform_get_drvdata(pdev); + struct pci_host_bridge *host = pci_host_bridge_from_priv(port); + + pci_lock_rescan_remove(); + pci_stop_root_bus(host->bus); + pci_remove_root_bus(host->bus); + pci_unlock_rescan_remove(); + + mtk_pcie_irq_teardown(port); + mtk_pcie_power_down(port); + + return 0; +} + +static int __maybe_unused mtk_pcie_turn_off_link(struct mtk_pcie_port *port) +{ + int val; + + val = readl(port->base + PCIE_ICMD_PM_REG); + val |= PCIE_TURN_OFF_LINK; + writel(val, port->base + PCIE_ICMD_PM_REG); + + /* Check the link is L2 */ + return readl_poll_timeout(port->base + PCIE_LTSSM_STATUS_REG, val, + (PCIE_LTSSM_STATE(val) == + PCIE_LTSSM_STATE_L2_IDLE), 20, + 50 * USEC_PER_MSEC); +} + +static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) +{ + struct mtk_pcie_port *port = dev_get_drvdata(dev); + int err, val; + + if (port->is_suspended) + return 0; + + /* Trigger link to L2 state */ + err = mtk_pcie_turn_off_link(port); + if (err) { + dev_notice(port->dev, "can not enter L2 state\n"); + goto power_off; + } + + /* Pull down the PERST# pin */ + val = readl(port->base + PCIE_RST_CTRL_REG); + val |= PCIE_PE_RSTB; + writel(val, port->base + PCIE_RST_CTRL_REG); + + dev_info(port->dev, "enter L2 state success"); + +power_off: + phy_power_off(port->phy); + + clk_bulk_disable_unprepare(port->num_clks, port->clks); + + port->is_suspended = true; + + return 0; +} + +static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) +{ + struct mtk_pcie_port *port = dev_get_drvdata(dev); + int err; + + if (!port->is_suspended) + return 0; + + phy_power_on(port->phy); + + err = clk_bulk_prepare_enable(port->num_clks, port->clks); + if (err) { + dev_dbg(dev, "failed to enable pcie clocks\n"); + return err; + } + + err = mtk_pcie_startup_port(port); + if (err) { + dev_notice(port->dev, "resume failed\n"); + return err; + } + + port->is_suspended = false; + + dev_info(port->dev, "resume done\n"); + + return 0; +} + +static const struct dev_pm_ops mtk_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq, + mtk_pcie_resume_noirq) +}; + +static const struct of_device_id mtk_pcie_of_match[] = { + { .compatible = "mediatek,gen3-pcie" }, + { .compatible = "mediatek,mt8192-pcie" }, + {}, +}; + +static struct platform_driver mtk_pcie_driver = { + .probe = mtk_pcie_probe, + .remove = mtk_pcie_remove, + .driver = { + .name = "mtk-pcie", + .of_match_table = mtk_pcie_of_match, + .pm = &mtk_pcie_pm_ops, + }, +}; + +module_platform_driver(mtk_pcie_driver); +MODULE_LICENSE("GPL v2"); -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel