Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d6a21b0 authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: intc: initial irqdomain support.



Trivial support for irq domains, using either a linear map or radix tree
depending on the vector layout.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 2d534926
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
config SH_INTC
	def_bool y
	select IRQ_DOMAIN

comment "Interrupt controller options"

config INTC_USERIMASK
+1 −1
Original line number Diff line number Diff line
obj-y 	:= access.o chip.o core.o handle.o virq.o
obj-y 	:= access.o chip.o core.o handle.o irqdomain.o virq.o

obj-$(CONFIG_INTC_BALANCING)		+= balancing.o
obj-$(CONFIG_INTC_USERIMASK)		+= userimask.o
+7 −4
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/stat.h>
#include <linux/interrupt.h>
#include <linux/sh_intc.h>
#include <linux/irqdomain.h>
#include <linux/device.h>
#include <linux/syscore_ops.h>
#include <linux/list.h>
@@ -310,6 +311,8 @@ int __init register_intc_controller(struct intc_desc *desc)

	BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */

	intc_irq_domain_init(d, hw);

	/* register the vectors one by one */
	for (i = 0; i < hw->nr_vectors; i++) {
		struct intc_vect *vect = hw->vectors + i;
@@ -319,8 +322,8 @@ int __init register_intc_controller(struct intc_desc *desc)
		if (!vect->enum_id)
			continue;

		res = irq_alloc_desc_at(irq, numa_node_id());
		if (res != irq && res != -EEXIST) {
		res = irq_create_identity_mapping(d->domain, irq);
		if (unlikely(res)) {
			pr_err("can't get irq_desc for %d\n", irq);
			continue;
		}
@@ -340,8 +343,8 @@ int __init register_intc_controller(struct intc_desc *desc)
			 * IRQ support, each vector still needs to have
			 * its own backing irq_desc.
			 */
			res = irq_alloc_desc_at(irq2, numa_node_id());
			if (res != irq2 && res != -EEXIST) {
			res = irq_create_identity_mapping(d->domain, irq2);
			if (unlikely(res)) {
				pr_err("can't get irq_desc for %d\n", irq2);
				continue;
			}
+5 −0
Original line number Diff line number Diff line
#include <linux/sh_intc.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -66,6 +67,7 @@ struct intc_desc_int {
	unsigned int nr_sense;
	struct intc_window *window;
	unsigned int nr_windows;
	struct irq_domain *domain;
	struct irq_chip chip;
	bool skip_suspend;
};
@@ -187,6 +189,9 @@ unsigned long intc_get_ack_handle(unsigned int irq);
void intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
			      intc_enum enum_id, int enable);

/* irqdomain.c */
void intc_irq_domain_init(struct intc_desc_int *d, struct intc_hw_desc *hw);

/* virq.c */
void intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
+68 −0
Original line number Diff line number Diff line
/*
 * IRQ domain support for SH INTC subsystem
 *
 * Copyright (C) 2012  Paul Mundt
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#define pr_fmt(fmt) "intc: " fmt

#include <linux/irqdomain.h>
#include <linux/sh_intc.h>
#include <linux/export.h>
#include "internals.h"

/**
 * intc_irq_domain_evt_xlate() - Generic xlate for vectored IRQs.
 *
 * This takes care of exception vector to hwirq translation through
 * by way of evt2irq() translation.
 *
 * Note: For platforms that use a flat vector space without INTEVT this
 * basically just mimics irq_domain_xlate_onecell() by way of a nopped
 * out evt2irq() implementation.
 */
static int intc_evt_xlate(struct irq_domain *d, struct device_node *ctrlr,
			  const u32 *intspec, unsigned int intsize,
			  unsigned long *out_hwirq, unsigned int *out_type)
{
	if (WARN_ON(intsize < 1))
		return -EINVAL;

	*out_hwirq = evt2irq(intspec[0]);
	*out_type = IRQ_TYPE_NONE;

	return 0;
}

static const struct irq_domain_ops intc_evt_ops = {
	.xlate		= intc_evt_xlate,
};

void __init intc_irq_domain_init(struct intc_desc_int *d,
				 struct intc_hw_desc *hw)
{
	unsigned int irq_base, irq_end;

	/*
	 * Quick linear revmap check
	 */
	irq_base = evt2irq(hw->vectors[0].vect);
	irq_end = evt2irq(hw->vectors[hw->nr_vectors - 1].vect);

	/*
	 * Linear domains have a hard-wired assertion that IRQs start at
	 * 0 in order to make some performance optimizations. Lamely
	 * restrict the linear case to these conditions here, taking the
	 * tree penalty for linear cases with non-zero hwirq bases.
	 */
	if (irq_base == 0 && irq_end == (irq_base + hw->nr_vectors - 1))
		d->domain = irq_domain_add_linear(NULL, hw->nr_vectors,
						  &intc_evt_ops, NULL);
	else
		d->domain = irq_domain_add_tree(NULL, &intc_evt_ops, NULL);

	BUG_ON(!d->domain);
}