From patchwork Mon Aug 14 13:04:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Honghui Zhang X-Patchwork-Id: 9898913 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3B94A60230 for ; Mon, 14 Aug 2017 13:17:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2C03123E64 for ; Mon, 14 Aug 2017 13:17:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 202442860F; Mon, 14 Aug 2017 13:17:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4EBB123E64 for ; Mon, 14 Aug 2017 13:17:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.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=z5h/X/WmIeetQlBqZQzR2EcbMcKw+rIPQk3w0k5LGQw=; b=Qmrse58x0k19pP V/fTX1Ty/cChnJ1x/0PCat+ITbjr3K7irb/NEVE2cajjkVx+DtkS6BoPgwI0pBpQimCB7ai2sdtZA xjT/90Pwz+4H6tFWMglZ7lW3zjnBtEcw1J7aQRPEiWAU1biZgKakPubgfC8fUWmHVZbMGLsvwnmjO BYCuc23/Tl8v2lIonzpb+7KQcTGLgmpiRVQwRohIEieUz1hufMU3Bt5tiTofpghoEIbhBPXf67L4R YqL0xvA+qOb3dNT2oKiQG+X8+vWCSRrVPJ1xFe4yXB7nWpSJ1nKrrOZTRY7p8MOMI51qpcVvbT2Bi gKNQ6p24hqh47Oz9Xgeg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dhFFI-0007WS-LJ; Mon, 14 Aug 2017 13:17:28 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dhFFG-0007R4-Ca; Mon, 14 Aug 2017 13:17:26 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:CC:To:From:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=CWBrdzg0BHsDcCNnmZ+vNg0Xs1z+/AdpogHHlVylxD4=; b=HaA70u9dVLbH2sWxEQRkiySA9 Xwmr7P3EV+XW8pL7PzHXoBELSsoZASfS9HO2/8Ja9wDoiIMvNI+FyHxuO0f65CurIgNOPad/eZkgh 7wS6FjkJNpCTqzugKipJyqlOn4u4bzx6dPTGb4KKp9nrj9jT16ObFtlJM0+KAm0VUysimqPevo/Bf 6W3meunWyzqQ8P0IMkNCPGn+UWcuPyX8bzEYDlInxkWKaVZskbNAK0zPBoKIHUQzYRolvX6+MHQf9 ZuM0A/OxSI+chKc01WSnUbMxRDw+wby2CtcA3QsFs8CySJJgU1xoLkfhleXq+XBRita+rWt2M8Reu frhN21B2w==; Received: from [210.61.82.183] (helo=mailgw01.mediatek.com) by casper.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dhF3Q-0001WU-JV; Mon, 14 Aug 2017 13:05:17 +0000 Received: from mtkcas07.mediatek.inc [(172.21.101.84)] by mailgw01.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 1587312710; Mon, 14 Aug 2017 21:04:39 +0800 Received: from mtkcas09.mediatek.inc (172.21.101.178) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1210.3; Mon, 14 Aug 2017 21:04:37 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1210.3 via Frontend Transport; Mon, 14 Aug 2017 21:04:37 +0800 From: To: , , , , , , , , , Subject: [PATCH v2 3/3] PCI: mediatek: add msi support for MT2712 and MT7622 Date: Mon, 14 Aug 2017 21:04:28 +0800 Message-ID: <1502715868-17651-4-git-send-email-honghui.zhang@mediatek.com> X-Mailer: git-send-email 2.6.4 In-Reply-To: <1502715868-17651-1-git-send-email-honghui.zhang@mediatek.com> References: <1502715868-17651-1-git-send-email-honghui.zhang@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170814_140513_201274_33690F1C X-CRM114-Status: GOOD ( 24.27 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: youlin.pei@mediatek.com, hongkun.cao@mediatek.com, sean.wang@mediatek.com, xinping.qian@mediatek.com, honghui.zhang@mediatek.com, yt.shen@mediatek.com, yong.wu@mediatek.com Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Honghui Zhang MT2712 and MT7622's PCIe host controller support MSI, but only 32bit MSI address are supportted. It connect to GIC with the same IRQ number of INTx IRQ, so it shares the same IRQ with INTx IRQ. This patch add MSI support for MT2712 and MT7622. Signed-off-by: Honghui Zhang --- drivers/pci/host/pcie-mediatek.c | 148 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c index acc2e28..35ab232 100644 --- a/drivers/pci/host/pcie-mediatek.c +++ b/drivers/pci/host/pcie-mediatek.c @@ -73,11 +73,17 @@ #define PCIE_CSR_ASPM_L1_EN(x) BIT(1 + (x) * 8) /* PCIe V2 per-port registers */ +#define PCIE_MSI_VECTOR 0x0c0 #define PCIE_INT_MASK 0x420 #define INTX_MASK GENMASK(19, 16) #define INTX_SHIFT 16 #define INTX_NUM 4 #define PCIE_INT_STATUS 0x424 +#define MSI_STATUS BIT(23) +#define PCIE_IMSI_STATUS 0x42c +#define PCIE_IMSI_ADDR 0x430 +#define MSI_MASK BIT(23) +#define MTK_MSI_IRQS_NUM 32 #define PCIE_AHB_TRANS_BASE0_L 0x438 #define PCIE_AHB_TRANS_BASE0_H 0x43c @@ -128,11 +134,13 @@ struct mtk_pcie_port; /** * struct mtk_pcie_soc - differentiate between host generations + * @has_msi: whether this host support MSI interrupt or not * @ops: pointer to configuration access functions * @startup: pointer to controller setting functions * @setup_irq: pointer to initialize IRQ functions */ struct mtk_pcie_soc { + bool has_msi; struct pci_ops *ops; int (*startup)(struct mtk_pcie_port *port); int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node); @@ -156,6 +164,8 @@ struct mtk_pcie_soc { * @lane: lane count * @slot: port slot * @irq_domain: legacy INTx IRQ domain + * @msi_domain: MSI IRQ domain + * @msi_irq_in_use: bit map for assigned MSI IRQ */ struct mtk_pcie_port { void __iomem *base; @@ -172,6 +182,8 @@ struct mtk_pcie_port { u32 lane; u32 slot; struct irq_domain *irq_domain; + struct irq_domain *msi_domain; + DECLARE_BITMAP(msi_irq_in_use, MTK_MSI_IRQS_NUM); }; /** @@ -427,6 +439,108 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) return 0; } +static int mtk_pcie_assign_msi(struct mtk_pcie_port *port) +{ + int pos; + + pos = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM); + if (pos < MTK_MSI_IRQS_NUM) + set_bit(pos, port->msi_irq_in_use); + else + return -ENOSPC; + + return pos; +} + +static int mtk_pcie_msi_setup_irq(struct msi_controller *chip, + struct pci_dev *pdev, + struct msi_desc *desc) +{ + struct mtk_pcie_port *port; + struct msi_msg msg; + int hwirq; + u32 irq; + + port = mtk_pcie_find_port(pdev->bus, pdev->devfn); + if (!port) + return -EINVAL; + + chip->dev = &pdev->dev; + hwirq = mtk_pcie_assign_msi(port); + if (hwirq < 0) + return hwirq; + + irq = irq_create_mapping(port->msi_domain, hwirq); + if (!irq) + return -EINVAL; + + irq_set_msi_desc(irq, desc); + + /* MT2712/MT7622 only support 32 bit MSI address */ + msg.address_hi = 0; + msg.address_lo = lower_32_bits((u64)(port->base + PCIE_MSI_VECTOR)); + msg.data = hwirq; + + pci_write_msi_msg(irq, &msg); + + return 0; +} + +static void mtk_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) +{ + struct pci_dev *pdev = to_pci_dev(chip->dev); + struct irq_data *d = irq_get_irq_data(irq); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct mtk_pcie_port *port; + + port = mtk_pcie_find_port(pdev->bus, pdev->devfn); + if (!port) + return; + + if (!test_bit(hwirq, port->msi_irq_in_use)) + dev_err(&pdev->dev, "trying to free unused MSI#%d\n", irq); + else + clear_bit(hwirq, port->msi_irq_in_use); +} + +static struct msi_controller mtk_pcie_msi_chip = { + .setup_irq = mtk_pcie_msi_setup_irq, + .teardown_irq = mtk_msi_teardown_irq, +}; + +static struct irq_chip mtk_msi_irq_chip = { + .name = "MTK PCIe MSI", + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + +static int mtk_pcie_msi_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &mtk_msi_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops msi_domain_ops = { + .map = mtk_pcie_msi_map, +}; + +static void mtk_pcie_enable_msi(struct mtk_pcie_port *port) +{ + u32 val; + + val = lower_32_bits((u64)(port->base + PCIE_MSI_VECTOR)); + writel(val, port->base + PCIE_IMSI_ADDR); + + val = readl(port->base + PCIE_INT_MASK); + val &= ~MSI_MASK; + writel(val, port->base + PCIE_INT_MASK); +} + static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) { @@ -460,6 +574,18 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, return -ENODEV; } + /* Setup MSI */ + if (IS_ENABLED(CONFIG_PCI_MSI)) { + port->msi_domain = irq_domain_add_linear(node, MTK_MSI_IRQS_NUM, + &msi_domain_ops, + &mtk_pcie_msi_chip); + if (!port->msi_domain) { + dev_err(dev, "failed to get MSI IRQ domain\n"); + return -ENODEV; + } + mtk_pcie_enable_msi(port); + } + return 0; } @@ -480,6 +606,23 @@ static irqreturn_t mtk_pcie_intr_handler(int irq, void *data) } } + if (IS_ENABLED(CONFIG_PCI_MSI)) { + while ((status = readl(port->base + PCIE_INT_STATUS)) & MSI_STATUS) { + unsigned long imsi_status; + + while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) { + for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) { + /* Clear the MSI */ + writel(1 << bit, port->base + PCIE_IMSI_STATUS); + virq = irq_find_mapping(port->msi_domain, bit); + generic_handle_irq(virq); + } + } + /* Clear MSI interrupt status */ + writel(MSI_STATUS, port->base + PCIE_INT_STATUS); + } + } + return IRQ_HANDLED; } @@ -501,7 +644,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, err = mtk_pcie_init_irq_domain(port, node); if (err) { - dev_err(dev, "failed to init PCIe legacy IRQ domain\n"); + dev_err(dev, "failed to init PCIe IRQ domain\n"); return err; } @@ -938,6 +1081,8 @@ static int mtk_pcie_register_host(struct pci_host_bridge *host) host->map_irq = of_irq_parse_and_map_pci; host->swizzle_irq = pci_common_swizzle; host->sysdata = pcie; + if (IS_ENABLED(CONFIG_PCI_MSI) && pcie->soc->has_msi) + host->msi = &mtk_pcie_msi_chip; err = pci_scan_root_bus_bridge(host); if (err < 0) @@ -999,6 +1144,7 @@ static const struct mtk_pcie_soc mtk_pcie_soc_v1 = { }; static const struct mtk_pcie_soc mtk_pcie_soc_v2 = { + .has_msi = true, .ops = &mtk_pcie_ops_v2, .startup = mtk_pcie_startup_port_v2, .setup_irq = mtk_pcie_setup_irq,