Re: [PATCH v2 06/14] irqchip: add initial support for ompic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Sun, Sep 10 2017 at  3:49:18 pm BST, Stafford Horne <shorne@xxxxxxxxx> wrote:
> From: Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx>
>
> IPI driver for the Open Multi-Processor Interrupt Controller (ompic) as
> described in the Multicore support section of the OpenRISC 1.2
> proposed architecture specification:
>
>   https://github.com/stffrdhrn/doc/raw/arch-1.2-proposal/openrisc-arch-1.2-rev0.pdf
>
> Each OpenRISC core contains a full interrupt controller which is used in
> the SMP architecture for interrupt balancing.  This IPI device, the
> ompic, is the only external device required for enabling SMP on
> OpenRISC.
>
> Pending ops are stored in a memory bit mask which can allow multiple
> pending operations to be set and serviced at a time. This is mostly
> borrowed from the alpha IPI implementation.
>
> Signed-off-by: Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx>
> [shorne@xxxxxxxxx: converted ops to bitmask, wrote commit message]
> Signed-off-by: Stafford Horne <shorne@xxxxxxxxx>
> ---
>
> Changes since v1
>  - Added openrisc, prefix
>  - Clarified 8 bytes per cpu
>  - Removed #interrupt-cells as this will not be an irq parent
>  - Changed ops to be percpu
>  - Added DTS and intialization failure validations
>
>  .../interrupt-controller/openrisc,ompic.txt        |  19 ++
>  arch/openrisc/Kconfig                              |   1 +
>  drivers/irqchip/Kconfig                            |   3 +
>  drivers/irqchip/Makefile                           |   1 +
>  drivers/irqchip/irq-ompic.c                        | 205 +++++++++++++++++++++
>  5 files changed, 229 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt
>  create mode 100644 drivers/irqchip/irq-ompic.c
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt b/Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt
> new file mode 100644
> index 000000000000..346e6042d62f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/openrisc,ompic.txt
> @@ -0,0 +1,19 @@
> +Open Multi-Processor Interrupt Controller
> +
> +Required properties:
> +
> +- compatible : This should be "openrisc,ompic"
> +- reg : Specifies base physical address and size of the register space. The
> +  size is based on the number of cores the controller has been configured
> +  to handle, this should be set to 8 bytes per cpu core.
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- interrupts : Specifies the interrupt line to which the ompic is wired.
> +
> +Example:
> +
> +ompic: ompic {
> +	compatible = "openrisc,ompic";
> +	reg = <0x98000000 16>;
> +	interrupt-controller;
> +	interrupts = <1>;
> +};
> diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
> index b49acda5e8f4..34eb4e90f56c 100644
> --- a/arch/openrisc/Kconfig
> +++ b/arch/openrisc/Kconfig
> @@ -30,6 +30,7 @@ config OPENRISC
>  	select NO_BOOTMEM
>  	select ARCH_USE_QUEUED_SPINLOCKS
>  	select ARCH_USE_QUEUED_RWLOCKS
> +	select OMPIC if SMP
>  
>  config CPU_BIG_ENDIAN
>  	def_bool y
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index f1fd5f44d1d4..0e4c96c90b86 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -145,6 +145,9 @@ config CLPS711X_IRQCHIP
>  	select SPARSE_IRQ
>  	default y
>  
> +config OMPIC
> +	bool
> +
>  config OR1K_PIC
>  	bool
>  	select IRQ_DOMAIN
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index e88d856cc09c..123047d7a20d 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_DW_APB_ICTL)		+= irq-dw-apb-ictl.o
>  obj-$(CONFIG_METAG)			+= irq-metag-ext.o
>  obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)	+= irq-metag.o
>  obj-$(CONFIG_CLPS711X_IRQCHIP)		+= irq-clps711x.o
> +obj-$(CONFIG_OMPIC)			+= irq-ompic.o
>  obj-$(CONFIG_OR1K_PIC)			+= irq-or1k-pic.o
>  obj-$(CONFIG_ORION_IRQCHIP)		+= irq-orion.o
>  obj-$(CONFIG_OMAP_IRQCHIP)		+= irq-omap-intc.o
> diff --git a/drivers/irqchip/irq-ompic.c b/drivers/irqchip/irq-ompic.c
> new file mode 100644
> index 000000000000..cd2616b6639b
> --- /dev/null
> +++ b/drivers/irqchip/irq-ompic.c
> @@ -0,0 +1,205 @@
> +/*
> + * Open Multi-Processor Interrupt Controller driver
> + *
> + * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx>
> + * Copyright (C) 2017 Stafford Horne <shorne@xxxxxxxxx>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2.  This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + * The ompic device handles IPI communication because cores in mulicore
> + * OpenRISC systems.

Should the above read "between cores"?

> + *
> + * Registers
> + *
> + * For each CPU the ompic has 2 registers. The control register for sending
> + * and acking IPIs and the status register for receiving IPIs. The register
> + * layouts are as follows:
> + *
> + *  Control register
> + *  +---------+---------+----------+---------+
> + *  | 31      | 30      | 29 .. 16 | 15 .. 0 |
> + *  ----------+---------+----------+----------
> + *  | IRQ ACK | IRQ GEN | DST CORE | DATA    |
> + *  +---------+---------+----------+---------+
> + *
> + *  Status register
> + *  +----------+-------------+----------+---------+
> + *  | 31       | 30          | 29 .. 16 | 15 .. 0 |
> + *  -----------+-------------+----------+---------+
> + *  | Reserved | IRQ Pending | SRC CORE | DATA    |
> + *  +----------+-------------+----------+---------+
> + *
> + * Architecture
> + *
> + * - The ompic generates a level interrupt to the CPU PIC when a message is
> + *   ready.  Messages are delivered via the memory bus.
> + * - The ompic does not have any interrupt input lines.
> + * - The ompic is wired to the same irq line on each core.
> + * - Devices are wired to the same irq line on each core.
> + *
> + *   +---------+                         +---------+
> + *   | CPU     |                         | CPU     |
> + *   |  Core 0 |<==\ (memory access) /==>|  Core 1 |
> + *   |  [ PIC ]|   |                 |   |  [ PIC ]|
> + *   +----^-^--+   |                 |   +----^-^--+
> + *        | |      v                 v        | |
> + *   <====|=|=================================|=|==> (memory bus)
> + *        | |      ^                  ^       | |
> + *  (ipi  | +------|---------+--------|-------|-+ (device irq)
> + *   irq  |        |         |        |       |
> + *  core0)| +------|---------|--------|-------+ (ipi irq core1)
> + *        | |      |         |        |
> + *   +----o-o-+    |    +--------+    |
> + *   | ompic  |<===/    | Device |<===/
> + *   |  IPI   |         +--------+
> + *   +--------+*
> + *
> + */
> +
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/interrupt.h>
> +#include <linux/smp.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +
> +#include <linux/irqchip.h>
> +
> +#define OMPIC_CPUBYTES		8
> +#define OMPIC_CTRL(cpu)		(0x0 + (cpu * OMPIC_CPUBYTES))
> +#define OMPIC_STAT(cpu)		(0x4 + (cpu * OMPIC_CPUBYTES))
> +
> +#define OMPIC_CTRL_IRQ_ACK	(1 << 31)
> +#define OMPIC_CTRL_IRQ_GEN	(1 << 30)
> +#define OMPIC_CTRL_DST(cpu)	(((cpu) & 0x3fff) << 16)
> +
> +#define OMPIC_STAT_IRQ_PENDING	(1 << 30)
> +
> +#define OMPIC_DATA(x)		((x) & 0xffff)
> +
> +DEFINE_PER_CPU(unsigned long, ops);
> +
> +static void __iomem *ompic_base;
> +
> +static inline u32 ompic_readreg(void __iomem *base, loff_t offset)
> +{
> +	return ioread32be(base + offset);
> +}
> +
> +static void ompic_writereg(void __iomem *base, loff_t offset, u32 data)
> +{
> +	iowrite32be(data, base + offset);
> +}
> +
> +void ompic_raise_softirq(const struct cpumask *mask, unsigned int ipi_msg)

