From patchwork Fri Oct 26 14:48:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Rutland X-Patchwork-Id: 1652221 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 3787D3FD4E for ; Fri, 26 Oct 2012 14:52:38 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TRlEh-0003ec-GO; Fri, 26 Oct 2012 14:50:11 +0000 Received: from service87.mimecast.com ([91.220.42.44]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TRlEc-0003dI-SK for linux-arm-kernel@lists.infradead.org; Fri, 26 Oct 2012 14:50:07 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Fri, 26 Oct 2012 15:50:04 +0100 Received: from localhost.localdomain ([10.1.255.212]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.0); Fri, 26 Oct 2012 15:50:03 +0100 From: Mark Rutland To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 2/2] ARM: Add functions to parse dt irq affinity Date: Fri, 26 Oct 2012 15:48:45 +0100 Message-Id: <1351262925-10306-3-git-send-email-mark.rutland@arm.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1351262925-10306-1-git-send-email-mark.rutland@arm.com> References: <1351262925-10306-1-git-send-email-mark.rutland@arm.com> X-OriginalArrivalTime: 26 Oct 2012 14:50:03.0262 (UTC) FILETIME=[2E51D9E0:01CDB389] X-MC-Unique: 112102615500406101 X-Spam-Note: CRM114 invocation failed 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] 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 cpu affinity of interrupts from devicetree. Devices using these functions are dealt with as follows: * If the device was not initialised from devicetree, it is considered to be affine to all CPUs, and interrupts are assumed to be in order of physical CPU id (MPIDR.Aff0). * If the device was initialised from devicetree, but does not have an "affinity" value, the device is considered to be affine to all CPUs, and interupts are assumed to be in order of physical CPU id (MPIDR.Aff0). * If the device was initialised from devicetree, and has an "affinity" value, then the interrupt at index i in the interrupts list is affine to the cpu or cluster pointed to by the entry in the affinity list at index i. Interrupts affine to a cluster are PPIs, and interrupts affine to a single cpu are SPIs. Signed-off-by: Mark Rutland --- arch/arm/include/asm/dt_irq.h | 64 ++++++++++++++++ arch/arm/kernel/devtree.c | 164 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 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..ed86ca8 --- /dev/null +++ b/arch/arm/include/asm/dt_irq.h @@ -0,0 +1,64 @@ +/* + * arch/arm/include/asm/dt_irq.h + * + * Copyright (C) 2009 ARM Ltd. + * + * 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. + * + */ +#ifndef __ASMARM_DT_IRQ_H +#define __ASMARM_DT_IRQ_H + +#include +#include +#include + +#ifdef CONFIG_OF + +extern int count_cpus_in_cluster(struct device_node *cluster); +extern struct device_node *of_get_cluster_cpu(struct device_node *cluster, int idx); +extern int count_irq_affine_cpus(struct platform_device *pdev, int irq_idx); +extern int of_get_logical_cpu_id(struct device_node *cpu); +extern int get_irq_affine_cpu(struct platform_device *pdev, int irq_idx, int cpu_idx); +extern int get_device_cpu_affinity(struct platform_device *pdev, cpumask_t *mask); + +#else /* CONFIG_OF */ + +static int count_cpus_in_cluster(struct device_node *cluster) +{ + return -EINVAL; +} + +static struct device_node *of_get_cluster_cpu(struct device_node *cluster, int idx) +{ + return NULL; +} + +static int count_irq_affine_cpus(struct platform_device *pdev, int irq_idx) +{ + return 1; +} + +static int of_get_logical_cpu_id(struct device_node *cpu) +{ + return -EINVAL; +} + +static int get_irq_affine_cpu(struct platform_device *pdev, int irq_idx, int cpu_idx); +{ + if (cpu_idx != 0) + return -EINVAL; + + return get_logical_index(irq_idx); +} + +static int get_device_cpu_affinity(struct platform_device *pdev, cpumask_t *mask) +{ + cpumask_setall(mask); + return 0; +} + +#endif /* CONFIG_OF */ +#endif /* ASMARM_DT_IRQ_H */ diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index bee7f9d..4026827 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -132,3 +132,167 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) return mdesc_best; } + +int count_cpus_in_cluster(struct device_node *cluster) +{ + struct device_node *cpus, *cpu, *cpu_cluster; + int count = 0; + + cpus = of_find_node_by_path("/cpus"); + if (!cpus) + return -EINVAL; + + for_each_child_of_node(cpus, cpu) { + cpu_cluster = of_parse_phandle(cpu, "cluster", 0); + if (cpu_cluster == cluster) + count++; + of_node_put(cpu_cluster); + } + + of_node_put(cpus); + return count; +} + +struct device_node *of_get_cluster_cpu(struct device_node *cluster, int idx) +{ + struct device_node *cpus, *cpu, *cpu_cluster; + + cpus = of_find_node_by_path("/cpus"); + if (!cpus) + return NULL; + + for_each_child_of_node(cpus, cpu) { + cpu_cluster = of_parse_phandle(cpu, "cluster", 0); + if (cpu_cluster == cluster && idx == 0) { + of_node_put(cpu_cluster); + break; + } + + idx--; + of_node_put(cpu_cluster); + } + + of_node_put(cpus); + return cpu; +} + +int count_irq_affine_cpus(struct platform_device *pdev, int irq_idx) +{ + struct device_node *node, *affine; + int ret = -EINVAL; + + if (!pdev) + return -EINVAL; + + node = pdev->dev.of_node; + + /* + * For devices not initialised from devicetree, we only support sets of + * SPIs. + */ + if (!node) + return 1; + + affine = of_parse_phandle(node, "affinity", irq_idx); + + /* + * A device initialised from devicetree without an affinity parameter + * is assumed to have a set of cpu-affine SPIs (so 1 cpu per irq). + */ + if (!affine) + return 1; + + if (!of_node_cmp(affine->name, "cpu")) + ret = 1; + else if (!of_node_cmp(affine->name, "cluster")) + ret = count_cpus_in_cluster(affine); + + of_node_put(affine); + return ret; +} + +int of_get_logical_cpu_id(struct device_node *cpu) +{ + u32 mpidr; + if (of_property_read_u32(cpu, "reg", &mpidr)) + return -EINVAL; + + return get_logical_index(mpidr); +} + +int get_irq_affine_cpu(struct platform_device *pdev, int irq_idx, int cpu_idx) +{ + struct device_node *node, *affine, *cpu; + int ret = -EINVAL; + + if (!pdev) + return -EINVAL; + + node = pdev->dev.of_node; + + /* + * Without devicetree, we only support single cluster systems. + * We assume 1 SPI per CPU. + * CPUs are assumed to be in increasing order of MPIDR.Aff{0}, + * starting at 0. MPIDR.Aff{2,1} are assumed to be 0. + */ + if (!node) { + if (cpu_idx != 0) + return -EINVAL; + return get_logical_index(irq_idx); + } + + affine = of_parse_phandle(node, "affinity", irq_idx); + if (!affine) { + if (cpu_idx != 0) + return -EINVAL; + return get_logical_index(irq_idx); + } + + if (!of_node_cmp(affine->name, "cluster")) { + cpu = of_get_cluster_cpu(affine, cpu_idx); + if (cpu) { + ret = of_get_logical_cpu_id(cpu); + of_node_put(cpu); + } + } + else if (!of_node_cmp(affine->name, "cpu")) { + ret = of_get_logical_cpu_id(affine); + } + + of_node_put(affine); + return ret; +} + +int get_device_cpu_affinity(struct platform_device *pdev, cpumask_t *mask) +{ + struct device_node *node; + int affines, a, cpus, c, cpu; + + node = pdev->dev.of_node; + + if (!node) { + cpumask_setall(mask); + return 0; + } + + affines = of_property_count_phandles(node, "affinity"); + if (affines == -ENOENT) { + cpumask_setall(mask); + return 0; + } + + if (affines < 0) + return -EINVAL; + + for (a = 0; a < affines; a++) { + cpus = count_irq_affine_cpus(pdev, a); + for (c = 0; c < cpus; c++) { + cpu = get_irq_affine_cpu(pdev, a, c); + if (cpu >= 0) + cpumask_set_cpu(cpu, mask); + } + } + + return 0; +}