From patchwork Thu Dec 13 16:49:28 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Rutland X-Patchwork-Id: 1875721 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id F2CCBDF23A for ; Thu, 13 Dec 2012 17:22:27 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TjCRV-0003PU-1b; Thu, 13 Dec 2012 17:19:29 +0000 Received: from service87.mimecast.com ([91.220.42.44]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TjC06-0000tu-0M for linux-arm-kernel@lists.infradead.org; Thu, 13 Dec 2012 16:51:10 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Thu, 13 Dec 2012 16:51:08 +0000 Received: from localhost.localdomain ([10.1.255.212]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.0); Thu, 13 Dec 2012 16:51:07 +0000 From: Mark Rutland To: linux-arm-kernel@lists.infradead.org Subject: [RFCv2 2/2] ARM: add functions to parse irq affinity from dt Date: Thu, 13 Dec 2012 16:49:28 +0000 Message-Id: <1355417368-6861-3-git-send-email-mark.rutland@arm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1355417368-6861-1-git-send-email-mark.rutland@arm.com> References: <1355417368-6861-1-git-send-email-mark.rutland@arm.com> X-OriginalArrivalTime: 13 Dec 2012 16:51:07.0837 (UTC) FILETIME=[0C2C06D0:01CDD952] X-MC-Unique: 112121316510800701 X-Bad-Reply: References and In-Reply-To but no 'Re:' in Subject. X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121213_115110_354547_6B0694A4 X-CRM114-Status: GOOD ( 16.49 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [91.220.42.44 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Mailman-Approved-At: Thu, 13 Dec 2012 12:18:34 -0500 Cc: Mark Rutland , Lorenzo.Pieralisi@arm.com, benh@kernel.crashing.org, devicetree-discuss@lists.ozlabs.org, Will.Deacon@arm.com, rob.herring@calxeda.com, grant.likely@secretlab.ca, tglx@linutronix.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch adds functions to handle parsing the CPU affinity of interrupts from devicetree, based on an "interrupts-affinity" parameter list. It is assumed that drivers which may optionally use this parameter implement their own fallback behaviour. The patch adds: * arm_dt_has_irq_affinity : returns whether or not a device_node has interrupts-affinity information * arm_dt_affine_irq_is_single : returns whether an interrupt targets a single CPU (i.e. is an SPI) or multiple CPUs (i.e. is a PPI). This test is independent of the number of affine CPUs we can logically map. * arm_dt_irq_get_affinity : fills a cpumask with the CPUs an interrupt is affine to. The "interrupts-affinity" property consists of a list of pairs of cells specifying how to test if a CPU is affine. This test specification consists of a most significant affinity level to match, and values for the MPIDR affinity bits down to this level. Each pair of cells has the form: < N 0x00AABBCC > \ \ \ \ \__ MPIDR.Aff0 \ \ \ \___ MPIDR.Aff1 \ \ \____ MPIDR.Aff2 \ \_____ [must be zero] \________ level-specifier The level-specifier is in the range [0-3]. When the value is 3, MPIDR affinity levels 2,1,0 are ignored, and all CPUs are matched. Affinity bits which are not to be matched should be set to zero. Signed-off-by: Mark Rutland --- arch/arm/include/asm/dt_irq.h | 9 ++++ arch/arm/kernel/devtree.c | 91 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/dt_irq.h diff --git a/arch/arm/include/asm/dt_irq.h b/arch/arm/include/asm/dt_irq.h new file mode 100644 index 0000000..431eeda --- /dev/null +++ b/arch/arm/include/asm/dt_irq.h @@ -0,0 +1,9 @@ +#ifndef ARM_ASM_DT_IRQ_H +#define ARM_ASM_DT_IRQ_H + +bool arm_dt_has_irq_affinity(struct device_node *node); +bool arm_dt_affine_irq_is_single(struct device_node *node, int idx); +int arm_dt_irq_get_affinity(struct device_node *node, int idx, + cpumask_t *mask); + +#endif /* ARM_ASM_DT_IRQ_H */ diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 70f1bde..65d5052 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -165,6 +166,96 @@ void __init arm_dt_init_cpu_maps(void) } } +#define PROP_IRQ_AFFINITY "interrupts-affinity" +#define AFFINE_LEVEL_IDX(i) (2*(i)) +#define AFFINE_MPIDR_IDX(i) (2*(i) + 1) + +/* + * Check whether the device has irq affinity information. + * Allows drivers to fall back to current behaviour with a single check. + */ +bool arm_dt_has_irq_affinity(struct device_node *node) +{ + return of_find_property(node, PROP_IRQ_AFFINITY, NULL) != NULL; +} + +/* + * Check whether an irq with affinity information is a single cpu + * interrupt (rather than percpu). The node paramenter should be + * checked with arm_dt_has_irq_affinity first. + */ +bool arm_dt_affine_irq_is_single(struct device_node *node, int idx) +{ + u32 level; + of_property_read_u32_index(node, PROP_IRQ_AFFINITY, &level, + AFFINE_LEVEL_IDX(idx)); + return level == 0; +} + +struct affine_match_spec { + u32 level; + u32 aff; +}; + +static bool arm_dt_affine_mpidr_match(u32 mpidr, struct affine_match_spec *match) +{ + u32 mask = 0xFFFFFFFF << (8*(match->level)); + return (mpidr & mask) == (match->aff & mask); +} + +static int arm_dt_irq_read_match(struct device_node *node, int idx, + struct affine_match_spec *match) +{ + int ret; + if (!node) + return -EINVAL; + + ret = of_property_read_u32_index(node, PROP_IRQ_AFFINITY, &match->aff, + AFFINE_MPIDR_IDX(idx)); + if (ret) + return ret; + + ret = of_property_read_u32_index(node, PROP_IRQ_AFFINITY, &match->level, + AFFINE_LEVEL_IDX(idx)); + if (ret) + return ret; + + /* + * To match all cpus regardless of Aff{2,1,0}, we match at the + * nonexistent Aff3. + */ + if (match->level > 3) + return -EINVAL; + + return ret; + +} + +/* + * Get the set of possible cpus that an interrupt at idx is affine to. + */ +int arm_dt_irq_get_affinity(struct device_node *node, int idx, + cpumask_t *mask) +{ + int i, ret; + struct affine_match_spec match; + u32 mpidr; + + ret = arm_dt_irq_read_match(node, idx, &match); + if (ret) + return ret; + + cpumask_clear(mask); + + for_each_possible_cpu(i) { + mpidr = cpu_logical_map(i); + if (arm_dt_affine_mpidr_match(mpidr, &match)) + cpumask_set_cpu(i, mask); + } + + return 0; +} + /** * setup_machine_fdt - Machine setup when an dtb was passed to the kernel * @dt_phys: physical address of dt blob