Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756488AbbLHNXz (ORCPT ); Tue, 8 Dec 2015 08:23:55 -0500 Received: from mailapp01.imgtec.com ([195.59.15.196]:14649 "EHLO mailapp01.imgtec.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756525AbbLHNVf (ORCPT ); Tue, 8 Dec 2015 08:21:35 -0500 From: Qais Yousef To: CC: , , , , , , , Qais Yousef Subject: [PATCH v4 11/19] genirq: Implement ipi_send_{mask, single}() Date: Tue, 8 Dec 2015 13:20:22 +0000 Message-ID: <1449580830-23652-12-git-send-email-qais.yousef@imgtec.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1449580830-23652-1-git-send-email-qais.yousef@imgtec.com> References: <1449580830-23652-1-git-send-email-qais.yousef@imgtec.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [192.168.154.94] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6424 Lines: 213 Add APIs to send IPIs from driver and arch code. There is 2 version, the exported one which takes virq to be used by the drivers. And the non exported version which takes irq_desc to be used by arch code. The difference is in the error checking done. We do less checking with arch code to reduce SMP IPIs overhead. Signed-off-by: Qais Yousef --- include/linux/irq.h | 5 ++ kernel/irq/ipi.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/include/linux/irq.h b/include/linux/irq.h index b0556c5787d7..f521f1ac36d4 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -988,4 +988,9 @@ irq_hw_number_t irq_ipi_mapping_get_hwirq(struct ipi_mapping *map, irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu); +int __ipi_send_single(struct irq_desc *desc, unsigned int cpu); +int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest); +int ipi_send_single(unsigned int virq, unsigned int cpu); +int ipi_send_mask(unsigned int virq, const struct cpumask *dest); + #endif /* _LINUX_IRQ_H */ diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index a389d7e6d593..7829bf89d759 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -270,3 +270,172 @@ irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu) return hwirq; } EXPORT_SYMBOL_GPL(ipi_get_hwirq); + +/** + * __ipi_send_single - send an IPI to a target Linux SMP CPU + * @desc: pointer to irq_desc of the IRQ + * @cpu: dest CPU, must be the same or a subset of the mask passed to + * irq_reserve_ipi() + * + * Sends an IPI to a single smp cpu + * This function is meant to be used from arch code to send single SMP IPI. + * + * Returns zero on success and negative error number on failure. + */ +int __ipi_send_single(struct irq_desc *desc, unsigned int cpu) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct irq_chip *chip = irq_data_get_irq_chip(data); + const struct cpumask *dest = cpumask_of(cpu); + +#ifdef DEBUG + /* + * Minimise the overhead by omitting the checks for Linux SMP IPIs. + * Since the callers should be ARCH code which is generally trusted, + * only check for errors when debugging. + */ + struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL; + + if (!chip || !ipimask) + return -EINVAL; + + if (!chip->ipi_send_single && !chip->ipi_send_mask) + return -EINVAL; + + if (cpu > nr_cpu_ids) + return -EINVAL; + + if (!cpumask_test_cpu(cpu, ipimask)) + return -EINVAL; +#endif + + + if (chip->ipi_send_single) { + /* use the correct data for that cpu */ + data = irq_get_irq_data(data->irq + cpu - data->common->ipi_offset); + chip->ipi_send_single(data, cpu); + } else { + chip->ipi_send_mask(data, dest); + } + return 0; +} + +/** + * ipi_send_mask - send an IPI to target Linux SMP CPU(s) + * @desc: pointer to irq_desc of the IRQ + * @dest: dest CPU(s), must be the same or a subset of the mask passed to + * irq_reserve_ipi() + * + * Sends an IPI to all smp cpus in dest mask. + * This function is meant to be used from arch code to send SMP IPIs. + * + * Returns zero on success and negative error number on failure. + */ +int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct irq_chip *chip = irq_data_get_irq_chip(data); + unsigned int cpu; + +#ifdef DEBUG + /* + * Minimise the overhead by omitting the checks for Linux SMP IPIs. + * Since the callers should be ARCH code which is generally trusted, + * only check for errors when debugging. + */ + struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL; + + if (!chip || !ipimask) + return -EINVAL; + + if (!chip->ipi_send_single && !chip->ipi_send_mask) + return -EINVAL; + + if (!cpumask_subset(dest, ipimask)) + return -EINVAL; +#endif + + if (chip->ipi_send_mask) { + chip->ipi_send_mask(data, dest); + return 0; + } + + if (irq_domain_is_ipi_per_cpu(data->domain)) { + unsigned int base_virq = data->irq; + for_each_cpu(cpu, dest) { + data = irq_get_irq_data(base_virq + cpu - data->common->ipi_offset); + chip->ipi_send_single(data, cpu); + } + } else { + for_each_cpu(cpu, dest) + chip->ipi_send_single(data, cpu); + } + + return 0; +} + +/** + * ipi_send_single - send an IPI to a single CPU + * @virq: linux irq number from irq_reserve_ipi() + * @cpu: CPU ID. Must be a subset of the mask passed to irq_reserve_ipi() + * + * Sends an IPI to destination CPU + * + * Returns zero on success and negative error number on failure. + */ +int ipi_send_single(unsigned int virq, unsigned int cpu) +{ + struct irq_desc *desc = irq_to_desc(virq); + struct irq_data *data = desc ? irq_desc_get_irq_data(desc) : NULL; + struct irq_chip *chip = data ? irq_data_get_irq_chip(data) : NULL; + struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL; + + if (!chip || !ipimask) + return -EINVAL; + + if (!chip->ipi_send_single && !chip->ipi_send_mask) + return -EINVAL; + + if (cpu > nr_cpu_ids) + return -EINVAL; + + if (!cpumask_test_cpu(cpu, ipimask)) + return -EINVAL; + + __ipi_send_single(desc, cpu); + + return 0; +} +EXPORT_SYMBOL_GPL(ipi_send_single); + +/** + * ipi_send_mask - send an IPI to target CPU(s) + * @virq: linux irq number from irq_reserve_ipi() + * @dest: dest CPU(s), must be the same or a subset of the mask passed to + * irq_reserve_ipi() + * + * Sends an IPI to all prcessors in dest mask. + * + * Returns zero on success and negative error number on failure. + */ +int ipi_send_mask(unsigned int virq, const struct cpumask *dest) +{ + struct irq_desc *desc = irq_to_desc(virq); + struct irq_data *data = desc ? irq_desc_get_irq_data(desc) : NULL; + struct irq_chip *chip = data ? irq_data_get_irq_chip(data) : NULL; + struct cpumask *ipimask = data ? irq_data_get_affinity_mask(data) : NULL; + + if (!chip || !ipimask) + return -EINVAL; + + if (!chip->ipi_send_single && !chip->ipi_send_mask) + return -EINVAL; + + if (!cpumask_subset(dest, ipimask)) + return -EINVAL; + + __ipi_send_mask(desc, dest); + + return 0; +} +EXPORT_SYMBOL_GPL(ipi_send_mask); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/