summaryrefslogtreecommitdiff
path: root/include/linux/irqdomain.h
blob: 35b9ff382e45c8c96205e3d14772611c963feab7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * irq_domain - IRQ translation domains
 *
 * Translation infrastructure between hw and linux irq numbers.  This is
 * helpful for interrupt controllers to implement mapping between hardware
 * irq numbers and the Linux irq number space.
 *
 * irq_domains also have a hook for translating device tree interrupt
 * representation into a hardware irq number that can be mapped back to a
 * Linux irq number without any extra platform support code.
 *
 * Interrupt controller "domain" data structure. This could be defined as a
 * irq domain controller. That is, it handles the mapping between hardware
 * and virtual interrupt numbers for a given interrupt domain. The domain
 * structure is generally created by the PIC code for a given PIC instance
 * (though a domain can cover more than one PIC if they have a flat number
 * model). It's the domain callbacks that are responsible for setting the
 * irq_chip on a given irq_desc after it's been mapped.
 */

#ifndef _LINUX_IRQDOMAIN_H
#define _LINUX_IRQDOMAIN_H

#include <linux/types.h>
#include <linux/radix-tree.h>

struct device_node;
struct irq_domain;
struct of_device_id;

/* This type is the placeholder for a hardware interrupt number. It has to
 * be big enough to enclose whatever representation is used by a given
 * platform.
 */
typedef unsigned long irq_hw_number_t;

/**
 * struct irq_domain_ops - Methods for irq_domain objects
 * @match: Match an interrupt controller device node to a host, returns
 *         1 on a match
 * @map: Create or update a mapping between a virtual irq number and a hw
 *       irq number. This is called only once for a given mapping.
 * @unmap: Dispose of such a mapping
 * @to_irq: (optional) given a local hardware irq number, return the linux
 *          irq number.  If to_irq is not implemented, then the irq_domain
 *          will use this translation: irq = (domain->irq_base + hwirq)
 * @xlate: Given a device tree node and interrupt specifier, decode
 *         the hardware irq number and linux irq type value.
 *
 * Functions below are provided by the driver and called whenever a new mapping
 * is created or an old mapping is disposed. The driver can then proceed to
 * whatever internal data structures management is required. It also needs
 * to setup the irq_desc when returning from map().
 */
struct irq_domain_ops {
	int (*match)(struct irq_domain *d, struct device_node *node);
	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
	void (*unmap)(struct irq_domain *d, unsigned int virq);
	unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
	int (*xlate)(struct irq_domain *d, struct device_node *node,
		     const u32 *intspec, unsigned int intsize,
		     unsigned long *out_hwirq, unsigned int *out_type);
};

/**
 * struct irq_domain - Hardware interrupt number translation object
 * @link: Element in global irq_domain list.
 * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This
 *               will be one of the IRQ_DOMAIN_MAP_* values.
 * @revmap_data: Revmap method specific data.
 * @ops: pointer to irq_domain methods
 * @host_data: private data pointer for use by owner.  Not touched by irq_domain
 *             core code.
 * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
 *            of the irq_domain is responsible for allocating the array of
 *            irq_desc structures.
 * @nr_irq: Number of irqs managed by the irq domain
 * @hwirq_base: Starting number for hwirqs managed by the irq domain
 * @of_node: (optional) Pointer to device tree nodes associated with the
 *           irq_domain.  Used when decoding device tree interrupt specifiers.
 */
struct irq_domain {
	struct list_head link;

	/* type of reverse mapping_technique */
	unsigned int revmap_type;
#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
	union {
		struct {
			unsigned int size;
			unsigned int *revmap;
		} linear;
		struct radix_tree_root tree;
	} revmap_data;
	struct irq_domain_ops *ops;
	void *host_data;
	irq_hw_number_t inval_irq;

	unsigned int irq_base;
	unsigned int nr_irq;
	unsigned int hwirq_base;

	/* Optional device node pointer */
	struct device_node *of_node;
};

#ifdef CONFIG_IRQ_DOMAIN
/**
 * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
 *
 * Returns the linux irq number associated with a hardware irq.  By default,
 * the mapping is irq == domain->irq_base + hwirq, but this mapping can
 * be overridden if the irq_domain implements a .to_irq() hook.
 */
static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
					     unsigned long hwirq)
{
	if (d->ops->to_irq)
		return d->ops->to_irq(d, hwirq);
	if (WARN_ON(hwirq < d->hwirq_base))
		return 0;
	return d->irq_base + hwirq - d->hwirq_base;
}

#define irq_domain_for_each_hwirq(d, hw) \
	for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)

#define irq_domain_for_each_irq(d, hw, irq) \
	for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
	     hw < d->hwirq_base + d->nr_irq; \
	     hw++, irq = irq_domain_to_irq(d, hw))

extern void irq_domain_add(struct irq_domain *domain);
extern void irq_domain_del(struct irq_domain *domain);

extern struct irq_domain_ops irq_domain_simple_ops;
#endif /* CONFIG_IRQ_DOMAIN */

#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
extern void irq_domain_generate_simple(const struct of_device_id *match,
					u64 phys_base, unsigned int irq_start);
#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
static inline void irq_domain_generate_simple(const struct of_device_id *match,
					u64 phys_base, unsigned int irq_start) { }
#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */

#endif /* _LINUX_IRQDOMAIN_H */