From patchwork Thu Sep 17 09:28:47 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Minghuan Lian X-Patchwork-Id: 7204221 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 638739F380 for ; Thu, 17 Sep 2015 09:30:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 249E6207CE for ; Thu, 17 Sep 2015 09:30:30 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 44F6D206FF for ; Thu, 17 Sep 2015 09:30:28 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZcVUl-0004ev-Jn; Thu, 17 Sep 2015 09:28:47 +0000 Received: from mail-by2on0133.outbound.protection.outlook.com ([207.46.100.133] helo=na01-by2-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZcVUZ-0004Sx-1Q for linux-arm-kernel@lists.infradead.org; Thu, 17 Sep 2015 09:28:36 +0000 Received: from CO2PR03CA0032.namprd03.prod.outlook.com (10.141.194.159) by CY1PR0301MB0633.namprd03.prod.outlook.com (10.160.158.139) with Microsoft SMTP Server (TLS) id 15.1.268.17; Thu, 17 Sep 2015 09:28:12 +0000 Received: from BL2FFO11FD047.protection.gbl (2a01:111:f400:7c09::162) by CO2PR03CA0032.outlook.office365.com (2a01:111:e400:1414::31) with Microsoft SMTP Server (TLS) id 15.1.280.12 via Frontend Transport; Thu, 17 Sep 2015 09:28:12 +0000 Authentication-Results: spf=fail (sender IP is 192.88.158.2) smtp.mailfrom=freescale.com; freescale.mail.onmicrosoft.com; dkim=none (message not signed) header.d=none; freescale.mail.onmicrosoft.com; dmarc=none action=none header.from=freescale.com; Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.158.2 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.158.2; helo=az84smr01.freescale.net; Received: from az84smr01.freescale.net (192.88.158.2) by BL2FFO11FD047.mail.protection.outlook.com (10.173.161.209) with Microsoft SMTP Server (TLS) id 15.1.262.18 via Frontend Transport; Thu, 17 Sep 2015 09:28:12 +0000 Received: from lmh.ap.freescale.net (lmh.ap.freescale.net [10.193.20.20]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id t8H9S4oK029809; Thu, 17 Sep 2015 02:28:08 -0700 From: Minghuan Lian To: Subject: [PATCH 2/2] irqchip/Layerscape: Add Layerscape MSI controller support Date: Thu, 17 Sep 2015 17:28:47 +0800 Message-ID: <1442482127-32674-2-git-send-email-Minghuan.Lian@freescale.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1442482127-32674-1-git-send-email-Minghuan.Lian@freescale.com> References: <1442482127-32674-1-git-send-email-Minghuan.Lian@freescale.com> X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD047; 1:9dg4fI1QQevlCHVaJzSXbHZiLJhRRHayCajknrGAWI4vUXKfO7BPGZU8kyNW0WgeS+uc7tZdp9qun2ce9rPDOpRHegtKe16XRvP5xYSPmJFWIFhcnWlo7/7yhVfQCfDDUd9jM3o7QtYDLYs9T4Fw2+jrhhLIq5EV3FjodLFAFpuyy7w/uUicCsEb7ud0WAZxxV2KECo/YqwQbNt04D+iQ1HRHDiFl83tOCdOrNT7s7UpYAOYXACLprN2H/hjj/2Ety1T0WNbz9ZiqKRklDFM9xbfzTRf6ar7g1FHOPhCmy3wwnRTvN6iea+6IF+QT1LwMQkuLxqsXcsdv5N5WCFvv8WAOl3F+2d+2ofPN6pGF84CRSRX+2bVosBsvAGGoREi4SQmHNTvh0GuPg1+swCvgA== X-Forefront-Antispam-Report: CIP:192.88.158.2; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(1109001)(1110001)(339900001)(189002)(199003)(105606002)(229853001)(19580405001)(5001860100001)(104016003)(2351001)(106466001)(76176999)(107886002)(81156007)(4001540100001)(5001960100002)(97736004)(5001830100001)(189998001)(36756003)(11100500001)(110136002)(19580395003)(6806004)(2950100001)(92566002)(5007970100001)(5003940100001)(50986999)(68736005)(46102003)(86362001)(85426001)(77096005)(47776003)(62966003)(64706001)(87936001)(50226001)(48376002)(50466002)(69596002)(77156002)(2004002)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:CY1PR0301MB0633; H:az84smr01.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0633; 2:siyTIpfVXMNm2EDiHnYKlFIQojs6rimlsFypeX/UuaWIYKLtRYsukbdAWdRApW2gApVZ0Dew22s+MbaW+6KjMnXwju4YWQgMtA6y5imCmmO2ina62VtCQpPZdrn+RcLakmAfxDqp93GKHCa6NLu+uDVO+bxZqBmECw8zsDzKajE=; 3:DnpuKSMRULrxogXXdbekhjhUwIcul7FmObpf1gr8PKe/SQ8qxOPSSE3kfQmbE7d+k7ooXASlkWzTVQE0NMUXhdlB4qUQcUF5y/IEKr5DzAEd8/EPzLCh7BgJIZHyllM6wbq4ZXqrCUpi2DKDZPNgfOvj7RNT1JTAJNrF1UKnSddvwxk6Os+4aHTxGpuzDLzEsaQso90+rnCRLJxHV32asQuYDHttd3pPuvutSVxMv6M=; 25:9q6PU2H6HIgD+qh45GSjxTDvjS848gYOGOFdDGWCJpHTaLIe8Ff87I1Iqq4rJ43nr4KAx4JNOeJYQ0aGhDkCjmbvNoS4T6ZEgG21Jxv7XL0uho65/L+2tL5TEV494TZFA26WS5yEQnYTm31JgDnpYHAuZ4mCp7NBPIOg/ygV+TusBxCKsvwbs3lNm/VC/bj2Bd8lPibqULOxXiAAPuCFNi4y6b9kqzARpZg1lBGsyCj46moP9irSVxiBad03zgyZ X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR0301MB0633; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0633; 20:5zZAr/OePq9uTd48pmzFLvYVmMK+Rq7JAINVdEgRvvTrTHcro4FmKhDA8sIKRQGv1adRf/xYg631VjqPLO1pS/VS/L9mBtcRpY+wU1UNrkU6KbmF84Zul6gZiPVsfP6nso5LeFKuqToeviPVMeGT7yhoeRusGw5Krne/Sm/QlVzHYOX8xcOEg2Y1eJSNRIPGC9dnGmBiaYRFWd9OhI3KYckAOgeJ0hHLIo/A3AeEE32A8xKNcy9uem8mQkj4sEBsXqAWtYIQnNJoFl0+CgCgNwB4jYHsTPMtrbSx2H/+zVmVVMbut0JUyiRvUu/Ckm1YWXGhT3AB1RMWMcCvsfMFakhW47QV3NJeH9QfGIeE3sY=; 4:aWPYGxgubFy5vLSVHKVHboEMOH2LHCwIs+/hr+ClIPm3mdT2X4ZNEdvii9gUYOCYLpJHTiFyJIspSJfEOrSTJsjFLoAt5cwcrHC5BqMwgsOl+TpKOEx8XQ4PAlKFf2AuUQ7b4+r1jmfa++UroWENdh0DSkTeff9kbbp5ZHTXabgU3n1BdB2AfqfDpfNR1MZ4xW5EDNamlRGRi8CW4HaVEE6G3FdIJ2c+LKipW9q3MMc4i6GACTBgShOqYVKmihJheBis68c15basf7QyWuDOiuLUyYH48/Y+Fa2DehWPIfLJGG3MirSWACCogh0ohPyLHkVicZT38ueIVwmeIXq+aRax03rcFsEXKJg7dbn+FoVVsPOjRoSZwcTpRLl2KAuf X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(520078)(520058)(520075)(8121501046)(3002001); SRVR:CY1PR0301MB0633; BCL:0; PCL:0; RULEID:; SRVR:CY1PR0301MB0633; X-Forefront-PRVS: 07025866F6 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR0301MB0633; 23:OZaAHT1Lyi5ZY/lOGb/0e2fmYFk8Z2NPjVjpwrz?= =?us-ascii?Q?8Ru1PusJhaDeG7JU12LHNp7doFrtL9EDKi/OPUeLO3/Kjlfp2bTXxPlzESPL?= =?us-ascii?Q?+XGUvMaQBttVPiL9ThYCYzyRcmcWh3GcRob2WPm2Uh4WMJAbGhYRZQLKi5Pd?= =?us-ascii?Q?fYf8EQg/XGzpy0LuuSQFDm73dVz1p0rNI2b4sv4+U/5EjaW9Wxq9nWDoCTeT?= =?us-ascii?Q?Xir8mK0wWGDZtR1Q3MFl0y8G1VXrvCKQZLKTO7MaFPVXZktfvmaVhAJKdOn+?= =?us-ascii?Q?VGO6LwZYz+/tWasHQeqNvxTzX700meerAss2TTZQxYqxAqjhxe2fgSb3QJ6y?= =?us-ascii?Q?RmR+Y19YS9TnRTcocC5IPpzv0KY1c45JKAWsOQbZ7NJ0gEkhT4SGkgoaMD8E?= =?us-ascii?Q?/PwsI0MkDrgirLlxOu+1m22KLuOmv+jxcJ4vCkyyhTB4Et0BWxPdtFEkGpJL?= =?us-ascii?Q?GWwturF2WfKn0r4Fs/QiomsbiuGo3+VFlQUo0+X+0lQNHwhG7M9EYCa34Lsx?= =?us-ascii?Q?PozSAwpR8Sp6GG9P84Svo98fP/I0Ks0sCGvIsVpSDYRxeVSWBQ97aS0o9xJn?= =?us-ascii?Q?AYsT2l9nq22QdnFcgx8fzG4iP0gTUp7SO5K0EL9Z3uoOmhBosr9yqPzJBYAm?= =?us-ascii?Q?ZzzIJqtO1CRYCtRDvQdodE8puyLEj9JdctUbfwzgPoADy10gFC5puISl3HR7?= =?us-ascii?Q?f+whPUtNX5K+UMsp9XW53awfzK96Y4y6mG7OoRA/8TfDuBv63hTTm25dPqBF?= =?us-ascii?Q?OyAEK3r0QJ1nN3C1YM2D7SM2BaD4jQooYd04MixV1NFeWaoFO29FJ8S1Gc2A?= =?us-ascii?Q?qVKaRuVKzGaJ055MX2OH2Nvn61BOnnRJDazc+JK5euz3zx4N9c9QvFyqS/7I?= =?us-ascii?Q?HZTk6+YOHMKPko/9wOmh1ICkRA7iEInkjbWyXbhO4s8Rc4n/Oxpgk8BQSe4y?= =?us-ascii?Q?r88IXtuV88IKoFyDgnXxuRZE0mz9i7DbOlhekuiqBEH3EKLhDd1p8OMR3Quk?= =?us-ascii?Q?kAn2yA8OP0O/4lSVlpLPNZvCouixeHwiD3Z0t5BRpJgzNGkp6GWSRgrsy1zJ?= =?us-ascii?Q?lPuMr7HcYIWWmfgkoCTlw9B5VsXSEO2gTqYqhvZ8duAWWH05QI7AD10X2qpI?= =?us-ascii?Q?9mSp1JeY2e0mcWhKwCQpkzjB1skQI7TCTtMClCk+9Gn/ZyP6u3iHiHf5DzAS?= =?us-ascii?Q?rEtGjFNKVd/hTHoaNs+Vp6asUkKbCvSvM0k1mYSFFy45LTICzqlpHYo4J0A9?= =?us-ascii?Q?ZXHTBNUOv3YOw4q8lJZFuFK1Apsx37rqqJBa/IKZU?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0633; 5:uqFP9+eAXr3XG+rYkEws4Og+mhAVx2RILYs83sdzfdIy1/E15OUY0z/m1zEqIpUEZndVL+nvKGKb+2rlTmLeREiLxJI6xh6HUPpLMlWnjUGBGefbNnuXLAXEVDTkVT81fig6fsUPmvG0Gte+HtQ5Jw==; 24:64caJltX31ibnGP2kOI+51J88NExqdggXHYIpAlbBE9buegBzeB65u397Xp4gB+culXxm24jdKQzLJaQmPbnRYRBxuRcFlSu9NJ/HFFl+Kc=; 20:01X1mS+sNAL0J8rMHPD1yf3VdvCUi3ligAqMmpAtALOrjD3U6sP70f33uafmD7p6DJBWPF5EZHAJXkS8nut7Pg== X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Sep 2015 09:28:12.0836 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.158.2]; Helo=[az84smr01.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR0301MB0633 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150917_022835_163489_31FC5A7D X-CRM114-Status: GOOD ( 23.91 ) X-Spam-Score: -1.9 (-) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jason Cooper , Hu Mingkai-B21284 , Yoder Stuart-B08248 , Zang Roy-R61911 , Minghuan Lian , Thomas Gleixner , Li Yang Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some SoC of Freescale Layerscape provide a kind of MSI controller which uses two registers MSIIR and MSIR to support 32 MSI interrupts for each PCIe controller. The patch is to support it. Signed-off-by: Minghuan Lian --- .../bindings/interrupt-controller/fsl,ls1-msi.txt | 26 +++ arch/arm/mach-imx/Kconfig | 1 + drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-ls1-msi.c | 247 +++++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/fsl,ls1-msi.txt create mode 100644 drivers/irqchip/irq-ls1-msi.c diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls1-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls1-msi.txt new file mode 100644 index 0000000..29296c1 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls1-msi.txt @@ -0,0 +1,26 @@ +* Freescale Layerscape PCIe MSI controller + +Required properties: + +- compatible: should be "fsl,-msi" to identify + Layerscape PCIe MSI controller block. +- msi-controller: indicates that this is a PCIe MSI controller node +- reg: Should contain msiir and msir registers location and length. + MSIIR is a MSI index register to trigger interrupts. + MSIR indicates which of the 32 interrupt sources have pending interrupt. +- reg-names: should be "msiir" and "msir". +- interrupts: A interrupt of the controller. + +Each PCIe node needs to have property msi-parent that points to +MSI controller node + +Examples: + + msi1: msi-controller1@1571000 { + compatible = "fsl,1s1043a-msi"; + reg = <0x0 0x1571000 0x0 0x4>, + <0x0 0x1571004 0x0 0x4>; + reg-names = "msiir", "msir"; + msi-controller; + interrupts = <0 116 0x4>; + }; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 8ceda28..fe64598 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -570,6 +570,7 @@ config SOC_LS1021A select ARM_GIC select HAVE_ARM_ARCH_TIMER select PCI_DOMAINS if PCI + select LS1_MSI if PCI_MSI select ZONE_DMA if ARM_LPAE help This enables support for Freescale LS1021A processor. diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 27b52c8..1da26b1 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -187,3 +187,8 @@ config IMX_GPCV2 select IRQ_DOMAIN help Enables the wakeup IRQs for IMX platforms with GPCv2 block + +config LS1_MSI + bool + depends on PCI && PCI_MSI + select PCI_MSI_IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index bb3048f..5241aa7 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -55,3 +55,4 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o +obj-$(CONFIG_LS1_MSI) += irq-ls1-msi.o diff --git a/drivers/irqchip/irq-ls1-msi.c b/drivers/irqchip/irq-ls1-msi.c new file mode 100644 index 0000000..cf836b6 --- /dev/null +++ b/drivers/irqchip/irq-ls1-msi.c @@ -0,0 +1,247 @@ +/* + * Layerscape MSI(-X) support + * + * Copyright (C) 2015 Freescale Semiconductor. + * + * Author: Minghuan Lian + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSI_MAX_IRQS 32 +#define MSI_IBS_SHIFT 3 + +struct ls1_msi { + spinlock_t lock; + struct platform_device *pdev; + struct irq_domain *parent; + struct irq_domain *msi_domain; + void __iomem *msir; + phys_addr_t msiir_addr; + u32 nr_irqs; + int irq; + DECLARE_BITMAP(used, MSI_MAX_IRQS); +}; + +static struct irq_chip ls1_msi_irq_chip = { + .name = "MSI", + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + +static struct msi_domain_info ls1_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | + MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX), + .chip = &ls1_msi_irq_chip, +}; + +static void ls1_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct ls1_msi *msi_data = irq_data_get_irq_chip_data(data); + + msg->address_hi = upper_32_bits(msi_data->msiir_addr); + msg->address_lo = lower_32_bits(msi_data->msiir_addr); + msg->data = data->hwirq << MSI_IBS_SHIFT; +} + +static int ls1_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) +{ + return -EINVAL; +} + +static struct irq_chip ls1_msi_parent_chip = { + .name = "LS1 MSI", + .irq_compose_msi_msg = ls1_msi_compose_msg, + .irq_set_affinity = ls1_msi_set_affinity, +}; + +static int ls1_msi_domain_irq_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *args) +{ + struct ls1_msi *msi_data = domain->host_data; + int pos, err = 0; + + WARN_ON(nr_irqs != 1); + + spin_lock(&msi_data->lock); + pos = find_first_zero_bit(msi_data->used, msi_data->nr_irqs); + if (pos < msi_data->nr_irqs) + __set_bit(pos, msi_data->used); + else + err = -ENOSPC; + spin_unlock(&msi_data->lock); + + if (err) + return err; + + irq_domain_set_info(domain, virq, pos, + &ls1_msi_parent_chip, msi_data, + handle_simple_irq, NULL, NULL); + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +static void ls1_msi_domain_irq_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct ls1_msi *msi_data = irq_data_get_irq_chip_data(d); + int pos; + + pos = d->hwirq; + if (pos < 0 || pos >= msi_data->nr_irqs) { + pr_err("failed to teardown msi. Invalid hwirq %d\n", pos); + return; + } + + spin_lock(&msi_data->lock); + __clear_bit(pos, msi_data->used); + spin_unlock(&msi_data->lock); +} + +static const struct irq_domain_ops ls1_msi_domain_ops = { + .alloc = ls1_msi_domain_irq_alloc, + .free = ls1_msi_domain_irq_free, +}; + +static void ls1_msi_irq_handler(unsigned int __irq, struct irq_desc *desc) +{ + struct ls1_msi *msi_data = irq_desc_get_handler_data(desc); + unsigned long val; + int pos, virq; + + chained_irq_enter(irq_desc_get_chip(desc), desc); + + val = ioread32be(msi_data->msir); + for_each_set_bit(pos, &val, msi_data->nr_irqs) { + virq = irq_find_mapping(msi_data->parent, (31 - pos)); + if (virq) + generic_handle_irq(virq); + } + + chained_irq_exit(irq_desc_get_chip(desc), desc); +} + +static int ls1_msi_domains_init(struct ls1_msi *msi_data) +{ + /* Initialize MSI domain parent */ + msi_data->parent = irq_domain_add_linear(NULL, + msi_data->nr_irqs, + &ls1_msi_domain_ops, + msi_data); + if (!msi_data->parent) { + dev_err(&msi_data->pdev->dev, "failed to create IRQ domain\n"); + return -ENOMEM; + } + + msi_data->msi_domain = + pci_msi_create_irq_domain(msi_data->pdev->dev.of_node, + &ls1_msi_domain_info, + msi_data->parent); + if (!msi_data->msi_domain) { + dev_err(&msi_data->pdev->dev, "failed to create MSI domain\n"); + irq_domain_remove(msi_data->parent); + return -ENOMEM; + } + + return 0; +} + +static int ls1_msi_probe(struct platform_device *pdev) +{ + struct ls1_msi *msi_data; + struct resource *res; + int ret; + + msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL); + if (!msi_data) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msiir"); + if (!res) { + dev_err(&pdev->dev, "missed msiir.\n"); + return -ENODEV; + } + msi_data->msiir_addr = res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "msir"); + msi_data->msir = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(msi_data->msir)) { + dev_err(&pdev->dev, "failed to initialize MSIR.\n"); + return PTR_ERR(msi_data->msir); + } + + msi_data->irq = platform_get_irq(pdev, 0); + if (msi_data->irq <= 0) { + dev_err(&pdev->dev, "failed to get MSI irq\n"); + return -ENODEV; + } + + msi_data->pdev = pdev; + msi_data->nr_irqs = MSI_MAX_IRQS; + spin_lock_init(&msi_data->lock); + + ret = ls1_msi_domains_init(msi_data); + if (ret) + return ret; + + irq_set_chained_handler_and_data(msi_data->irq, + ls1_msi_irq_handler, + msi_data); + + platform_set_drvdata(pdev, msi_data); + + return 0; +} + +static int ls1_msi_remove(struct platform_device *pdev) +{ + struct ls1_msi *msi_data = platform_get_drvdata(pdev); + + irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL); + + irq_domain_remove(msi_data->msi_domain); + irq_domain_remove(msi_data->parent); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +static const struct of_device_id ls1_msi_id[] = { + { .compatible = "fsl,1s1021a-msi", }, + { .compatible = "fsl,1s1043a-msi", }, + {}, +}; + +static struct platform_driver ls1_msi_driver = { + .driver = { + .name = "ls1-msi", + .of_match_table = ls1_msi_id, + }, + .probe = ls1_msi_probe, + .remove = ls1_msi_remove, +}; + +module_platform_driver(ls1_msi_driver); + +MODULE_AUTHOR("Minghuan Lian "); +MODULE_DESCRIPTION("Freescale Layerscape1 MSI controller driver"); +MODULE_LICENSE("GPL v2");