Please make this static.

> +{
> +	unsigned int dst_cpu;
> +	unsigned int src_cpu = smp_processor_id();
> +
> +	for_each_cpu(dst_cpu, mask) {
> +		set_bit(ipi_msg, &per_cpu(ops, dst_cpu));
> +
> +		/*
> +		 * On OpenRISC the atomic set_bit() call implies a memory
> +		 * barrier.  Otherwise we would need: smp_wmb(); paired
> +		 * with the read in ompic_ipi_handler.
> +		 */

One last question on this, because the architecture document is terribly
unclear: If you have CPU0 doing an atomic operation A0, CPU1 seeing A0
and doeing another atomic A1 (the set_bit above) followed by an IPI to
CPU2, is CPU2 *guaranteed* to observe both A0 *and* A1? Because that's
required by the IPI semantics, and you wouldn't see that kind of issue
with only two CPUs.

> +
> +		ompic_writereg(ompic_base, OMPIC_CTRL(src_cpu),
> +			       OMPIC_CTRL_IRQ_GEN |
> +			       OMPIC_CTRL_DST(dst_cpu) |
> +			       OMPIC_DATA(1));
> +	}
> +}
> +
> +irqreturn_t ompic_ipi_handler(int irq, void *dev_id)

This should be static.

> +{
> +	unsigned int cpu = smp_processor_id();
> +	unsigned long *pending_ops = &per_cpu(ops, cpu);
> +	unsigned long ops;
> +
> +	ompic_writereg(ompic_base, OMPIC_CTRL(cpu), OMPIC_CTRL_IRQ_ACK);
> +	while ((ops = xchg(pending_ops, 0)) != 0) {
> +
> +		/*
> +		 * On OpenRISC the atomic xchg() call implies a memory
> +		 * barrier.  Otherwise we may need an smp_rmb(); paired
> +		 * with the write in ompic_raise_softirq.
> +		 */
> +
> +		do {
> +			unsigned long ipi_msg;
> +
> +			ipi_msg = __ffs(ops);
> +			ops &= ~(1UL << ipi_msg);
> +
> +			handle_IPI(ipi_msg);
> +		} while (ops);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static struct irqaction ompi_ipi_irqaction = {
> +	.handler =      ompic_ipi_handler,
> +	.flags =        IRQF_PERCPU,
> +	.name =         "ompic_ipi",
> +};
> +
> +int __init ompic_of_init(struct device_node *node, struct device_node *parent)

static again.

> +{
> +	struct resource res;
> +	int irq;
> +	int ret;
> +
> +	/* Validate the DT */
> +	if (ompic_base) {
> +		pr_err("ompic: duplicate ompic's are not supported");
> +		return -EEXIST;
> +	}
> +
> +	if (of_address_to_resource(node, 0, &res)) {
> +		pr_err("ompic: reg property requires an address and size");
> +		return -EINVAL;
> +	}
> +
> +	if (resource_size(&res) < (num_possible_cpus() * OMPIC_CPUBYTES)) {
> +		pr_err("ompic: reg size, currently %d must be at least %d",
> +			resource_size(&res),
> +			(num_possible_cpus() * OMPIC_CPUBYTES));
> +		return -EINVAL;
> +	}
> +
> +	/* Setup the device */
> +	ompic_base = ioremap(res.start, resource_size(&res));
> +	if (IS_ERR(ompic_base)) {
> +		pr_err("ompic: unable to map registers");
> +		return PTR_ERR(ompic_base);
> +	}
> +
> +	irq = irq_of_parse_and_map(node, 0);
> +	if (irq <= 0) {
> +		pr_err("ompic: unable to parse device irq");
> +		ret = -EINVAL;
> +		goto out_unmap;
> +	}
> +
> +	ret = setup_irq(irq, &ompi_ipi_irqaction);
> +	if (ret)
> +		goto out_irq_disp;
> +
> +	set_smp_cross_call(ompic_raise_softirq);
> +
> +	return 0;
> +
> +out_irq_disp:
> +	irq_dispose_mapping(irq);
> +out_unmap:
> +	iounmap(ompic_base);
> +	ompic_base = NULL;
> +	return ret;
> +}
> +IRQCHIP_DECLARE(ompic, "openrisc,ompic", ompic_of_init);

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux