From patchwork Fri Oct 16 07:00:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Minghuan Lian X-Patchwork-Id: 7411141 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7902FBEEA4 for ; Fri, 16 Oct 2015 07:02:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AA97E2086C for ; Fri, 16 Oct 2015 07:02:35 +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 550CE208C8 for ; Fri, 16 Oct 2015 07:02:34 +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 1Zmz05-0008IF-NA; Fri, 16 Oct 2015 07:00:25 +0000 Received: from mail-bn1on0118.outbound.protection.outlook.com ([157.56.110.118] helo=na01-bn1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zmyzy-00077J-3D for linux-arm-kernel@lists.infradead.org; Fri, 16 Oct 2015 07:00:19 +0000 Received: from BN3PR0301CA0051.namprd03.prod.outlook.com (10.160.152.147) by BN3PR0301MB1252.namprd03.prod.outlook.com (10.161.207.28) with Microsoft SMTP Server (TLS) id 15.1.293.16; Fri, 16 Oct 2015 06:59:54 +0000 Received: from BL2FFO11FD040.protection.gbl (2a01:111:f400:7c09::120) by BN3PR0301CA0051.outlook.office365.com (2a01:111:e400:401e::19) with Microsoft SMTP Server (TLS) id 15.1.300.14 via Frontend Transport; Fri, 16 Oct 2015 06:59:54 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) 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.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BL2FFO11FD040.mail.protection.outlook.com (10.173.161.136) with Microsoft SMTP Server (TLS) id 15.1.293.9 via Frontend Transport; Fri, 16 Oct 2015 06:59:54 +0000 Received: from lmh.ap.freescale.net (lmh.ap.freescale.net [10.193.20.20]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id t9G6xkA5019540; Thu, 15 Oct 2015 23:59:50 -0700 From: Minghuan Lian To: Subject: [PATCH v2 2/2] irqchip/Layerscape: Add SCFG MSI controller support Date: Fri, 16 Oct 2015 15:00:38 +0800 Message-ID: <1444978838-18412-2-git-send-email-Minghuan.Lian@freescale.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1444978838-18412-1-git-send-email-Minghuan.Lian@freescale.com> References: <1444978838-18412-1-git-send-email-Minghuan.Lian@freescale.com> X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD040; 1:DNwOEBAXDW6oEsGVHAZqua1ri4hMoaHBKoVe9k3k4X9f4ZLxp3elUtKXksPXDaaWpZzh+csg+hI2ibLp5YYBt7uhJoLTq0JYE/N3wofmozFXVQ/+VmHqJQ+skXLs5/xQxXv5GUgighBGb8405VI4iZN9k6aqh8lb6HkqXWgtxfCqFn4D9mn0NLI4u1qHj0zNHq7tykz+ykhyrSnnPTDo6VtFBuhbTTz4LCgw6/eqPCTI2cW058VLzwQaBpCGvR0EwcNchpVo0aDynioAPzcbPE7ntpioExh62xTJptiTvHZl1jM+WhgnJTJV4HjYpcL47wy84c6kBCPCblJU+VFggwIWwQvrJ0ozJlf/vHY0VKzyGiUAlVZ1TIBvsY5rk48TnGy4aXpxMBJIvo5gn9s50w== X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(1109001)(1110001)(339900001)(54534003)(199003)(189002)(5001960100002)(64706001)(6806005)(81156007)(77096005)(50986999)(5008740100001)(2351001)(97736004)(107886002)(5003940100001)(36756003)(110136002)(92566002)(87936001)(50226001)(2950100001)(104016004)(19580405001)(46102003)(85426001)(106466001)(189998001)(11100500001)(76176999)(47776003)(48376002)(50466002)(5007970100001)(86362001)(19580395003)(105606002)(229853001)(2004002)(4001430100001)(217873001); DIR:OUT; SFP:1102; SCL:1; SRVR:BN3PR0301MB1252; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1252; 2:FHzkzMzN09kaOcmw+NeZJ6oBXkURAb1jZ2LXekErnLIl2lOh1RgMuBOaEDVTtsRxLe5UN5LtKx2sESA8qxrni0TwIB96101r53oV7bd8FLIJVHkrNQXP5k3UeE6kBn0zNO4f2Nm8w8VzAmtkW/mAZSKIj/3oAOfnR+pNGGxmZ0Q=; 3:zpFP3h7kcmLH/qrH5SwGQVrxnkxBBHtpP+p4A9NU4oQUvOEPXvqo+zAHG5k7yn7eJBDhj1AnNOEkfxsypcQaAMDD469KtT6sdtj+jHJmu31+CfWTlaTKWvC2oSSTgW9i58Gr+u7dsy3Dtip2Svp+zBUFQih1DWZseLgyEjnI1nBpa8Q+vn5I6dFDACHbwWAHb5zUUvpo1j5VKQMc0CR22kJ1DPB+j9CoU6d5kz+/JOA=; 25:G8HIu6Tey4lJy40CPs4ypIgKN3VVjRZDUz2j9+FrTb2/g3CMfS2OEaBerenxfv4vEA+NwHLU2xlEXOBIB5mnBUb83iI58gt/H4HORlgTCvbS0aR3dHh0O/NlaP/bGH1LqUKYCvYIDwHkbZL5j9BaQCzZD7i3YuDVQSGHXnIIkEiTedZ53J2JlHfk6LX/EZ3mDRgxEfg8ImaCbTgaAu0XgkmQ5pj5cd0Y67IVk4R8ORJUYKeELbXG8f3GKN+ra+7G X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN3PR0301MB1252; X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1252; 20:MBOcKG7yG8J5im/pLzQdO1oA2eqJ++rmatJG4jIx56cmnVWXbsaXBkYpZZtxPZ/MqNsaYH43H7LYfnqHLgmMg9aBg4Mgq635KU4k91xxMfQYerzcKv+AfSq2wyBgtCaXqNlIxZe+TMMy6L0+iX/delRrAt82nbpo71709TxpIFePV1oQkbAAdfboPTGrYmkaNDn4Mm6URRjHFMm2nEsld9OOduQWmTt8vU8Ih0RWe11OqXyjuzazjOLV8zXqnzR+3dVyUzCg8InMn3KQkm9alGiiNh0bu4/YUtzWTLUuu2j5AMoodsOC25nwbV2d4vb/3Jcl/v7QmofKzL0CrrNoikq96zBtr7WqW/x4vD+Yl4I=; 4:6GriLr+z8he2Mgsm4kOPDxxSfWoSiSJMgB158QvYw1aMVPSTUJ7w246pbq6jfgtJRKZBQdKqrHQIyMVJOOHVdHt/6N+wuERP8CMecAqqJ3e+15jlpx80kqIedsEM9dGy067704veFgiOODhPgQ1qDKCoOo9BKrLucqbXBv54pwrwoKC6/KjQemlytVQb6Q7N7ECuE/XOeHqPNbJCPVJ2giktR0sYzs66sGCw67VErVCjy1mRGcZ9Uy3qB576DV1beWQrsLzfeau6FxN7kWAJcJqzjhqHPYf++b4pneu24CU9ay5eoHQP4TNADV7igVX73UJWIuzyIN9CA4kdmRjDUtSfLkm6SVm9PjUngM9gZd4= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(101931422205132); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(8121501046)(520078)(5005006)(3002001); SRVR:BN3PR0301MB1252; BCL:0; PCL:0; RULEID:; SRVR:BN3PR0301MB1252; X-Forefront-PRVS: 0731AA2DE6 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN3PR0301MB1252; 23:xYBVca0moJg91oIQaMDLCfyerqg7vt8+0UOf6zb?= =?us-ascii?Q?COKsHmHEY34sQgMt8qqjKo72M+TYZI8ze67a+THuIyAlovQcd1/jzdNESMN0?= =?us-ascii?Q?qFX2KZTOCaW3CuEdqvM7hf7Nu0PDBTn7px5XQNivU+iq2C1tyDveiLCqLNb3?= =?us-ascii?Q?FJQysyc8wTUiLkhQg1LuqXrfl5w4gN/fylzSGxiF/pRQbfT6XJuFlWLJesXD?= =?us-ascii?Q?g6kbvPLCXFXyFtl+ZbuZH8/TANHBiJ4XjfwbK2CGXb4QlDPrHo6jwA//usFL?= =?us-ascii?Q?g1prxBYtcIchmJgtFqoT9l8QVmOM2vwBbbbJO3oDcAwMOheBY22hovqK4plz?= =?us-ascii?Q?HeP7vmnbSgQWXSI+ZnlrBQ954TUi+O335hH4NpRWDByvlKu/XOD2zCR73Ga0?= =?us-ascii?Q?38W6+TB22g+HHL0OJaw0g5PMJZsERimb9cbT0aCYZkaqSQo5oIoQSzK9knzB?= =?us-ascii?Q?hrStjIpuFQQlQXRE7yUbH1qmr4iy7DocvRwb0a22hIDdeqgseFKE9lS6elOC?= =?us-ascii?Q?DmMui/9ifgmEIV1IwHlr66ICk7XZ4bUnBJKxbF9a1jsHRFBUSxHD/ob4U0qA?= =?us-ascii?Q?NnZipRSD7ZZcbzJXBfgfee+oCC5e1fGb639+yyjKSxq+pfSGUgRVCjO6aYfF?= =?us-ascii?Q?j6WypOoYRAw6DfIjN83JXgBu39iMOy+Ikb4o94+D8E09XyN9pmJpGKSHimDt?= =?us-ascii?Q?46d8ut0YAxYgasOOUOW+/C+yFKcGKASNiN5vzbdfmY1HzfaCtbHt5bgEZeBT?= =?us-ascii?Q?oQSPXt2z2vbmK358DEioIS6F6Cbgd5RTrMn/m3Bpsb/TjCNAnGt3ZT6ZeLFP?= =?us-ascii?Q?eO47rRuVpEVhJVFmdaTwJJv9P8FjDXzNt0Vrwi4DfzT0eE6ArCtW+gpxdLdf?= =?us-ascii?Q?Lg8U9bRfLkrzZQkOTKb4WlPfep7eXe8kncFQzMaRolwqBGBfpBEj+8noOjnv?= =?us-ascii?Q?auXmJQfJsOMN22P9bSGdV7bbyzR42gAk4aDcgIRnskeFCs7tSQ+U0nK+zhbN?= =?us-ascii?Q?xXnogzG5M0m51Yf7RJWHzR52yQnWBV+u2bLpOMgsiB74xtzO4Sdb1jHLqYYU?= =?us-ascii?Q?+Y37NDF1Gd8pVXFDLsa4KJWOY17izwYPtSPI8ZdWrCp0auCeYxrTNXPO5U/T?= =?us-ascii?Q?vzi2NvW2/petPOnUmyQ2bIyVrUHm0lNLYi0lZN0uY0B7G86Tt/xKCXw=3D?= =?us-ascii?Q?=3D?= X-Microsoft-Exchange-Diagnostics: 1; BN3PR0301MB1252; 5:uyG1lbwAmzByXNw/XuMBH9z1E3hf9lj8eYlxHiv6mI7o6EGuF+ESw6/LHLMqaUV3u38gN7fJdqsgVD58aV/sy8J6I9nMF3Uw+QgyIVbJIDaPKhyVcaBihHc9EgUoIxMx4h0FUsGw2F/4gbGvMwlIrA==; 24:i3i3TiFKVAQMl6H4KW9jAo2QEZ320vFenBLDogH9ppEnT7POAI6aZSR4T0GL1pgExHJqkpXEHYHwJw/DPPdanV6mwRC6LGJ7kXAJo376xM4=; 20:GM4OBNNe/JXzjL/1q4EjLplbA/pyO7ryOD7Rk8Aop8UAK3kVCTHIUtEjhz4cNMqlrwdVIueqnAjL2MNJI75hfw== X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Oct 2015 06:59:54.1464 (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.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR0301MB1252 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151016_000018_373704_F7014666 X-CRM114-Status: GOOD ( 26.96 ) 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 kind of Freescale Layerscape SoC provides a MSI implementation which uses two SCFG registers MSIIR and MSIR to support 32 MSI interrupts for each PCIe controller. The patch is to support it. Signed-off-by: Minghuan Lian --- Change log v2: 1. rename ls1-msi to ls-scfg-msi 2. remove reg-names MSIIR MSIR 3. remove calling set_irq_flags() .../interrupt-controller/fsl,ls-scfg-msi.txt | 23 ++ arch/arm/mach-imx/Kconfig | 1 + drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-ls-scfg-msi.c | 244 +++++++++++++++++++++ 5 files changed, 274 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt create mode 100644 drivers/irqchip/irq-ls-scfg-msi.c diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt new file mode 100644 index 0000000..de39804 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -0,0 +1,23 @@ +* Freescale Layerscape SCFG PCIe MSI controller + +Required properties: + +- compatible: should be "fsl,-msi" to identify + Layerscape PCIe MSI controller block such as: + "fsl,1s1021a-msi" + "fsl,1s1043a-msi" +- msi-controller: indicates that this is a PCIe MSI controller node +- reg: physical base address of the controller and length of memory mapped. +- 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 0x8>, + msi-controller; + interrupts = <0 116 0x4>; + }; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 8ceda28..a8a5092 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 LS_SCFG_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..65a2d1c 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 LS_SCFG_MSI + bool + depends on PCI && PCI_MSI + select PCI_MSI_IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index bb3048f..88b36a3 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_LS_SCFG_MSI) += irq-ls-scfg-msi.o diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c new file mode 100644 index 0000000..b4940e4 --- /dev/null +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -0,0 +1,244 @@ +/* + * Layerscape SCFG 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 +#define MSIR 4 + +struct ls_scfg_msi { + spinlock_t lock; + struct platform_device *pdev; + struct irq_domain *parent; + struct irq_domain *msi_domain; + void __iomem *regs; + phys_addr_t msiir_addr; + u32 nr_irqs; + int irq; + DECLARE_BITMAP(used, MSI_MAX_IRQS); +}; + +static struct irq_chip ls_scfg_msi_irq_chip = { + .name = "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 struct msi_domain_info ls_scfg_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | + MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX), + .chip = &ls_scfg_msi_irq_chip, +}; + +static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct ls_scfg_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 ls_scfg_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) +{ + return -EINVAL; +} + +static struct irq_chip ls_scfg_msi_parent_chip = { + .name = "LS SCFG MSI", + .irq_compose_msi_msg = ls_scfg_msi_compose_msg, + .irq_set_affinity = ls_scfg_msi_set_affinity, +}; + +static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *args) +{ + struct ls_scfg_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, + &ls_scfg_msi_parent_chip, msi_data, + handle_simple_irq, NULL, NULL); + + return 0; +} + +static void ls_scfg_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 ls_scfg_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 ls_scfg_msi_domain_ops = { + .alloc = ls_scfg_msi_domain_irq_alloc, + .free = ls_scfg_msi_domain_irq_free, +}; + +static void ls_scfg_msi_irq_handler(struct irq_desc *desc) +{ + struct ls_scfg_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->regs + 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 ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) +{ + /* Initialize MSI domain parent */ + msi_data->parent = irq_domain_add_linear(NULL, + msi_data->nr_irqs, + &ls_scfg_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, + &ls_scfg_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 ls_scfg_msi_probe(struct platform_device *pdev) +{ + struct ls_scfg_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(pdev, IORESOURCE_MEM, 0); + msi_data->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(msi_data->regs)) { + dev_err(&pdev->dev, "failed to initialize 'regs'\n"); + return PTR_ERR(msi_data->regs); + } + msi_data->msiir_addr = res->start; + + 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 = ls_scfg_msi_domains_init(msi_data); + if (ret) + return ret; + + irq_set_chained_handler_and_data(msi_data->irq, + ls_scfg_msi_irq_handler, + msi_data); + + platform_set_drvdata(pdev, msi_data); + + return 0; +} + +static int ls_scfg_msi_remove(struct platform_device *pdev) +{ + struct ls_scfg_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 ls_scfg_msi_id[] = { + { .compatible = "fsl,1s1021a-msi", }, + { .compatible = "fsl,1s1043a-msi", }, + {}, +}; + +static struct platform_driver ls_scfg_msi_driver = { + .driver = { + .name = "ls-scfg-msi", + .of_match_table = ls_scfg_msi_id, + }, + .probe = ls_scfg_msi_probe, + .remove = ls_scfg_msi_remove, +}; + +module_platform_driver(ls_scfg_msi_driver); + +MODULE_AUTHOR("Minghuan Lian "); +MODULE_DESCRIPTION("Freescale Layerscape SCFG MSI controller driver"); +MODULE_LICENSE("GPL v2");