Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
1f52299e
Commit
1f52299e
authored
Feb 27, 2012
by
Benoit Cousson
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'irqdomain/next' of
git://git.secretlab.ca/git/linux-2.6
into for_3.4/dt_irq_domain2
parents
ffd76d8b
280ad7fd
Changes
86
Hide whitespace changes
Inline
Side-by-side
Showing
86 changed files
with
1435 additions
and
2603 deletions
+1435
-2603
Documentation/IRQ-domain.txt
Documentation/IRQ-domain.txt
+117
-0
MAINTAINERS
MAINTAINERS
+9
-0
arch/arm/common/gic.c
arch/arm/common/gic.c
+42
-53
arch/arm/common/vic.c
arch/arm/common/vic.c
+5
-11
arch/arm/include/asm/hardware/gic.h
arch/arm/include/asm/hardware/gic.h
+2
-2
arch/arm/include/asm/hardware/vic.h
arch/arm/include/asm/hardware/vic.h
+2
-0
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/common.c
+1
-1
arch/arm/mach-imx/imx51-dt.c
arch/arm/mach-imx/imx51-dt.c
+2
-2
arch/arm/mach-imx/imx53-dt.c
arch/arm/mach-imx/imx53-dt.c
+2
-2
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-imx6q.c
+2
-1
arch/arm/mach-msm/board-msm8x60.c
arch/arm/mach-msm/board-msm8x60.c
+2
-6
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-generic.c
+1
-1
arch/arm/mach-prima2/irq.c
arch/arm/mach-prima2/irq.c
+1
-1
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/core.c
+5
-2
arch/c6x/Kconfig
arch/c6x/Kconfig
+1
-0
arch/c6x/include/asm/irq.h
arch/c6x/include/asm/irq.h
+1
-244
arch/c6x/kernel/irq.c
arch/c6x/kernel/irq.c
+14
-598
arch/c6x/platforms/megamod-pic.c
arch/c6x/platforms/megamod-pic.c
+6
-19
arch/microblaze/Kconfig
arch/microblaze/Kconfig
+1
-0
arch/microblaze/include/asm/hardirq.h
arch/microblaze/include/asm/hardirq.h
+0
-16
arch/microblaze/include/asm/irq.h
arch/microblaze/include/asm/irq.h
+3
-39
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/intc.c
+37
-24
arch/microblaze/kernel/irq.c
arch/microblaze/kernel/irq.c
+4
-20
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/setup.c
+0
-2
arch/mips/Kconfig
arch/mips/Kconfig
+1
-0
arch/mips/include/asm/irq.h
arch/mips/include/asm/irq.h
+1
-4
arch/mips/kernel/prom.c
arch/mips/kernel/prom.c
+0
-14
arch/openrisc/include/asm/prom.h
arch/openrisc/include/asm/prom.h
+1
-9
arch/powerpc/Kconfig
arch/powerpc/Kconfig
+1
-0
arch/powerpc/include/asm/ehv_pic.h
arch/powerpc/include/asm/ehv_pic.h
+1
-1
arch/powerpc/include/asm/i8259.h
arch/powerpc/include/asm/i8259.h
+1
-1
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/irq.h
+1
-246
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/mpic.h
+1
-1
arch/powerpc/include/asm/xics.h
arch/powerpc/include/asm/xics.h
+1
-1
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/irq.c
+3
-614
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+5
-7
arch/powerpc/platforms/52xx/media5200.c
arch/powerpc/platforms/52xx/media5200.c
+6
-9
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+7
-9
arch/powerpc/platforms/52xx/mpc52xx_pic.c
arch/powerpc/platforms/52xx/mpc52xx_pic.c
+6
-6
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
+5
-9
arch/powerpc/platforms/85xx/socrates_fpga_pic.c
arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+7
-8
arch/powerpc/platforms/86xx/gef_pic.c
arch/powerpc/platforms/86xx/gef_pic.c
+7
-8
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/axon_msi.c
+13
-16
arch/powerpc/platforms/cell/beat_interrupt.c
arch/powerpc/platforms/cell/beat_interrupt.c
+7
-9
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/cell/interrupt.c
+8
-8
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/cell/spider-pic.c
+6
-8
arch/powerpc/platforms/embedded6xx/flipper-pic.c
arch/powerpc/platforms/embedded6xx/flipper-pic.c
+11
-13
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+14
-15
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/irq.c
+5
-6
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powermac/pic.c
+7
-19
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powermac/smp.c
+4
-5
arch/powerpc/platforms/ps3/interrupt.c
arch/powerpc/platforms/ps3/interrupt.c
+5
-6
arch/powerpc/platforms/wsp/opb_pic.c
arch/powerpc/platforms/wsp/opb_pic.c
+6
-20
arch/powerpc/sysdev/cpm1.c
arch/powerpc/sysdev/cpm1.c
+4
-5
arch/powerpc/sysdev/cpm2_pic.c
arch/powerpc/sysdev/cpm2_pic.c
+5
-18
arch/powerpc/sysdev/ehv_pic.c
arch/powerpc/sysdev/ehv_pic.c
+6
-8
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_msi.c
+4
-6
arch/powerpc/sysdev/fsl_msi.h
arch/powerpc/sysdev/fsl_msi.h
+1
-1
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/i8259.c
+7
-8
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/ipic.c
+6
-25
arch/powerpc/sysdev/ipic.h
arch/powerpc/sysdev/ipic.h
+1
-1
arch/powerpc/sysdev/mpc8xx_pic.c
arch/powerpc/sysdev/mpc8xx_pic.c
+5
-6
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic.c
+7
-10
arch/powerpc/sysdev/mpic_msi.c
arch/powerpc/sysdev/mpic_msi.c
+1
-1
arch/powerpc/sysdev/mv64x60_pic.c
arch/powerpc/sysdev/mv64x60_pic.c
+5
-6
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
+6
-20
arch/powerpc/sysdev/qe_lib/qe_ic.h
arch/powerpc/sysdev/qe_lib/qe_ic.h
+1
-1
arch/powerpc/sysdev/tsi108_pci.c
arch/powerpc/sysdev/tsi108_pci.c
+6
-7
arch/powerpc/sysdev/uic.c
arch/powerpc/sysdev/uic.c
+6
-20
arch/powerpc/sysdev/xics/xics-common.c
arch/powerpc/sysdev/xics/xics-common.c
+12
-13
arch/powerpc/sysdev/xilinx_intc.c
arch/powerpc/sysdev/xilinx_intc.c
+9
-10
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/prom.h
+1
-9
arch/x86/Kconfig
arch/x86/Kconfig
+2
-0
arch/x86/include/asm/irq_controller.h
arch/x86/include/asm/irq_controller.h
+0
-12
arch/x86/include/asm/prom.h
arch/x86/include/asm/prom.h
+0
-10
arch/x86/kernel/devicetree.c
arch/x86/kernel/devicetree.c
+30
-71
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mpc8xxx.c
+6
-24
drivers/mfd/Kconfig
drivers/mfd/Kconfig
+1
-0
drivers/mfd/twl-core.c
drivers/mfd/twl-core.c
+5
-16
drivers/net/phy/mdio-gpio.c
drivers/net/phy/mdio-gpio.c
+2
-2
drivers/of/platform.c
drivers/of/platform.c
+2
-2
include/linux/irqdomain.h
include/linux/irqdomain.h
+137
-54
include/linux/of_address.h
include/linux/of_address.h
+29
-4
include/linux/of_irq.h
include/linux/of_irq.h
+1
-3
include/linux/of_platform.h
include/linux/of_platform.h
+10
-2
kernel/irq/irqdomain.c
kernel/irq/irqdomain.c
+716
-112
No files found.
Documentation/IRQ-domain.txt
0 → 100644
View file @
1f52299e
irq_domain interrupt number mapping library
The current design of the Linux kernel uses a single large number
space where each separate IRQ source is assigned a different number.
This is simple when there is only one interrupt controller, but in
systems with multiple interrupt controllers the kernel must ensure
that each one gets assigned non-overlapping allocations of Linux
IRQ numbers.
The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
irq numbers, but they don't provide any support for reverse mapping of
the controller-local IRQ (hwirq) number into the Linux IRQ number
space.
The irq_domain library adds mapping between hwirq and IRQ numbers on
top of the irq_alloc_desc*() API. An irq_domain to manage mapping is
preferred over interrupt controller drivers open coding their own
reverse mapping scheme.
irq_domain also implements translation from Device Tree interrupt
specifiers to hwirq numbers, and can be easily extended to support
other IRQ topology data sources.
=== irq_domain usage ===
An interrupt controller driver creates and registers an irq_domain by
calling one of the irq_domain_add_*() functions (each mapping method
has a different allocator function, more on that later). The function
will return a pointer to the irq_domain on success. The caller must
provide the allocator function with an irq_domain_ops structure with
the .map callback populated as a minimum.
In most cases, the irq_domain will begin empty without any mappings
between hwirq and IRQ numbers. Mappings are added to the irq_domain
by calling irq_create_mapping() which accepts the irq_domain and a
hwirq number as arguments. If a mapping for the hwirq doesn't already
exist then it will allocate a new Linux irq_desc, associate it with
the hwirq, and call the .map() callback so the driver can perform any
required hardware setup.
When an interrupt is received, irq_find_mapping() function should
be used to find the Linux IRQ number from the hwirq number.
If the driver has the Linux IRQ number or the irq_data pointer, and
needs to know the associated hwirq number (such as in the irq_chip
callbacks) then it can be directly obtained from irq_data->hwirq.
=== Types of irq_domain mappings ===
There are several mechanisms available for reverse mapping from hwirq
to Linux irq, and each mechanism uses a different allocation function.
Which reverse map type should be used depends on the use case. Each
of the reverse map types are described below:
==== Linear ====
irq_domain_add_linear()
The linear reverse map maintains a fixed size table indexed by the
hwirq number. When a hwirq is mapped, an irq_desc is allocated for
the hwirq, and the IRQ number is stored in the table.
The Linear map is a good choice when the maximum number of hwirqs is
fixed and a relatively small number (~ < 256). The advantages of this
map are fixed time lookup for IRQ numbers, and irq_descs are only
allocated for in-use IRQs. The disadvantage is that the table must be
as large as the largest possible hwirq number.
The majority of drivers should use the linear map.
==== Tree ====
irq_domain_add_tree()
The irq_domain maintains a radix tree map from hwirq numbers to Linux
IRQs. When an hwirq is mapped, an irq_desc is allocated and the
hwirq is used as the lookup key for the radix tree.
The tree map is a good choice if the hwirq number can be very large
since it doesn't need to allocate a table as large as the largest
hwirq number. The disadvantage is that hwirq to IRQ number lookup is
dependent on how many entries are in the table.
Very few drivers should need this mapping. At the moment, powerpc
iseries is the only user.
==== No Map ===-
irq_domain_add_nomap()
The No Map mapping is to be used when the hwirq number is
programmable in the hardware. In this case it is best to program the
Linux IRQ number into the hardware itself so that no mapping is
required. Calling irq_create_direct_mapping() will allocate a Linux
IRQ number and call the .map() callback so that driver can program the
Linux IRQ number into the hardware.
Most drivers cannot use this mapping.
==== Legacy ====
irq_domain_add_legacy()
irq_domain_add_legacy_isa()
The Legacy mapping is a special case for drivers that already have a
range of irq_descs allocated for the hwirqs. It is used when the
driver cannot be immediately converted to use the linear mapping. For
example, many embedded system board support files use a set of #defines
for IRQ numbers that are passed to struct device registrations. In that
case the Linux IRQ numbers cannot be dynamically assigned and the legacy
mapping should be used.
The legacy map assumes a contiguous range of IRQ numbers has already
been allocated for the controller and that the IRQ number can be
calculated by adding a fixed offset to the hwirq number, and
visa-versa. The disadvantage is that it requires the interrupt
controller to manage IRQ allocations and it requires an irq_desc to be
allocated for every hwirq, even if it is unused.
The legacy map should only be used if fixed IRQ mappings must be
supported. For example, ISA controllers would use the legacy map for
mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
numbers.
MAINTAINERS
View file @
1f52299e
...
...
@@ -3640,6 +3640,15 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
F: kernel/irq/
IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
M: Grant Likely <grant.likely@secretlab.ca>
T: git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
S: Maintained
F: Documentation/IRQ-domain.txt
F: include/linux/irqdomain.h
F: kernel/irq/irqdomain.c
ISAPNP
M: Jaroslav Kysela <perex@perex.cz>
S: Maintained
...
...
arch/arm/common/gic.c
View file @
1f52299e
...
...
@@ -51,7 +51,6 @@ union gic_base {
};
struct
gic_chip_data
{
unsigned
int
irq_offset
;
union
gic_base
dist_base
;
union
gic_base
cpu_base
;
#ifdef CONFIG_CPU_PM
...
...
@@ -61,9 +60,7 @@ struct gic_chip_data {
u32
__percpu
*
saved_ppi_enable
;
u32
__percpu
*
saved_ppi_conf
;
#endif
#ifdef CONFIG_IRQ_DOMAIN
struct
irq_domain
domain
;
#endif
struct
irq_domain
*
domain
;
unsigned
int
gic_irqs
;
#ifdef CONFIG_GIC_NON_BANKED
void
__iomem
*
(
*
get_base
)(
union
gic_base
*
);
...
...
@@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
irqnr
=
irqstat
&
~
0x1c00
;
if
(
likely
(
irqnr
>
15
&&
irqnr
<
1021
))
{
irqnr
=
irq_
domain_to_irq
(
&
gic
->
domain
,
irqnr
);
irqnr
=
irq_
find_mapping
(
gic
->
domain
,
irqnr
);
handle_IRQ
(
irqnr
,
regs
);
continue
;
}
...
...
@@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
if
(
gic_irq
==
1023
)
goto
out
;
cascade_irq
=
irq_
domain_to_irq
(
&
chip_data
->
domain
,
gic_irq
);
if
(
unlikely
(
gic_irq
<
32
||
gic_irq
>
1020
||
cascade_irq
>=
NR_IRQS
))
cascade_irq
=
irq_
find_mapping
(
chip_data
->
domain
,
gic_irq
);
if
(
unlikely
(
gic_irq
<
32
||
gic_irq
>
1020
))
do_bad_IRQ
(
cascade_irq
,
desc
);
else
generic_handle_irq
(
cascade_irq
);
...
...
@@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
static
void
__init
gic_dist_init
(
struct
gic_chip_data
*
gic
)
{
unsigned
int
i
,
irq
;
unsigned
int
i
;
u32
cpumask
;
unsigned
int
gic_irqs
=
gic
->
gic_irqs
;
struct
irq_domain
*
domain
=
&
gic
->
domain
;
void
__iomem
*
base
=
gic_data_dist_base
(
gic
);
u32
cpu
=
cpu_logical_map
(
smp_processor_id
());
...
...
@@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
32
)
writel_relaxed
(
0xffffffff
,
base
+
GIC_DIST_ENABLE_CLEAR
+
i
*
4
/
32
);
/*
* Setup the Linux IRQ subsystem.
*/
irq_domain_for_each_irq
(
domain
,
i
,
irq
)
{
if
(
i
<
32
)
{
irq_set_percpu_devid
(
irq
);
irq_set_chip_and_handler
(
irq
,
&
gic_chip
,
handle_percpu_devid_irq
);
set_irq_flags
(
irq
,
IRQF_VALID
|
IRQF_NOAUTOEN
);
}
else
{
irq_set_chip_and_handler
(
irq
,
&
gic_chip
,
handle_fasteoi_irq
);
set_irq_flags
(
irq
,
IRQF_VALID
|
IRQF_PROBE
);
}
irq_set_chip_data
(
irq
,
gic
);
}
writel_relaxed
(
1
,
base
+
GIC_DIST_CTRL
);
}
...
...
@@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
}
#endif
#ifdef CONFIG_OF
static
int
gic_irq_domain_dt_translate
(
struct
irq_domain
*
d
,
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
)
static
int
gic_irq_domain_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
irq_hw_number_t
hw
)
{
if
(
hw
<
32
)
{
irq_set_percpu_devid
(
irq
);
irq_set_chip_and_handler
(
irq
,
&
gic_chip
,
handle_percpu_devid_irq
);
set_irq_flags
(
irq
,
IRQF_VALID
|
IRQF_NOAUTOEN
);
}
else
{
irq_set_chip_and_handler
(
irq
,
&
gic_chip
,
handle_fasteoi_irq
);
set_irq_flags
(
irq
,
IRQF_VALID
|
IRQF_PROBE
);
}
irq_set_chip_data
(
irq
,
d
->
host_data
);
return
0
;
}
static
int
gic_irq_domain_xlate
(
struct
irq_domain
*
d
,
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
)
{
if
(
d
->
of_node
!=
controller
)
return
-
EINVAL
;
...
...
@@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d,
*
out_type
=
intspec
[
2
]
&
IRQ_TYPE_SENSE_MASK
;
return
0
;
}
#endif
const
struct
irq_domain_ops
gic_irq_domain_ops
=
{
#ifdef CONFIG_OF
.
dt_translate
=
gic_irq_domain_dt_translate
,
#endif
.
map
=
gic_irq_domain_map
,
.
xlate
=
gic_irq_domain_xlate
,
};
void
__init
gic_init_bases
(
unsigned
int
gic_nr
,
int
irq_start
,
void
__iomem
*
dist_base
,
void
__iomem
*
cpu_base
,
u32
percpu_offset
)
u32
percpu_offset
,
struct
device_node
*
node
)
{
irq_hw_number_t
hwirq_base
;
struct
gic_chip_data
*
gic
;
struct
irq_domain
*
domain
;
int
gic_irqs
;
int
gic_irqs
,
irq_base
;
BUG_ON
(
gic_nr
>=
MAX_GIC_NR
);
gic
=
&
gic_data
[
gic_nr
];
domain
=
&
gic
->
domain
;
#ifdef CONFIG_GIC_NON_BANKED
if
(
percpu_offset
)
{
/* Frankein-GIC without banked registers... */
unsigned
int
cpu
;
...
...
@@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
domain
->
hwirq_base
=
32
;
hwirq_base
=
32
;
if
(
gic_nr
==
0
)
{
if
((
irq_start
&
31
)
>
0
)
{
domain
->
hwirq_base
=
16
;
hwirq_base
=
16
;
if
(
irq_start
!=
-
1
)
irq_start
=
(
irq_start
&
~
31
)
+
16
;
}
...
...
@@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
gic_irqs
=
1020
;
gic
->
gic_irqs
=
gic_irqs
;
domain
->
nr_irq
=
gic_irqs
-
domain
->
hwirq_base
;
domain
->
irq_base
=
irq_alloc_descs
(
irq_start
,
16
,
domain
->
nr_irq
,
numa_node_id
());
if
(
IS_ERR_VALUE
(
domain
->
irq_base
))
{
gic_irqs
-=
hwirq_base
;
/* calculate # of irqs to allocate */
irq_base
=
irq_alloc_descs
(
irq_start
,
16
,
gic_irqs
,
numa_node_id
());
if
(
IS_ERR_VALUE
(
irq_base
))
{
WARN
(
1
,
"Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated
\n
"
,
irq_start
);
domain
->
irq_base
=
irq_start
;
irq_base
=
irq_start
;
}
domain
->
priv
=
gic
;
domain
->
ops
=
&
gic_irq_domain_ops
;
irq_domain_add
(
domain
);
gic
->
domain
=
irq_domain_add_legacy
(
node
,
gic_irqs
,
irq_base
,
hwirq_base
,
&
gic_irq_domain_ops
,
gic
);
if
(
WARN_ON
(
!
gic
->
domain
))
return
;
gic_chip
.
flags
|=
gic_arch_extn
.
flags
;
gic_dist_init
(
gic
);
...
...
@@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
void
__iomem
*
dist_base
;
u32
percpu_offset
;
int
irq
;
struct
irq_domain
*
domain
=
&
gic_data
[
gic_cnt
].
domain
;
if
(
WARN_ON
(
!
node
))
return
-
ENODEV
;
...
...
@@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
if
(
of_property_read_u32
(
node
,
"cpu-offset"
,
&
percpu_offset
))
percpu_offset
=
0
;
domain
->
of_node
=
of_node_get
(
node
);
gic_init_bases
(
gic_cnt
,
-
1
,
dist_base
,
cpu_base
,
percpu_offset
);
gic_init_bases
(
gic_cnt
,
-
1
,
dist_base
,
cpu_base
,
percpu_offset
,
node
);
if
(
parent
)
{
irq
=
irq_of_parse_and_map
(
node
,
0
);
...
...
arch/arm/common/vic.c
View file @
1f52299e
...
...
@@ -56,7 +56,7 @@ struct vic_device {
u32
int_enable
;
u32
soft_int
;
u32
protect
;
struct
irq_domain
domain
;
struct
irq_domain
*
domain
;
};
/* we cannot allocate memory when VICs are initially registered */
...
...
@@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
v
->
resume_sources
=
resume_sources
;
v
->
irq
=
irq
;
vic_id
++
;
v
->
domain
.
irq_base
=
irq
;
v
->
domain
.
nr_irq
=
32
;
#ifdef CONFIG_OF_IRQ
v
->
domain
.
of_node
=
of_node_get
(
node
);
#endif
/* CONFIG_OF */
v
->
domain
.
ops
=
&
irq_domain_simple_ops
;
irq_domain_add
(
&
v
->
domain
);
v
->
domain
=
irq_domain_add_legacy
(
node
,
32
,
irq
,
0
,
&
irq_domain_simple_ops
,
v
);
}
static
void
vic_ack_irq
(
struct
irq_data
*
d
)
...
...
@@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
vic_register
(
base
,
irq_start
,
0
,
node
);
}
static
void
__init
__vic_init
(
void
__iomem
*
base
,
unsigned
int
irq_start
,
void
__init
__vic_init
(
void
__iomem
*
base
,
unsigned
int
irq_start
,
u32
vic_sources
,
u32
resume_sources
,
struct
device_node
*
node
)
{
...
...
@@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
stat
=
readl_relaxed
(
vic
->
base
+
VIC_IRQ_STATUS
);
while
(
stat
)
{
irq
=
ffs
(
stat
)
-
1
;
handle_IRQ
(
irq_
domain_to_irq
(
&
vic
->
domain
,
irq
),
regs
);
handle_IRQ
(
irq_
find_mapping
(
vic
->
domain
,
irq
),
regs
);
stat
&=
~
(
1
<<
irq
);
handled
=
1
;
}
...
...
arch/arm/include/asm/hardware/gic.h
View file @
1f52299e
...
...
@@ -39,7 +39,7 @@ struct device_node;
extern
struct
irq_chip
gic_arch_extn
;
void
gic_init_bases
(
unsigned
int
,
int
,
void
__iomem
*
,
void
__iomem
*
,
u32
offset
);
u32
offset
,
struct
device_node
*
);
int
gic_of_init
(
struct
device_node
*
node
,
struct
device_node
*
parent
);
void
gic_secondary_init
(
unsigned
int
);
void
gic_handle_irq
(
struct
pt_regs
*
regs
);
...
...
@@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
static
inline
void
gic_init
(
unsigned
int
nr
,
int
start
,
void
__iomem
*
dist
,
void
__iomem
*
cpu
)
{
gic_init_bases
(
nr
,
start
,
dist
,
cpu
,
0
);
gic_init_bases
(
nr
,
start
,
dist
,
cpu
,
0
,
NULL
);
}
#endif
...
...
arch/arm/include/asm/hardware/vic.h
View file @
1f52299e
...
...
@@ -47,6 +47,8 @@
struct
device_node
;
struct
pt_regs
;
void
__vic_init
(
void
__iomem
*
base
,
unsigned
int
irq_start
,
u32
vic_sources
,
u32
resume_sources
,
struct
device_node
*
node
);
void
vic_init
(
void
__iomem
*
base
,
unsigned
int
irq_start
,
u32
vic_sources
,
u32
resume_sources
);
int
vic_of_init
(
struct
device_node
*
node
,
struct
device_node
*
parent
);
void
vic_handle_irq
(
struct
pt_regs
*
regs
);
...
...
arch/arm/mach-exynos/common.c
View file @
1f52299e
...
...
@@ -402,7 +402,7 @@ void __init exynos4_init_irq(void)
gic_bank_offset
=
soc_is_exynos4412
()
?
0x4000
:
0x8000
;
if
(
!
of_have_populated_dt
())
gic_init_bases
(
0
,
IRQ_PPI
(
0
),
S5P_VA_GIC_DIST
,
S5P_VA_GIC_CPU
,
gic_bank_offset
);
gic_init_bases
(
0
,
IRQ_PPI
(
0
),
S5P_VA_GIC_DIST
,
S5P_VA_GIC_CPU
,
gic_bank_offset
,
NULL
);
#ifdef CONFIG_OF
else
of_irq_init
(
exynos4_dt_irq_match
);
...
...
arch/arm/mach-imx/imx51-dt.c
View file @
1f52299e
...
...
@@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = {
static
int
__init
imx51_tzic_add_irq_domain
(
struct
device_node
*
np
,
struct
device_node
*
interrupt_parent
)
{
irq_domain_add_
simple
(
np
,
0
);
irq_domain_add_
legacy
(
np
,
128
,
0
,
0
,
&
irq_domain_simple_ops
,
NULL
);
return
0
;
}
...
...
@@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np,
static
int
gpio_irq_base
=
MXC_GPIO_IRQ_START
+
ARCH_NR_GPIOS
;
gpio_irq_base
-=
32
;
irq_domain_add_
simple
(
np
,
gpio_irq_base
);
irq_domain_add_
legacy
(
np
,
32
,
gpio_irq_base
,
0
,
&
irq_domain_simple_ops
,
NULL
);
return
0
;
}
...
...
arch/arm/mach-imx/imx53-dt.c
View file @
1f52299e
...
...
@@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = {
static
int
__init
imx53_tzic_add_irq_domain
(
struct
device_node
*
np
,
struct
device_node
*
interrupt_parent
)
{
irq_domain_add_
simple
(
np
,
0
);
irq_domain_add_
legacy
(
np
,
128
,
0
,
0
,
&
irq_domain_simple_ops
,
NULL
);
return
0
;
}
...
...
@@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np,
static
int
gpio_irq_base
=
MXC_GPIO_IRQ_START
+
ARCH_NR_GPIOS
;
gpio_irq_base
-=
32
;
irq_domain_add_
simple
(
np
,
gpio_irq_base
);
irq_domain_add_
legacy
(
np
,
32
,
gpio_irq_base
,
0
,
&
irq_domain_simple_ops
,
NULL
);
return
0
;
}
...
...
arch/arm/mach-imx/mach-imx6q.c
View file @
1f52299e
...
...
@@ -97,7 +97,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np,
static
int
gpio_irq_base
=
MXC_GPIO_IRQ_START
+
ARCH_NR_GPIOS
;
gpio_irq_base
-=
32
;
irq_domain_add_simple
(
np
,
gpio_irq_base
);
irq_domain_add_legacy
(
np
,
32
,
gpio_irq_base
,
0
,
&
irq_domain_simple_ops
,
NULL
);
return
0
;
}
...
...
arch/arm/mach-msm/board-msm8x60.c
View file @
1f52299e
...
...
@@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = {
static
void
__init
msm8x60_dt_init
(
void
)
{
struct
device_node
*
node
;
node
=
of_find_matching_node_by_address
(
NULL
,
msm_dt_gic_match
,
MSM8X60_QGIC_DIST_PHYS
);
if
(
node
)
irq_domain_add_simple
(
node
,
GIC_SPI_START
);
irq_domain_generate_simple
(
msm_dt_gic_match
,
MSM8X60_QGIC_DIST_PHYS
,
GIC_SPI_START
);
if
(
of_machine_is_compatible
(
"qcom,msm8660-surf"
))
{
printk
(
KERN_INFO
"Init surf UART registers
\n
"
);
...
...
arch/arm/mach-omap2/board-generic.c
View file @
1f52299e
...
...
@@ -68,7 +68,7 @@ static void __init omap_generic_init(void)
{
struct
device_node
*
node
=
of_find_matching_node
(
NULL
,
intc_match
);
if
(
node
)
irq_domain_add_
simple
(
node
,
0
);
irq_domain_add_
legacy
(
node
,
32
,
0
,
0
,
&
irq_domain_simple_ops
,
NULL
);
omap_sdrc_init
(
NULL
,
NULL
);
...
...
arch/arm/mach-prima2/irq.c
View file @
1f52299e
...
...
@@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void)
if
(
!
sirfsoc_intc_base
)
panic
(
"unable to map intc cpu registers
\n
"
);
irq_domain_add_
simple
(
np
,
0
);
irq_domain_add_
legacy
(
np
,
32
,
0
,
0
,
&
irq_domain_simple_ops
,
NULL
);
of_node_put
(
np
);
...
...
arch/arm/mach-versatile/core.c
View file @
1f52299e
...
...
@@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = {
void
__init
versatile_init_irq
(
void
)
{
vic_init
(
VA_VIC_BASE
,
IRQ_VIC_START
,
~
0
,
0
);
irq_domain_generate_simple
(
vic_of_match
,
VERSATILE_VIC_BASE
,
IRQ_VIC_START
);
struct
device_node
*
np
;
np
=
of_find_matching_node_by_address
(
NULL
,
vic_of_match
,
VERSATILE_VIC_BASE
);
__vic_init
(
VA_VIC_BASE
,
IRQ_VIC_START
,
~
0
,
0
,
np
);
writel
(
~
0
,
VA_SIC_BASE
+
SIC_IRQ_ENABLE_CLEAR
);
...
...
arch/c6x/Kconfig
View file @
1f52299e
...
...
@@ -12,6 +12,7 @@ config TMS320C6X
select HAVE_GENERIC_HARDIRQS
select HAVE_MEMBLOCK
select HAVE_SPARSE_IRQ
select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
...
...
arch/c6x/include/asm/irq.h
View file @
1f52299e
...
...
@@ -13,6 +13,7 @@
#ifndef _ASM_C6X_IRQ_H
#define _ASM_C6X_IRQ_H
#include <linux/irqdomain.h>
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
...
...
@@ -41,253 +42,9 @@
/* This number is used when no interrupt has been assigned */
#define NO_IRQ 0
/* 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
;
/* Interrupt controller "host" 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 host
* structure is generally created by the PIC code for a given PIC instance
* (though a host can cover more than one PIC if they have a flat number
* model). It's the host callbacks that are responsible for setting the
* irq_chip on a given irq_desc after it's been mapped.
*
* The host code and data structures are fairly agnostic to the fact that
* we use an open firmware device-tree. We do have references to struct
* device_node in two places: in irq_find_host() to find the host matching
* a given interrupt controller node, and of course as an argument to its
* counterpart host->ops->match() callback. However, those are treated as
* generic pointers by the core and the fact that it's actually a device-node
* pointer is purely a convention between callers and implementation. This
* code could thus be used on other architectures by replacing those two
* by some sort of arch-specific void * "token" used to identify interrupt
* controllers.
*/
struct
irq_host
;
struct
radix_tree_root
;
struct
device_node
;
/* Functions below are provided by the host and called whenever a new mapping
* is created or an old mapping is disposed. The host 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_host_ops
{
/* Match an interrupt controller device node to a host, returns
* 1 on a match
*/
int
(
*
match
)(
struct
irq_host
*
h
,
struct
device_node
*
node
);
/* Create or update a mapping between a virtual irq number and a hw
* irq number. This is called only once for a given mapping.
*/
int
(
*
map
)(
struct
irq_host
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
);
/* Dispose of such a mapping */
void
(
*
unmap
)(
struct
irq_host
*
h
,
unsigned
int
virq
);
/* Translate device-tree interrupt specifier from raw format coming
* from the firmware to a irq_hw_number_t (interrupt line number) and
* type (sense) that can be passed to set_irq_type(). In the absence
* of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
* will return the hw number in the first cell and IRQ_TYPE_NONE for
* the type (which amount to keeping whatever default value the
* interrupt controller has for that line)
*/
int
(
*
xlate
)(
struct
irq_host
*
h
,
struct
device_node
*
ctrler
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
);
};
struct
irq_host
{
struct
list_head
link
;
/* type of reverse mapping technique */
unsigned
int
revmap_type
;
#define IRQ_HOST_MAP_PRIORITY 0
/* core priority irqs, get irqs 1..15 */
#define IRQ_HOST_MAP_NOMAP 1
/* no fast reverse mapping */
#define IRQ_HOST_MAP_LINEAR 2
/* linear map of interrupts */
#define IRQ_HOST_MAP_TREE 3
/* radix tree */
union
{
struct
{
unsigned
int
size
;
unsigned
int
*
revmap
;
}
linear
;
struct
radix_tree_root
tree
;
}
revmap_data
;
struct
irq_host_ops
*
ops
;
void
*
host_data
;
irq_hw_number_t
inval_irq
;
/* Optional device node pointer */
struct
device_node
*
of_node
;
};
struct
irq_data
;
extern
irq_hw_number_t
irqd_to_hwirq
(
struct
irq_data
*
d
);
extern
irq_hw_number_t
virq_to_hw
(
unsigned
int
virq
);
extern
bool
virq_is_host
(
unsigned
int
virq
,
struct
irq_host
*
host
);
/**
* irq_alloc_host - Allocate a new irq_host data structure
* @of_node: optional device-tree node of the interrupt controller
* @revmap_type: type of reverse mapping to use
* @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
* @ops: map/unmap host callbacks
* @inval_irq: provide a hw number in that host space that is always invalid
*
* Allocates and initialize and irq_host structure. Note that in the case of
* IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
* for all legacy interrupts except 0 (which is always the invalid irq for
* a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
* this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
* later during boot automatically (the reverse mapping will use the slow path
* until that happens).
*/
extern
struct
irq_host
*
irq_alloc_host
(
struct
device_node
*
of_node
,
unsigned
int
revmap_type
,
unsigned
int
revmap_arg
,
struct
irq_host_ops
*
ops
,
irq_hw_number_t
inval_irq
);
/**
* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller
*/
extern
struct
irq_host
*
irq_find_host
(
struct
device_node
*
node
);
/**
* irq_set_default_host - Set a "default" host
* @host: default host pointer
*
* For convenience, it's possible to set a "default" host that will be used
* whenever NULL is passed to irq_create_mapping(). It makes life easier for
* platforms that want to manipulate a few hard coded interrupt numbers that
* aren't properly represented in the device-tree.
*/
extern
void
irq_set_default_host
(
struct
irq_host
*
host
);
/**
* irq_set_virq_count - Set the maximum number of virt irqs
* @count: number of linux virtual irqs, capped with NR_IRQS
*
* This is mainly for use by platforms like iSeries who want to program
* the virtual irq number in the controller to avoid the reverse mapping
*/
extern
void
irq_set_virq_count
(
unsigned
int
count
);
/**
* irq_create_mapping - Map a hardware interrupt into linux virq space
* @host: host owning this hardware interrupt or NULL for default host
* @hwirq: hardware irq number in that host space
*
* Only one mapping per hardware interrupt is permitted. Returns a linux
* virq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
extern
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
*/
extern
void
irq_dispose_mapping
(
unsigned
int
virq
);
/**
* irq_find_mapping - Find a linux virq from an hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a slow path, for use by generic code. It's expected that an
* irq controller implementation directly calls the appropriate low level
* mapping function.
*/
extern
unsigned
int
irq_find_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_create_direct_mapping - Allocate a virq for direct mapping
* @host: host to allocate the virq for or NULL for default host
*
* This routine is used for irq controllers which can choose the hardware
* interrupt numbers they generate. In such a case it's simplest to use
* the linux virq as the hardware interrupt number.
*/
extern
unsigned
int
irq_create_direct_mapping
(
struct
irq_host
*
host
);
/**
* irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
* @host: host owning this hardware interrupt
* @virq: linux irq number
* @hwirq: hardware irq number in that host space
*
* This is for use by irq controllers that use a radix tree reverse
* mapping for fast lookup.
*/
extern
void
irq_radix_revmap_insert
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
);
/**
* irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses radix tree
* revmaps
*/
extern
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_linear_revmap - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses linear
* revmaps. It does fallback to the slow path if the revmap doesn't exist
* yet and will create the revmap entry with appropriate locking
*/
extern
unsigned
int
irq_linear_revmap
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_alloc_virt - Allocate virtual irq numbers
* @host: host owning these new virtual irqs
* @count: number of consecutive numbers to allocate
* @hint: pass a hint number, the allocator will try to use a 1:1 mapping
*
* This is a low level function that is used internally by irq_create_mapping()
* and that can be used by some irq controllers implementations for things
* like allocating ranges of numbers for MSIs. The revmaps are left untouched.
*/
extern
unsigned
int
irq_alloc_virt
(
struct
irq_host
*
host
,
unsigned
int
count
,
unsigned
int
hint
);
/**
* irq_free_virt - Free virtual irq numbers
* @virq: virtual irq number of the first interrupt to free
* @count: number of interrupts to free
*
* This function is the opposite of irq_alloc_virt. It will not clear reverse
* maps, this should be done previously by unmap'ing the interrupt. In fact,
* all interrupts covered by the range being freed should have been unmapped
* prior to calling this.
*/
extern
void
irq_free_virt
(
unsigned
int
virq
,
unsigned
int
count
);
extern
void
__init
init_pic_c64xplus
(
void
);
...
...
arch/c6x/kernel/irq.c
View file @
1f52299e
...
...
@@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
set_irq_regs
(
old_regs
);
}
static
struct
irq_
host
*
core_host
;
static
struct
irq_
domain
*
core_domain
;
static
int
core_
host_map
(
struct
irq_host
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
static
int
core_
domain_map
(
struct
irq_domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
if
(
hw
<
4
||
hw
>=
NR_PRIORITY_IRQS
)
return
-
EINVAL
;
...
...
@@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host_ops
core_host_ops
=
{
.
map
=
core_host_map
,
static
const
struct
irq_domain_ops
core_domain_ops
=
{
.
map
=
core_domain_map
,
.
xlate
=
irq_domain_xlate_onecell
,
};
void
__init
init_IRQ
(
void
)
...
...
@@ -100,10 +101,11 @@ void __init init_IRQ(void)
np
=
of_find_compatible_node
(
NULL
,
NULL
,
"ti,c64x+core-pic"
);
if
(
np
!=
NULL
)
{
/* create the core host */
core_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_PRIORITY
,
0
,
&
core_host_ops
,
0
);
if
(
core_host
)
irq_set_default_host
(
core_host
);
core_domain
=
irq_domain_add_legacy
(
np
,
NR_PRIORITY_IRQS
,
0
,
0
,
&
core_domain_ops
,
NULL
);
if
(
core_domain
)
irq_set_default_host
(
core_domain
);
of_node_put
(
np
);
}
...
...
@@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)
return
0
;
}
/*
* IRQ controller and virtual interrupts
*/
/* The main irq map itself is an array of NR_IRQ entries containing the
* associate host and irq number. An entry with a host of NULL is free.
* An entry can be allocated if it's free, the allocator always then sets
* hwirq first to the host's invalid irq number and then fills ops.
*/
struct
irq_map_entry
{
irq_hw_number_t
hwirq
;
struct
irq_host
*
host
;
};
static
LIST_HEAD
(
irq_hosts
);
static
DEFINE_RAW_SPINLOCK
(
irq_big_lock
);
static
DEFINE_MUTEX
(
revmap_trees_mutex
);
static
struct
irq_map_entry
irq_map
[
NR_IRQS
];
static
unsigned
int
irq_virq_count
=
NR_IRQS
;
static
struct
irq_host
*
irq_default_host
;
irq_hw_number_t
irqd_to_hwirq
(
struct
irq_data
*
d
)
{
return
irq_map
[
d
->
irq
].
hwirq
;
return
d
->
hwirq
;
}
EXPORT_SYMBOL_GPL
(
irqd_to_hwirq
);
irq_hw_number_t
virq_to_hw
(
unsigned
int
virq
)
{
return
irq_map
[
virq
].
hwirq
;
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
return
WARN_ON
(
!
irq_data
)
?
0
:
irq_data
->
hwirq
;
}
EXPORT_SYMBOL_GPL
(
virq_to_hw
);
bool
virq_is_host
(
unsigned
int
virq
,
struct
irq_host
*
host
)
{
return
irq_map
[
virq
].
host
==
host
;
}
EXPORT_SYMBOL_GPL
(
virq_is_host
);
static
int
default_irq_host_match
(
struct
irq_host
*
h
,
struct
device_node
*
np
)
{
return
h
->
of_node
!=
NULL
&&
h
->
of_node
==
np
;
}
struct
irq_host
*
irq_alloc_host
(
struct
device_node
*
of_node
,
unsigned
int
revmap_type
,
unsigned
int
revmap_arg
,
struct
irq_host_ops
*
ops
,
irq_hw_number_t
inval_irq
)
{
struct
irq_host
*
host
;
unsigned
int
size
=
sizeof
(
struct
irq_host
);
unsigned
int
i
;
unsigned
int
*
rmap
;
unsigned
long
flags
;
/* Allocate structure and revmap table if using linear mapping */
if
(
revmap_type
==
IRQ_HOST_MAP_LINEAR
)
size
+=
revmap_arg
*
sizeof
(
unsigned
int
);
host
=
kzalloc
(
size
,
GFP_KERNEL
);
if
(
host
==
NULL
)
return
NULL
;
/* Fill structure */
host
->
revmap_type
=
revmap_type
;
host
->
inval_irq
=
inval_irq
;
host
->
ops
=
ops
;
host
->
of_node
=
of_node_get
(
of_node
);
if
(
host
->
ops
->
match
==
NULL
)
host
->
ops
->
match
=
default_irq_host_match
;
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
/* Check for the priority controller. */
if
(
revmap_type
==
IRQ_HOST_MAP_PRIORITY
)
{
if
(
irq_map
[
0
].
host
!=
NULL
)
{
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
of_node_put
(
host
->
of_node
);
kfree
(
host
);
return
NULL
;
}
irq_map
[
0
].
host
=
host
;
}
list_add
(
&
host
->
link
,
&
irq_hosts
);
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
/* Additional setups per revmap type */
switch
(
revmap_type
)
{
case
IRQ_HOST_MAP_PRIORITY
:
/* 0 is always the invalid number for priority */
host
->
inval_irq
=
0
;
/* setup us as the host for all priority interrupts */
for
(
i
=
1
;
i
<
NR_PRIORITY_IRQS
;
i
++
)
{
irq_map
[
i
].
hwirq
=
i
;
smp_wmb
();
irq_map
[
i
].
host
=
host
;
smp_wmb
();
ops
->
map
(
host
,
i
,
i
);
}
break
;
case
IRQ_HOST_MAP_LINEAR
:
rmap
=
(
unsigned
int
*
)(
host
+
1
);
for
(
i
=
0
;
i
<
revmap_arg
;
i
++
)
rmap
[
i
]
=
NO_IRQ
;
host
->
revmap_data
.
linear
.
size
=
revmap_arg
;
smp_wmb
();
host
->
revmap_data
.
linear
.
revmap
=
rmap
;
break
;
case
IRQ_HOST_MAP_TREE
:
INIT_RADIX_TREE
(
&
host
->
revmap_data
.
tree
,
GFP_KERNEL
);
break
;
default:
break
;
}
pr_debug
(
"irq: Allocated host of type %d @0x%p
\n
"
,
revmap_type
,
host
);
return
host
;
}
struct
irq_host
*
irq_find_host
(
struct
device_node
*
node
)
{
struct
irq_host
*
h
,
*
found
=
NULL
;
unsigned
long
flags
;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*/
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
list_for_each_entry
(
h
,
&
irq_hosts
,
link
)
if
(
h
->
ops
->
match
(
h
,
node
))
{
found
=
h
;
break
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
found
;
}
EXPORT_SYMBOL_GPL
(
irq_find_host
);
void
irq_set_default_host
(
struct
irq_host
*
host
)
{
pr_debug
(
"irq: Default host set to @0x%p
\n
"
,
host
);
irq_default_host
=
host
;
}
void
irq_set_virq_count
(
unsigned
int
count
)
{
pr_debug
(
"irq: Trying to set virq count to %d
\n
"
,
count
);
BUG_ON
(
count
<
NR_PRIORITY_IRQS
);
if
(
count
<
NR_IRQS
)
irq_virq_count
=
count
;
}
static
int
irq_setup_virq
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
int
res
;
res
=
irq_alloc_desc_at
(
virq
,
0
);
if
(
res
!=
virq
)
{
pr_debug
(
"irq: -> allocating desc failed
\n
"
);
goto
error
;
}
/* map it */
smp_wmb
();
irq_map
[
virq
].
hwirq
=
hwirq
;
smp_mb
();
if
(
host
->
ops
->
map
(
host
,
virq
,
hwirq
))
{
pr_debug
(
"irq: -> mapping failed, freeing
\n
"
);
goto
errdesc
;
}
irq_clear_status_flags
(
virq
,
IRQ_NOREQUEST
);
return
0
;
errdesc:
irq_free_descs
(
virq
,
1
);
error:
irq_free_virt
(
virq
,
1
);
return
-
1
;
}
unsigned
int
irq_create_direct_mapping
(
struct
irq_host
*
host
)
{
unsigned
int
virq
;
if
(
host
==
NULL
)
host
=
irq_default_host
;
BUG_ON
(
host
==
NULL
);
WARN_ON
(
host
->
revmap_type
!=
IRQ_HOST_MAP_NOMAP
);
virq
=
irq_alloc_virt
(
host
,
1
,
0
);
if
(
virq
==
NO_IRQ
)
{
pr_debug
(
"irq: create_direct virq allocation failed
\n
"
);
return
NO_IRQ
;
}
pr_debug
(
"irq: create_direct obtained virq %d
\n
"
,
virq
);
if
(
irq_setup_virq
(
host
,
virq
,
virq
))
return
NO_IRQ
;
return
virq
;
}
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
virq
,
hint
;
pr_debug
(
"irq: irq_create_mapping(0x%p, 0x%lx)
\n
"
,
host
,
hwirq
);
/* Look for default host if nececssary */
if
(
host
==
NULL
)
host
=
irq_default_host
;
if
(
host
==
NULL
)
{
printk
(
KERN_WARNING
"irq_create_mapping called for"
" NULL host, hwirq=%lx
\n
"
,
hwirq
);
WARN_ON
(
1
);
return
NO_IRQ
;
}
pr_debug
(
"irq: -> using host @%p
\n
"
,
host
);
/* Check if mapping already exists */
virq
=
irq_find_mapping
(
host
,
hwirq
);
if
(
virq
!=
NO_IRQ
)
{
pr_debug
(
"irq: -> existing mapping on virq %d
\n
"
,
virq
);
return
virq
;
}
/* Allocate a virtual interrupt number */
hint
=
hwirq
%
irq_virq_count
;
virq
=
irq_alloc_virt
(
host
,
1
,
hint
);
if
(
virq
==
NO_IRQ
)
{
pr_debug
(
"irq: -> virq allocation failed
\n
"
);
return
NO_IRQ
;
}
if
(
irq_setup_virq
(
host
,
virq
,
hwirq
))
return
NO_IRQ
;
pr_debug
(
"irq: irq %lu on host %s mapped to virtual irq %u
\n
"
,
hwirq
,
host
->
of_node
?
host
->
of_node
->
full_name
:
"null"
,
virq
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_mapping
);
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
struct
irq_host
*
host
;
irq_hw_number_t
hwirq
;
unsigned
int
type
=
IRQ_TYPE_NONE
;
unsigned
int
virq
;
if
(
controller
==
NULL
)
host
=
irq_default_host
;
else
host
=
irq_find_host
(
controller
);
if
(
host
==
NULL
)
{
printk
(
KERN_WARNING
"irq: no irq host found for %s !
\n
"
,
controller
->
full_name
);
return
NO_IRQ
;
}
/* If host has no translation, then we assume interrupt line */
if
(
host
->
ops
->
xlate
==
NULL
)
hwirq
=
intspec
[
0
];
else
{
if
(
host
->
ops
->
xlate
(
host
,
controller
,
intspec
,
intsize
,
&
hwirq
,
&
type
))
return
NO_IRQ
;
}
/* Create mapping */
virq
=
irq_create_mapping
(
host
,
hwirq
);
if
(
virq
==
NO_IRQ
)
return
virq
;
/* Set type if specified and different than the current one */
if
(
type
!=
IRQ_TYPE_NONE
&&
type
!=
(
irqd_get_trigger_type
(
irq_get_irq_data
(
virq
))))
irq_set_irq_type
(
virq
,
type
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
struct
irq_host
*
host
;
irq_hw_number_t
hwirq
;
if
(
virq
==
NO_IRQ
)
return
;
/* Never unmap priority interrupts */
if
(
virq
<
NR_PRIORITY_IRQS
)
return
;
host
=
irq_map
[
virq
].
host
;
if
(
WARN_ON
(
host
==
NULL
))
return
;
irq_set_status_flags
(
virq
,
IRQ_NOREQUEST
);
/* remove chip and handler */
irq_set_chip_and_handler
(
virq
,
NULL
,
NULL
);
/* Make sure it's completed */
synchronize_irq
(
virq
);
/* Tell the PIC about it */
if
(
host
->
ops
->
unmap
)
host
->
ops
->
unmap
(
host
,
virq
);
smp_mb
();
/* Clear reverse map */
hwirq
=
irq_map
[
virq
].
hwirq
;
switch
(
host
->
revmap_type
)
{
case
IRQ_HOST_MAP_LINEAR
:
if
(
hwirq
<
host
->
revmap_data
.
linear
.
size
)
host
->
revmap_data
.
linear
.
revmap
[
hwirq
]
=
NO_IRQ
;
break
;
case
IRQ_HOST_MAP_TREE
:
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_delete
(
&
host
->
revmap_data
.
tree
,
hwirq
);
mutex_unlock
(
&
revmap_trees_mutex
);
break
;
}
/* Destroy map */
smp_mb
();
irq_map
[
virq
].
hwirq
=
host
->
inval_irq
;
irq_free_descs
(
virq
,
1
);
/* Free it */
irq_free_virt
(
virq
,
1
);
}
EXPORT_SYMBOL_GPL
(
irq_dispose_mapping
);
unsigned
int
irq_find_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
i
;
unsigned
int
hint
=
hwirq
%
irq_virq_count
;
/* Look for default host if nececssary */
if
(
host
==
NULL
)
host
=
irq_default_host
;
if
(
host
==
NULL
)
return
NO_IRQ
;
/* Slow path does a linear search of the map */
i
=
hint
;
do
{
if
(
irq_map
[
i
].
host
==
host
&&
irq_map
[
i
].
hwirq
==
hwirq
)
return
i
;
i
++
;
if
(
i
>=
irq_virq_count
)
i
=
4
;
}
while
(
i
!=
hint
);
return
NO_IRQ
;
}
EXPORT_SYMBOL_GPL
(
irq_find_mapping
);
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
struct
irq_map_entry
*
ptr
;
unsigned
int
virq
;
if
(
WARN_ON_ONCE
(
host
->
revmap_type
!=
IRQ_HOST_MAP_TREE
))
return
irq_find_mapping
(
host
,
hwirq
);
/*
* The ptr returned references the static global irq_map.
* but freeing an irq can delete nodes along the path to
* do the lookup via call_rcu.
*/
rcu_read_lock
();
ptr
=
radix_tree_lookup
(
&
host
->
revmap_data
.
tree
,
hwirq
);
rcu_read_unlock
();
/*
* If found in radix tree, then fine.
* Else fallback to linear lookup - this should not happen in practice
* as it means that we failed to insert the node in the radix tree.
*/
if
(
ptr
)
virq
=
ptr
-
irq_map
;
else
virq
=
irq_find_mapping
(
host
,
hwirq
);
return
virq
;
}
void
irq_radix_revmap_insert
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
if
(
WARN_ON
(
host
->
revmap_type
!=
IRQ_HOST_MAP_TREE
))
return
;
if
(
virq
!=
NO_IRQ
)
{
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_insert
(
&
host
->
revmap_data
.
tree
,
hwirq
,
&
irq_map
[
virq
]);
mutex_unlock
(
&
revmap_trees_mutex
);
}
}
unsigned
int
irq_linear_revmap
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
*
revmap
;
if
(
WARN_ON_ONCE
(
host
->
revmap_type
!=
IRQ_HOST_MAP_LINEAR
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Check revmap bounds */
if
(
unlikely
(
hwirq
>=
host
->
revmap_data
.
linear
.
size
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Check if revmap was allocated */
revmap
=
host
->
revmap_data
.
linear
.
revmap
;
if
(
unlikely
(
revmap
==
NULL
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Fill up revmap with slow path if no mapping found */
if
(
unlikely
(
revmap
[
hwirq
]
==
NO_IRQ
))
revmap
[
hwirq
]
=
irq_find_mapping
(
host
,
hwirq
);
return
revmap
[
hwirq
];
}
unsigned
int
irq_alloc_virt
(
struct
irq_host
*
host
,
unsigned
int
count
,
unsigned
int
hint
)
{
unsigned
long
flags
;
unsigned
int
i
,
j
,
found
=
NO_IRQ
;
if
(
count
==
0
||
count
>
(
irq_virq_count
-
NR_PRIORITY_IRQS
))
return
NO_IRQ
;
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
/* Use hint for 1 interrupt if any */
if
(
count
==
1
&&
hint
>=
NR_PRIORITY_IRQS
&&
hint
<
irq_virq_count
&&
irq_map
[
hint
].
host
==
NULL
)
{
found
=
hint
;
goto
hint_found
;
}
/* Look for count consecutive numbers in the allocatable
* (non-legacy) space
*/
for
(
i
=
NR_PRIORITY_IRQS
,
j
=
0
;
i
<
irq_virq_count
;
i
++
)
{
if
(
irq_map
[
i
].
host
!=
NULL
)
j
=
0
;
else
j
++
;
if
(
j
==
count
)
{
found
=
i
-
count
+
1
;
break
;
}
}
if
(
found
==
NO_IRQ
)
{
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
NO_IRQ
;
}
hint_found:
for
(
i
=
found
;
i
<
(
found
+
count
);
i
++
)
{
irq_map
[
i
].
hwirq
=
host
->
inval_irq
;
smp_wmb
();
irq_map
[
i
].
host
=
host
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
found
;
}
void
irq_free_virt
(
unsigned
int
virq
,
unsigned
int
count
)
{
unsigned
long
flags
;
unsigned
int
i
;
WARN_ON
(
virq
<
NR_PRIORITY_IRQS
);
WARN_ON
(
count
==
0
||
(
virq
+
count
)
>
irq_virq_count
);
if
(
virq
<
NR_PRIORITY_IRQS
)
{
if
(
virq
+
count
<
NR_PRIORITY_IRQS
)
return
;
count
-=
NR_PRIORITY_IRQS
-
virq
;
virq
=
NR_PRIORITY_IRQS
;
}
if
(
count
>
irq_virq_count
||
virq
>
irq_virq_count
-
count
)
{
if
(
virq
>
irq_virq_count
)
return
;
count
=
irq_virq_count
-
virq
;
}
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
for
(
i
=
virq
;
i
<
(
virq
+
count
);
i
++
)
{
struct
irq_host
*
host
;
host
=
irq_map
[
i
].
host
;
irq_map
[
i
].
hwirq
=
host
->
inval_irq
;
smp_wmb
();
irq_map
[
i
].
host
=
NULL
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
}
#ifdef CONFIG_VIRQ_DEBUG
static
int
virq_debug_show
(
struct
seq_file
*
m
,
void
*
private
)
{
unsigned
long
flags
;
struct
irq_desc
*
desc
;
const
char
*
p
;
static
const
char
none
[]
=
"none"
;
void
*
data
;
int
i
;
seq_printf
(
m
,
"%-5s %-7s %-15s %-18s %s
\n
"
,
"virq"
,
"hwirq"
,
"chip name"
,
"chip data"
,
"host name"
);
for
(
i
=
1
;
i
<
nr_irqs
;
i
++
)
{
desc
=
irq_to_desc
(
i
);
if
(
!
desc
)
continue
;
raw_spin_lock_irqsave
(
&
desc
->
lock
,
flags
);
if
(
desc
->
action
&&
desc
->
action
->
handler
)
{
struct
irq_chip
*
chip
;
seq_printf
(
m
,
"%5d "
,
i
);
seq_printf
(
m
,
"0x%05lx "
,
irq_map
[
i
].
hwirq
);
chip
=
irq_desc_get_chip
(
desc
);
if
(
chip
&&
chip
->
name
)
p
=
chip
->
name
;
else
p
=
none
;
seq_printf
(
m
,
"%-15s "
,
p
);
data
=
irq_desc_get_chip_data
(
desc
);
seq_printf
(
m
,
"0x%16p "
,
data
);
if
(
irq_map
[
i
].
host
&&
irq_map
[
i
].
host
->
of_node
)
p
=
irq_map
[
i
].
host
->
of_node
->
full_name
;
else
p
=
none
;
seq_printf
(
m
,
"%s
\n
"
,
p
);
}
raw_spin_unlock_irqrestore
(
&
desc
->
lock
,
flags
);
}
return
0
;
}
static
int
virq_debug_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
virq_debug_show
,
inode
->
i_private
);
}
static
const
struct
file_operations
virq_debug_fops
=
{
.
open
=
virq_debug_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
__init
irq_debugfs_init
(
void
)
{
if
(
debugfs_create_file
(
"virq_mapping"
,
S_IRUGO
,
powerpc_debugfs_root
,
NULL
,
&
virq_debug_fops
)
==
NULL
)
return
-
ENOMEM
;
return
0
;
}
device_initcall
(
irq_debugfs_init
);
#endif
/* CONFIG_VIRQ_DEBUG */
arch/c6x/platforms/megamod-pic.c
View file @
1f52299e
...
...
@@ -48,7 +48,7 @@ struct megamod_regs {
};
struct
megamod_pic
{
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
struct
megamod_regs
__iomem
*
regs
;
raw_spinlock_t
lock
;
...
...
@@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
}
}
static
int
megamod_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
megamod_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
megamod_pic
*
pic
=
h
->
host_data
;
...
...
@@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
megamod_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
)
{
/* megamod intspecs must have 1 cell */
BUG_ON
(
intsize
!=
1
);
*
out_hwirq
=
intspec
[
0
];
*
out_type
=
IRQ_TYPE_NONE
;
return
0
;
}
static
struct
irq_host_ops
megamod_host_ops
=
{
static
const
struct
irq_domain_ops
megamod_domain_ops
=
{
.
map
=
megamod_map
,
.
xlate
=
megamod_xlate
,
.
xlate
=
irq_domain_xlate_onecell
,
};
static
void
__init
set_megamod_mux
(
struct
megamod_pic
*
pic
,
int
src
,
int
output
)
...
...
@@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
return
NULL
;
}
pic
->
irqhost
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
NR_COMBINERS
*
32
,
&
megamod_host_ops
,
IRQ_UNMAPPED
);
pic
->
irqhost
=
irq_domain_add_linear
(
np
,
NR_COMBINERS
*
32
,
&
megamod_domain_ops
,
pic
);
if
(
!
pic
->
irqhost
)
{
pr_err
(
"%s: Could not alloc host.
\n
"
,
np
->
full_name
);
goto
error_free
;
...
...
arch/microblaze/Kconfig
View file @
1f52299e
...
...
@@ -14,6 +14,7 @@ config MICROBLAZE
select TRACING_SUPPORT
select OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
...
...
arch/microblaze/include/asm/hardirq.h
View file @
1f52299e
/*
* Copyright (C) 2006 Atmark Techno, Inc.
*
* 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.
*/
#ifndef _ASM_MICROBLAZE_HARDIRQ_H
#define _ASM_MICROBLAZE_HARDIRQ_H
/* should be defined in each interrupt controller driver */
extern
unsigned
int
get_irq
(
struct
pt_regs
*
regs
);
#include <asm-generic/hardirq.h>
#endif
/* _ASM_MICROBLAZE_HARDIRQ_H */
arch/microblaze/include/asm/irq.h
View file @
1f52299e
...
...
@@ -9,49 +9,13 @@
#ifndef _ASM_MICROBLAZE_IRQ_H
#define _ASM_MICROBLAZE_IRQ_H
/*
* Linux IRQ# is currently offset by one to map to the hardware
* irq number. So hardware IRQ0 maps to Linux irq 1.
*/
#define NO_IRQ_OFFSET 1
#define IRQ_OFFSET NO_IRQ_OFFSET
#define NR_IRQS (32 + IRQ_OFFSET)
#define NR_IRQS (32 + 1)
#include <asm-generic/irq.h>
/* 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
;
extern
unsigned
int
nr_irq
;
struct
pt_regs
;
extern
void
do_IRQ
(
struct
pt_regs
*
regs
);
/** FIXME - not implement
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
*/
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
return
;
}
struct
irq_host
;
/**
* irq_create_mapping - Map a hardware interrupt into linux virq space
* @host: host owning this hardware interrupt or NULL for default host
* @hwirq: hardware irq number in that host space
*
* Only one mapping per hardware interrupt is permitted. Returns a linux
* virq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
extern
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/* should be defined in each interrupt controller driver */
extern
unsigned
int
get_irq
(
void
);
#endif
/* _ASM_MICROBLAZE_IRQ_H */
arch/microblaze/kernel/intc.c
View file @
1f52299e
...
...
@@ -9,6 +9,7 @@
*/
#include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <asm/page.h>
#include <linux/io.h>
...
...
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
#define INTC_BASE intc_baseaddr
#endif
unsigned
int
nr_irq
;
/* No one else should require these constants, so define them locally here. */
#define ISR 0x00
/* Interrupt Status Register */
#define IPR 0x04
/* Interrupt Pending Register */
...
...
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
.
irq_mask_ack
=
intc_mask_ack
,
};
unsigned
int
get_irq
(
struct
pt_regs
*
regs
)
static
struct
irq_domain
*
root_domain
;
unsigned
int
get_irq
(
void
)
{
int
irq
;
unsigned
int
hwirq
,
irq
=
-
1
;
/*
* NOTE: This function is the one that needs to be improved in
* order to handle multiple interrupt controllers. It currently
* is hardcoded to check for interrupts only on the first INTC.
*/
irq
=
in_be32
(
INTC_BASE
+
IVR
)
+
NO_IRQ_OFFSET
;
pr_debug
(
"get_irq: %d
\n
"
,
irq
);
hwirq
=
in_be32
(
INTC_BASE
+
IVR
);
if
(
hwirq
!=
-
1U
)
irq
=
irq_find_mapping
(
root_domain
,
hwirq
);
pr_debug
(
"get_irq: hwirq=%d, irq=%d
\n
"
,
hwirq
,
irq
);
return
irq
;
}
int
xintc_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
irq_hw_number_t
hw
)
{
u32
intr_mask
=
(
u32
)
d
->
host_data
;
if
(
intr_mask
&
(
1
<<
hw
))
{
irq_set_chip_and_handler_name
(
irq
,
&
intc_dev
,
handle_edge_irq
,
"edge"
);
irq_clear_status_flags
(
irq
,
IRQ_LEVEL
);
}
else
{
irq_set_chip_and_handler_name
(
irq
,
&
intc_dev
,
handle_level_irq
,
"level"
);
irq_set_status_flags
(
irq
,
IRQ_LEVEL
);
}
return
0
;
}
static
const
struct
irq_domain_ops
xintc_irq_domain_ops
=
{
.
xlate
=
irq_domain_xlate_onetwocell
,
.
map
=
xintc_map
,
};
void
__init
init_IRQ
(
void
)
{
u32
i
,
intr_mask
;
u32
nr_irq
,
intr_mask
;
struct
device_node
*
intc
=
NULL
;
#ifdef CONFIG_SELFMOD_INTC
unsigned
int
intc_baseaddr
=
0
;
...
...
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
/* Turn on the Master Enable. */
out_be32
(
intc_baseaddr
+
MER
,
MER_HIE
|
MER_ME
);
for
(
i
=
IRQ_OFFSET
;
i
<
(
nr_irq
+
IRQ_OFFSET
);
++
i
)
{
if
(
intr_mask
&
(
0x00000001
<<
(
i
-
IRQ_OFFSET
)))
{
irq_set_chip_and_handler_name
(
i
,
&
intc_dev
,
handle_edge_irq
,
"edge"
);
irq_clear_status_flags
(
i
,
IRQ_LEVEL
);
}
else
{
irq_set_chip_and_handler_name
(
i
,
&
intc_dev
,
handle_level_irq
,
"level"
);
irq_set_status_flags
(
i
,
IRQ_LEVEL
);
}
irq_get_irq_data
(
i
)
->
hwirq
=
i
-
IRQ_OFFSET
;
}
/* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
* lazy and Michal can clean it up to something nicer when he tests
* and commits this patch. ~~gcl */
root_domain
=
irq_domain_add_linear
(
intc
,
nr_irq
,
&
xintc_irq_domain_ops
,
(
void
*
)
intr_mask
);
}
arch/microblaze/kernel/irq.c
View file @
1f52299e
...
...
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
trace_hardirqs_off
();
irq_enter
();
irq
=
get_irq
(
regs
);
irq
=
get_irq
();
next_irq:
BUG_ON
(
!
irq
);
/* Substract 1 because of get_irq */
generic_handle_irq
(
irq
+
IRQ_OFFSET
-
NO_IRQ_OFFSET
);
generic_handle_irq
(
irq
);
irq
=
get_irq
(
regs
);
if
(
irq
)
{
irq
=
get_irq
();
if
(
irq
!=
-
1U
)
{
pr_debug
(
"next irq: %d
\n
"
,
irq
);
++
concurrent_irq
;
goto
next_irq
;
...
...
@@ -48,18 +47,3 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
set_irq_regs
(
old_regs
);
trace_hardirqs_on
();
}
/* MS: There is no any advance mapping mechanism. We are using simple 32bit
intc without any cascades or any connection that's why mapping is 1:1 */
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
return
hwirq
+
IRQ_OFFSET
;
}
EXPORT_SYMBOL_GPL
(
irq_create_mapping
);
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
return
intspec
[
0
]
+
IRQ_OFFSET
;
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
arch/microblaze/kernel/setup.c
View file @
1f52299e
...
...
@@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree
();
/* NOTE I think that this function is not necessary to call */
/* irq_early_init(); */
setup_cpuinfo
();
microblaze_cache_init
();
...
...
arch/mips/Kconfig
View file @
1f52299e
...
...
@@ -2327,6 +2327,7 @@ config USE_OF
bool "Flattened Device Tree support"
select OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
help
Include support for flattened device tree machine descriptions.
...
...
arch/mips/include/asm/irq.h
View file @
1f52299e
...
...
@@ -11,15 +11,12 @@
#include <linux/linkage.h>
#include <linux/smp.h>
#include <linux/irqdomain.h>
#include <asm/mipsmtregs.h>
#include <irq.h>
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
}
#ifdef CONFIG_I8259
static
inline
int
irq_canonicalize
(
int
irq
)
{
...
...
arch/mips/kernel/prom.c
View file @
1f52299e
...
...
@@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
}
#endif
/*
* irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
*
* Currently the mapping mechanism is trivial; simple flat hwirq numbers are
* mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not
* supported.
*/
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
return
intspec
[
0
];
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
void
__init
early_init_devtree
(
void
*
params
)
{
/* Setup flat device-tree pointer */
...
...
arch/openrisc/include/asm/prom.h
View file @
1f52299e
...
...
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <asm/irq.h>
#include <linux/irqdomain.h>
#include <linux/atomic.h>
#include <linux/of_irq.h>
#include <linux/of_fdt.h>
...
...
@@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np);
struct
pci_dev
;
extern
int
of_irq_map_pci
(
struct
pci_dev
*
pdev
,
struct
of_irq
*
out_irq
);
/* This routine is here to provide compatibility with how powerpc
* handles IRQ mapping for OF device nodes. We precompute and permanently
* register them in the platform_device objects, whereas powerpc computes them
* on request.
*/
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
}
#endif
/* __ASSEMBLY__ */
#endif
/* __KERNEL__ */
#endif
/* _ASM_OPENRISC_PROM_H */
arch/powerpc/Kconfig
View file @
1f52299e
...
...
@@ -135,6 +135,7 @@ config PPC
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select IRQ_PER_CPU
select IRQ_DOMAIN
select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL
select IRQ_FORCED_THREADING
...
...
arch/powerpc/include/asm/ehv_pic.h
View file @
1f52299e
...
...
@@ -25,7 +25,7 @@
struct
ehv_pic
{
/* The remapper for this EHV_PIC */
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
/* The "linux" controller struct */
struct
irq_chip
hc_irq
;
...
...
arch/powerpc/include/asm/i8259.h
View file @
1f52299e
...
...
@@ -6,7 +6,7 @@
extern
void
i8259_init
(
struct
device_node
*
node
,
unsigned
long
intack_addr
);
extern
unsigned
int
i8259_irq
(
void
);
extern
struct
irq_
host
*
i8259_get_host
(
void
);
extern
struct
irq_
domain
*
i8259_get_host
(
void
);
#endif
/* __KERNEL__ */
#endif
/* _ASM_POWERPC_I8259_H */
arch/powerpc/include/asm/irq.h
View file @
1f52299e
...
...
@@ -9,6 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/irqdomain.h>
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
...
...
@@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts;
/* Total number of virq in the platform */
#define NR_IRQS CONFIG_NR_IRQS
/* Number of irqs reserved for the legacy controller */
#define NUM_ISA_INTERRUPTS 16
/* Same thing, used by the generic IRQ code */
#define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS
/* 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
;
/* Interrupt controller "host" 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 host
* structure is generally created by the PIC code for a given PIC instance
* (though a host can cover more than one PIC if they have a flat number
* model). It's the host callbacks that are responsible for setting the
* irq_chip on a given irq_desc after it's been mapped.
*
* The host code and data structures are fairly agnostic to the fact that
* we use an open firmware device-tree. We do have references to struct
* device_node in two places: in irq_find_host() to find the host matching
* a given interrupt controller node, and of course as an argument to its
* counterpart host->ops->match() callback. However, those are treated as
* generic pointers by the core and the fact that it's actually a device-node
* pointer is purely a convention between callers and implementation. This
* code could thus be used on other architectures by replacing those two
* by some sort of arch-specific void * "token" used to identify interrupt
* controllers.
*/
struct
irq_host
;
struct
radix_tree_root
;
/* Functions below are provided by the host and called whenever a new mapping
* is created or an old mapping is disposed. The host 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_host_ops
{
/* Match an interrupt controller device node to a host, returns
* 1 on a match
*/
int
(
*
match
)(
struct
irq_host
*
h
,
struct
device_node
*
node
);
/* Create or update a mapping between a virtual irq number and a hw
* irq number. This is called only once for a given mapping.
*/
int
(
*
map
)(
struct
irq_host
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
);
/* Dispose of such a mapping */
void
(
*
unmap
)(
struct
irq_host
*
h
,
unsigned
int
virq
);
/* Translate device-tree interrupt specifier from raw format coming
* from the firmware to a irq_hw_number_t (interrupt line number) and
* type (sense) that can be passed to set_irq_type(). In the absence
* of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
* will return the hw number in the first cell and IRQ_TYPE_NONE for
* the type (which amount to keeping whatever default value the
* interrupt controller has for that line)
*/
int
(
*
xlate
)(
struct
irq_host
*
h
,
struct
device_node
*
ctrler
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
);
};
struct
irq_host
{
struct
list_head
link
;
/* type of reverse mapping technique */
unsigned
int
revmap_type
;
#define IRQ_HOST_MAP_LEGACY 0
/* legacy 8259, gets irqs 1..15 */
#define IRQ_HOST_MAP_NOMAP 1
/* no fast reverse mapping */
#define IRQ_HOST_MAP_LINEAR 2
/* linear map of interrupts */
#define IRQ_HOST_MAP_TREE 3
/* radix tree */
union
{
struct
{
unsigned
int
size
;
unsigned
int
*
revmap
;
}
linear
;
struct
radix_tree_root
tree
;
}
revmap_data
;
struct
irq_host_ops
*
ops
;
void
*
host_data
;
irq_hw_number_t
inval_irq
;
/* Optional device node pointer */
struct
device_node
*
of_node
;
};
struct
irq_data
;
extern
irq_hw_number_t
irqd_to_hwirq
(
struct
irq_data
*
d
);
extern
irq_hw_number_t
virq_to_hw
(
unsigned
int
virq
);
extern
bool
virq_is_host
(
unsigned
int
virq
,
struct
irq_host
*
host
);
/**
* irq_alloc_host - Allocate a new irq_host data structure
* @of_node: optional device-tree node of the interrupt controller
* @revmap_type: type of reverse mapping to use
* @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
* @ops: map/unmap host callbacks
* @inval_irq: provide a hw number in that host space that is always invalid
*
* Allocates and initialize and irq_host structure. Note that in the case of
* IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
* for all legacy interrupts except 0 (which is always the invalid irq for
* a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
* this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
* later during boot automatically (the reverse mapping will use the slow path
* until that happens).
*/
extern
struct
irq_host
*
irq_alloc_host
(
struct
device_node
*
of_node
,
unsigned
int
revmap_type
,
unsigned
int
revmap_arg
,
struct
irq_host_ops
*
ops
,
irq_hw_number_t
inval_irq
);
/**
* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller
*/
extern
struct
irq_host
*
irq_find_host
(
struct
device_node
*
node
);
/**
* irq_set_default_host - Set a "default" host
* @host: default host pointer
*
* For convenience, it's possible to set a "default" host that will be used
* whenever NULL is passed to irq_create_mapping(). It makes life easier for
* platforms that want to manipulate a few hard coded interrupt numbers that
* aren't properly represented in the device-tree.
*/
extern
void
irq_set_default_host
(
struct
irq_host
*
host
);
/**
* irq_set_virq_count - Set the maximum number of virt irqs
* @count: number of linux virtual irqs, capped with NR_IRQS
*
* This is mainly for use by platforms like iSeries who want to program
* the virtual irq number in the controller to avoid the reverse mapping
*/
extern
void
irq_set_virq_count
(
unsigned
int
count
);
/**
* irq_create_mapping - Map a hardware interrupt into linux virq space
* @host: host owning this hardware interrupt or NULL for default host
* @hwirq: hardware irq number in that host space
*
* Only one mapping per hardware interrupt is permitted. Returns a linux
* virq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
extern
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
*/
extern
void
irq_dispose_mapping
(
unsigned
int
virq
);
/**
* irq_find_mapping - Find a linux virq from an hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a slow path, for use by generic code. It's expected that an
* irq controller implementation directly calls the appropriate low level
* mapping function.
*/
extern
unsigned
int
irq_find_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_create_direct_mapping - Allocate a virq for direct mapping
* @host: host to allocate the virq for or NULL for default host
*
* This routine is used for irq controllers which can choose the hardware
* interrupt numbers they generate. In such a case it's simplest to use
* the linux virq as the hardware interrupt number.
*/
extern
unsigned
int
irq_create_direct_mapping
(
struct
irq_host
*
host
);
/**
* irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
* @host: host owning this hardware interrupt
* @virq: linux irq number
* @hwirq: hardware irq number in that host space
*
* This is for use by irq controllers that use a radix tree reverse
* mapping for fast lookup.
*/
extern
void
irq_radix_revmap_insert
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
);
/**
* irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses radix tree
* revmaps
*/
extern
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_linear_revmap - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses linear
* revmaps. It does fallback to the slow path if the revmap doesn't exist
* yet and will create the revmap entry with appropriate locking
*/
extern
unsigned
int
irq_linear_revmap
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
);
/**
* irq_alloc_virt - Allocate virtual irq numbers
* @host: host owning these new virtual irqs
* @count: number of consecutive numbers to allocate
* @hint: pass a hint number, the allocator will try to use a 1:1 mapping
*
* This is a low level function that is used internally by irq_create_mapping()
* and that can be used by some irq controllers implementations for things
* like allocating ranges of numbers for MSIs. The revmaps are left untouched.
*/
extern
unsigned
int
irq_alloc_virt
(
struct
irq_host
*
host
,
unsigned
int
count
,
unsigned
int
hint
);
/**
* irq_free_virt - Free virtual irq numbers
* @virq: virtual irq number of the first interrupt to free
* @count: number of interrupts to free
*
* This function is the opposite of irq_alloc_virt. It will not clear reverse
* maps, this should be done previously by unmap'ing the interrupt. In fact,
* all interrupts covered by the range being freed should have been unmapped
* prior to calling this.
*/
extern
void
irq_free_virt
(
unsigned
int
virq
,
unsigned
int
count
);
/**
* irq_early_init - Init irq remapping subsystem
...
...
arch/powerpc/include/asm/mpic.h
View file @
1f52299e
...
...
@@ -255,7 +255,7 @@ struct mpic
struct
device_node
*
node
;
/* The remapper for this MPIC */
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
/* The "linux" controller struct */
struct
irq_chip
hc_irq
;
...
...
arch/powerpc/include/asm/xics.h
View file @
1f52299e
...
...
@@ -86,7 +86,7 @@ struct ics {
extern
unsigned
int
xics_default_server
;
extern
unsigned
int
xics_default_distrib_server
;
extern
unsigned
int
xics_interrupt_server_size
;
extern
struct
irq_
host
*
xics_host
;
extern
struct
irq_
domain
*
xics_host
;
struct
xics_cppr
{
unsigned
char
stack
[
MAX_NUM_PRIORITIES
];
...
...
arch/powerpc/kernel/irq.c
View file @
1f52299e
...
...
@@ -490,409 +490,19 @@ void do_softirq(void)
local_irq_restore
(
flags
);
}
/*
* IRQ controller and virtual interrupts
*/
/* The main irq map itself is an array of NR_IRQ entries containing the
* associate host and irq number. An entry with a host of NULL is free.
* An entry can be allocated if it's free, the allocator always then sets
* hwirq first to the host's invalid irq number and then fills ops.
*/
struct
irq_map_entry
{
irq_hw_number_t
hwirq
;
struct
irq_host
*
host
;
};
static
LIST_HEAD
(
irq_hosts
);
static
DEFINE_RAW_SPINLOCK
(
irq_big_lock
);
static
DEFINE_MUTEX
(
revmap_trees_mutex
);
static
struct
irq_map_entry
irq_map
[
NR_IRQS
];
static
unsigned
int
irq_virq_count
=
NR_IRQS
;
static
struct
irq_host
*
irq_default_host
;
irq_hw_number_t
irqd_to_hwirq
(
struct
irq_data
*
d
)
{
return
irq_map
[
d
->
irq
].
hwirq
;
return
d
->
hwirq
;
}
EXPORT_SYMBOL_GPL
(
irqd_to_hwirq
);
irq_hw_number_t
virq_to_hw
(
unsigned
int
virq
)
{
return
irq_map
[
virq
].
hwirq
;
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
return
WARN_ON
(
!
irq_data
)
?
0
:
irq_data
->
hwirq
;
}
EXPORT_SYMBOL_GPL
(
virq_to_hw
);
bool
virq_is_host
(
unsigned
int
virq
,
struct
irq_host
*
host
)
{
return
irq_map
[
virq
].
host
==
host
;
}
EXPORT_SYMBOL_GPL
(
virq_is_host
);
static
int
default_irq_host_match
(
struct
irq_host
*
h
,
struct
device_node
*
np
)
{
return
h
->
of_node
!=
NULL
&&
h
->
of_node
==
np
;
}
struct
irq_host
*
irq_alloc_host
(
struct
device_node
*
of_node
,
unsigned
int
revmap_type
,
unsigned
int
revmap_arg
,
struct
irq_host_ops
*
ops
,
irq_hw_number_t
inval_irq
)
{
struct
irq_host
*
host
;
unsigned
int
size
=
sizeof
(
struct
irq_host
);
unsigned
int
i
;
unsigned
int
*
rmap
;
unsigned
long
flags
;
/* Allocate structure and revmap table if using linear mapping */
if
(
revmap_type
==
IRQ_HOST_MAP_LINEAR
)
size
+=
revmap_arg
*
sizeof
(
unsigned
int
);
host
=
kzalloc
(
size
,
GFP_KERNEL
);
if
(
host
==
NULL
)
return
NULL
;
/* Fill structure */
host
->
revmap_type
=
revmap_type
;
host
->
inval_irq
=
inval_irq
;
host
->
ops
=
ops
;
host
->
of_node
=
of_node_get
(
of_node
);
if
(
host
->
ops
->
match
==
NULL
)
host
->
ops
->
match
=
default_irq_host_match
;
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
/* If it's a legacy controller, check for duplicates and
* mark it as allocated (we use irq 0 host pointer for that
*/
if
(
revmap_type
==
IRQ_HOST_MAP_LEGACY
)
{
if
(
irq_map
[
0
].
host
!=
NULL
)
{
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
of_node_put
(
host
->
of_node
);
kfree
(
host
);
return
NULL
;
}
irq_map
[
0
].
host
=
host
;
}
list_add
(
&
host
->
link
,
&
irq_hosts
);
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
/* Additional setups per revmap type */
switch
(
revmap_type
)
{
case
IRQ_HOST_MAP_LEGACY
:
/* 0 is always the invalid number for legacy */
host
->
inval_irq
=
0
;
/* setup us as the host for all legacy interrupts */
for
(
i
=
1
;
i
<
NUM_ISA_INTERRUPTS
;
i
++
)
{
irq_map
[
i
].
hwirq
=
i
;
smp_wmb
();
irq_map
[
i
].
host
=
host
;
smp_wmb
();
/* Legacy flags are left to default at this point,
* one can then use irq_create_mapping() to
* explicitly change them
*/
ops
->
map
(
host
,
i
,
i
);
/* Clear norequest flags */
irq_clear_status_flags
(
i
,
IRQ_NOREQUEST
);
}
break
;
case
IRQ_HOST_MAP_LINEAR
:
rmap
=
(
unsigned
int
*
)(
host
+
1
);
for
(
i
=
0
;
i
<
revmap_arg
;
i
++
)
rmap
[
i
]
=
NO_IRQ
;
host
->
revmap_data
.
linear
.
size
=
revmap_arg
;
smp_wmb
();
host
->
revmap_data
.
linear
.
revmap
=
rmap
;
break
;
case
IRQ_HOST_MAP_TREE
:
INIT_RADIX_TREE
(
&
host
->
revmap_data
.
tree
,
GFP_KERNEL
);
break
;
default:
break
;
}
pr_debug
(
"irq: Allocated host of type %d @0x%p
\n
"
,
revmap_type
,
host
);
return
host
;
}
struct
irq_host
*
irq_find_host
(
struct
device_node
*
node
)
{
struct
irq_host
*
h
,
*
found
=
NULL
;
unsigned
long
flags
;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*/
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
list_for_each_entry
(
h
,
&
irq_hosts
,
link
)
if
(
h
->
ops
->
match
(
h
,
node
))
{
found
=
h
;
break
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
found
;
}
EXPORT_SYMBOL_GPL
(
irq_find_host
);
void
irq_set_default_host
(
struct
irq_host
*
host
)
{
pr_debug
(
"irq: Default host set to @0x%p
\n
"
,
host
);
irq_default_host
=
host
;
}
void
irq_set_virq_count
(
unsigned
int
count
)
{
pr_debug
(
"irq: Trying to set virq count to %d
\n
"
,
count
);
BUG_ON
(
count
<
NUM_ISA_INTERRUPTS
);
if
(
count
<
NR_IRQS
)
irq_virq_count
=
count
;
}
static
int
irq_setup_virq
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
int
res
;
res
=
irq_alloc_desc_at
(
virq
,
0
);
if
(
res
!=
virq
)
{
pr_debug
(
"irq: -> allocating desc failed
\n
"
);
goto
error
;
}
/* map it */
smp_wmb
();
irq_map
[
virq
].
hwirq
=
hwirq
;
smp_mb
();
if
(
host
->
ops
->
map
(
host
,
virq
,
hwirq
))
{
pr_debug
(
"irq: -> mapping failed, freeing
\n
"
);
goto
errdesc
;
}
irq_clear_status_flags
(
virq
,
IRQ_NOREQUEST
);
return
0
;
errdesc:
irq_free_descs
(
virq
,
1
);
error:
irq_free_virt
(
virq
,
1
);
return
-
1
;
}
unsigned
int
irq_create_direct_mapping
(
struct
irq_host
*
host
)
{
unsigned
int
virq
;
if
(
host
==
NULL
)
host
=
irq_default_host
;
BUG_ON
(
host
==
NULL
);
WARN_ON
(
host
->
revmap_type
!=
IRQ_HOST_MAP_NOMAP
);
virq
=
irq_alloc_virt
(
host
,
1
,
0
);
if
(
virq
==
NO_IRQ
)
{
pr_debug
(
"irq: create_direct virq allocation failed
\n
"
);
return
NO_IRQ
;
}
pr_debug
(
"irq: create_direct obtained virq %d
\n
"
,
virq
);
if
(
irq_setup_virq
(
host
,
virq
,
virq
))
return
NO_IRQ
;
return
virq
;
}
unsigned
int
irq_create_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
virq
,
hint
;
pr_debug
(
"irq: irq_create_mapping(0x%p, 0x%lx)
\n
"
,
host
,
hwirq
);
/* Look for default host if nececssary */
if
(
host
==
NULL
)
host
=
irq_default_host
;
if
(
host
==
NULL
)
{
printk
(
KERN_WARNING
"irq_create_mapping called for"
" NULL host, hwirq=%lx
\n
"
,
hwirq
);
WARN_ON
(
1
);
return
NO_IRQ
;
}
pr_debug
(
"irq: -> using host @%p
\n
"
,
host
);
/* Check if mapping already exists */
virq
=
irq_find_mapping
(
host
,
hwirq
);
if
(
virq
!=
NO_IRQ
)
{
pr_debug
(
"irq: -> existing mapping on virq %d
\n
"
,
virq
);
return
virq
;
}
/* Get a virtual interrupt number */
if
(
host
->
revmap_type
==
IRQ_HOST_MAP_LEGACY
)
{
/* Handle legacy */
virq
=
(
unsigned
int
)
hwirq
;
if
(
virq
==
0
||
virq
>=
NUM_ISA_INTERRUPTS
)
return
NO_IRQ
;
return
virq
;
}
else
{
/* Allocate a virtual interrupt number */
hint
=
hwirq
%
irq_virq_count
;
virq
=
irq_alloc_virt
(
host
,
1
,
hint
);
if
(
virq
==
NO_IRQ
)
{
pr_debug
(
"irq: -> virq allocation failed
\n
"
);
return
NO_IRQ
;
}
}
if
(
irq_setup_virq
(
host
,
virq
,
hwirq
))
return
NO_IRQ
;
pr_debug
(
"irq: irq %lu on host %s mapped to virtual irq %u
\n
"
,
hwirq
,
host
->
of_node
?
host
->
of_node
->
full_name
:
"null"
,
virq
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_mapping
);
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
struct
irq_host
*
host
;
irq_hw_number_t
hwirq
;
unsigned
int
type
=
IRQ_TYPE_NONE
;
unsigned
int
virq
;
if
(
controller
==
NULL
)
host
=
irq_default_host
;
else
host
=
irq_find_host
(
controller
);
if
(
host
==
NULL
)
{
printk
(
KERN_WARNING
"irq: no irq host found for %s !
\n
"
,
controller
->
full_name
);
return
NO_IRQ
;
}
/* If host has no translation, then we assume interrupt line */
if
(
host
->
ops
->
xlate
==
NULL
)
hwirq
=
intspec
[
0
];
else
{
if
(
host
->
ops
->
xlate
(
host
,
controller
,
intspec
,
intsize
,
&
hwirq
,
&
type
))
return
NO_IRQ
;
}
/* Create mapping */
virq
=
irq_create_mapping
(
host
,
hwirq
);
if
(
virq
==
NO_IRQ
)
return
virq
;
/* Set type if specified and different than the current one */
if
(
type
!=
IRQ_TYPE_NONE
&&
type
!=
(
irqd_get_trigger_type
(
irq_get_irq_data
(
virq
))))
irq_set_irq_type
(
virq
,
type
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
struct
irq_host
*
host
;
irq_hw_number_t
hwirq
;
if
(
virq
==
NO_IRQ
)
return
;
host
=
irq_map
[
virq
].
host
;
if
(
WARN_ON
(
host
==
NULL
))
return
;
/* Never unmap legacy interrupts */
if
(
host
->
revmap_type
==
IRQ_HOST_MAP_LEGACY
)
return
;
irq_set_status_flags
(
virq
,
IRQ_NOREQUEST
);
/* remove chip and handler */
irq_set_chip_and_handler
(
virq
,
NULL
,
NULL
);
/* Make sure it's completed */
synchronize_irq
(
virq
);
/* Tell the PIC about it */
if
(
host
->
ops
->
unmap
)
host
->
ops
->
unmap
(
host
,
virq
);
smp_mb
();
/* Clear reverse map */
hwirq
=
irq_map
[
virq
].
hwirq
;
switch
(
host
->
revmap_type
)
{
case
IRQ_HOST_MAP_LINEAR
:
if
(
hwirq
<
host
->
revmap_data
.
linear
.
size
)
host
->
revmap_data
.
linear
.
revmap
[
hwirq
]
=
NO_IRQ
;
break
;
case
IRQ_HOST_MAP_TREE
:
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_delete
(
&
host
->
revmap_data
.
tree
,
hwirq
);
mutex_unlock
(
&
revmap_trees_mutex
);
break
;
}
/* Destroy map */
smp_mb
();
irq_map
[
virq
].
hwirq
=
host
->
inval_irq
;
irq_free_descs
(
virq
,
1
);
/* Free it */
irq_free_virt
(
virq
,
1
);
}
EXPORT_SYMBOL_GPL
(
irq_dispose_mapping
);
unsigned
int
irq_find_mapping
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
i
;
unsigned
int
hint
=
hwirq
%
irq_virq_count
;
/* Look for default host if nececssary */
if
(
host
==
NULL
)
host
=
irq_default_host
;
if
(
host
==
NULL
)
return
NO_IRQ
;
/* legacy -> bail early */
if
(
host
->
revmap_type
==
IRQ_HOST_MAP_LEGACY
)
return
hwirq
;
/* Slow path does a linear search of the map */
if
(
hint
<
NUM_ISA_INTERRUPTS
)
hint
=
NUM_ISA_INTERRUPTS
;
i
=
hint
;
do
{
if
(
irq_map
[
i
].
host
==
host
&&
irq_map
[
i
].
hwirq
==
hwirq
)
return
i
;
i
++
;
if
(
i
>=
irq_virq_count
)
i
=
NUM_ISA_INTERRUPTS
;
}
while
(
i
!=
hint
);
return
NO_IRQ
;
}
EXPORT_SYMBOL_GPL
(
irq_find_mapping
);
#ifdef CONFIG_SMP
int
irq_choose_cpu
(
const
struct
cpumask
*
mask
)
{
...
...
@@ -929,232 +539,11 @@ int irq_choose_cpu(const struct cpumask *mask)
}
#endif
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
struct
irq_map_entry
*
ptr
;
unsigned
int
virq
;
if
(
WARN_ON_ONCE
(
host
->
revmap_type
!=
IRQ_HOST_MAP_TREE
))
return
irq_find_mapping
(
host
,
hwirq
);
/*
* The ptr returned references the static global irq_map.
* but freeing an irq can delete nodes along the path to
* do the lookup via call_rcu.
*/
rcu_read_lock
();
ptr
=
radix_tree_lookup
(
&
host
->
revmap_data
.
tree
,
hwirq
);
rcu_read_unlock
();
/*
* If found in radix tree, then fine.
* Else fallback to linear lookup - this should not happen in practice
* as it means that we failed to insert the node in the radix tree.
*/
if
(
ptr
)
virq
=
ptr
-
irq_map
;
else
virq
=
irq_find_mapping
(
host
,
hwirq
);
return
virq
;
}
void
irq_radix_revmap_insert
(
struct
irq_host
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
if
(
WARN_ON
(
host
->
revmap_type
!=
IRQ_HOST_MAP_TREE
))
return
;
if
(
virq
!=
NO_IRQ
)
{
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_insert
(
&
host
->
revmap_data
.
tree
,
hwirq
,
&
irq_map
[
virq
]);
mutex_unlock
(
&
revmap_trees_mutex
);
}
}
unsigned
int
irq_linear_revmap
(
struct
irq_host
*
host
,
irq_hw_number_t
hwirq
)
{
unsigned
int
*
revmap
;
if
(
WARN_ON_ONCE
(
host
->
revmap_type
!=
IRQ_HOST_MAP_LINEAR
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Check revmap bounds */
if
(
unlikely
(
hwirq
>=
host
->
revmap_data
.
linear
.
size
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Check if revmap was allocated */
revmap
=
host
->
revmap_data
.
linear
.
revmap
;
if
(
unlikely
(
revmap
==
NULL
))
return
irq_find_mapping
(
host
,
hwirq
);
/* Fill up revmap with slow path if no mapping found */
if
(
unlikely
(
revmap
[
hwirq
]
==
NO_IRQ
))
revmap
[
hwirq
]
=
irq_find_mapping
(
host
,
hwirq
);
return
revmap
[
hwirq
];
}
unsigned
int
irq_alloc_virt
(
struct
irq_host
*
host
,
unsigned
int
count
,
unsigned
int
hint
)
{
unsigned
long
flags
;
unsigned
int
i
,
j
,
found
=
NO_IRQ
;
if
(
count
==
0
||
count
>
(
irq_virq_count
-
NUM_ISA_INTERRUPTS
))
return
NO_IRQ
;
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
/* Use hint for 1 interrupt if any */
if
(
count
==
1
&&
hint
>=
NUM_ISA_INTERRUPTS
&&
hint
<
irq_virq_count
&&
irq_map
[
hint
].
host
==
NULL
)
{
found
=
hint
;
goto
hint_found
;
}
/* Look for count consecutive numbers in the allocatable
* (non-legacy) space
*/
for
(
i
=
NUM_ISA_INTERRUPTS
,
j
=
0
;
i
<
irq_virq_count
;
i
++
)
{
if
(
irq_map
[
i
].
host
!=
NULL
)
j
=
0
;
else
j
++
;
if
(
j
==
count
)
{
found
=
i
-
count
+
1
;
break
;
}
}
if
(
found
==
NO_IRQ
)
{
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
NO_IRQ
;
}
hint_found:
for
(
i
=
found
;
i
<
(
found
+
count
);
i
++
)
{
irq_map
[
i
].
hwirq
=
host
->
inval_irq
;
smp_wmb
();
irq_map
[
i
].
host
=
host
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
return
found
;
}
void
irq_free_virt
(
unsigned
int
virq
,
unsigned
int
count
)
{
unsigned
long
flags
;
unsigned
int
i
;
WARN_ON
(
virq
<
NUM_ISA_INTERRUPTS
);
WARN_ON
(
count
==
0
||
(
virq
+
count
)
>
irq_virq_count
);
if
(
virq
<
NUM_ISA_INTERRUPTS
)
{
if
(
virq
+
count
<
NUM_ISA_INTERRUPTS
)
return
;
count
=-
NUM_ISA_INTERRUPTS
-
virq
;
virq
=
NUM_ISA_INTERRUPTS
;
}
if
(
count
>
irq_virq_count
||
virq
>
irq_virq_count
-
count
)
{
if
(
virq
>
irq_virq_count
)
return
;
count
=
irq_virq_count
-
virq
;
}
raw_spin_lock_irqsave
(
&
irq_big_lock
,
flags
);
for
(
i
=
virq
;
i
<
(
virq
+
count
);
i
++
)
{
struct
irq_host
*
host
;
host
=
irq_map
[
i
].
host
;
irq_map
[
i
].
hwirq
=
host
->
inval_irq
;
smp_wmb
();
irq_map
[
i
].
host
=
NULL
;
}
raw_spin_unlock_irqrestore
(
&
irq_big_lock
,
flags
);
}
int
arch_early_irq_init
(
void
)
{
return
0
;
}
#ifdef CONFIG_VIRQ_DEBUG
static
int
virq_debug_show
(
struct
seq_file
*
m
,
void
*
private
)
{
unsigned
long
flags
;
struct
irq_desc
*
desc
;
const
char
*
p
;
static
const
char
none
[]
=
"none"
;
void
*
data
;
int
i
;
seq_printf
(
m
,
"%-5s %-7s %-15s %-18s %s
\n
"
,
"virq"
,
"hwirq"
,
"chip name"
,
"chip data"
,
"host name"
);
for
(
i
=
1
;
i
<
nr_irqs
;
i
++
)
{
desc
=
irq_to_desc
(
i
);
if
(
!
desc
)
continue
;
raw_spin_lock_irqsave
(
&
desc
->
lock
,
flags
);
if
(
desc
->
action
&&
desc
->
action
->
handler
)
{
struct
irq_chip
*
chip
;
seq_printf
(
m
,
"%5d "
,
i
);
seq_printf
(
m
,
"0x%05lx "
,
irq_map
[
i
].
hwirq
);
chip
=
irq_desc_get_chip
(
desc
);
if
(
chip
&&
chip
->
name
)
p
=
chip
->
name
;
else
p
=
none
;
seq_printf
(
m
,
"%-15s "
,
p
);
data
=
irq_desc_get_chip_data
(
desc
);
seq_printf
(
m
,
"0x%16p "
,
data
);
if
(
irq_map
[
i
].
host
&&
irq_map
[
i
].
host
->
of_node
)
p
=
irq_map
[
i
].
host
->
of_node
->
full_name
;
else
p
=
none
;
seq_printf
(
m
,
"%s
\n
"
,
p
);
}
raw_spin_unlock_irqrestore
(
&
desc
->
lock
,
flags
);
}
return
0
;
}
static
int
virq_debug_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
virq_debug_show
,
inode
->
i_private
);
}
static
const
struct
file_operations
virq_debug_fops
=
{
.
open
=
virq_debug_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
__init
irq_debugfs_init
(
void
)
{
if
(
debugfs_create_file
(
"virq_mapping"
,
S_IRUGO
,
powerpc_debugfs_root
,
NULL
,
&
virq_debug_fops
)
==
NULL
)
return
-
ENOMEM
;
return
0
;
}
__initcall
(
irq_debugfs_init
);
#endif
/* CONFIG_VIRQ_DEBUG */
#ifdef CONFIG_PPC64
static
int
__init
setup_noirqdistrib
(
char
*
str
)
{
...
...
arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
View file @
1f52299e
...
...
@@ -21,7 +21,7 @@
#include <asm/prom.h>
static
struct
device_node
*
cpld_pic_node
;
static
struct
irq_
host
*
cpld_pic_host
;
static
struct
irq_
domain
*
cpld_pic_host
;
/*
* Bits to ignore in the misc_status register
...
...
@@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
}
static
int
cpld_pic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
cpld_pic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
return
cpld_pic_node
==
node
;
}
static
int
cpld_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
cpld_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_status_flags
(
virq
,
IRQ_LEVEL
);
...
...
@@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host_ops
cpld_pic_host_ops
=
{
static
const
struct
irq_domain_ops
cpld_pic_host_ops
=
{
.
match
=
cpld_pic_host_match
,
.
map
=
cpld_pic_host_map
,
};
...
...
@@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void)
cpld_pic_node
=
of_node_get
(
np
);
cpld_pic_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
16
,
&
cpld_pic_host_ops
,
16
);
cpld_pic_host
=
irq_domain_add_linear
(
np
,
16
,
&
cpld_pic_host_ops
,
NULL
);
if
(
!
cpld_pic_host
)
{
printk
(
KERN_ERR
"CPLD PIC: failed to allocate irq host!
\n
"
);
goto
end
;
...
...
arch/powerpc/platforms/52xx/media5200.c
View file @
1f52299e
...
...
@@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = {
struct
media5200_irq
{
void
__iomem
*
regs
;
spinlock_t
lock
;
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
};
struct
media5200_irq
media5200_irq
;
...
...
@@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
raw_spin_unlock
(
&
desc
->
lock
);
}
static
int
media5200_irq_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
media5200_irq_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
pr_debug
(
"%s: h=%p, virq=%i, hwirq=%i
\n
"
,
__func__
,
h
,
virq
,
(
int
)
hw
);
...
...
@@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
media5200_irq_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
media5200_irq_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
media5200_irq_ops
=
{
static
const
struct
irq_domain
_ops
media5200_irq_ops
=
{
.
map
=
media5200_irq_map
,
.
xlate
=
media5200_irq_xlate
,
};
...
...
@@ -173,15 +173,12 @@ static void __init media5200_init_irq(void)
spin_lock_init
(
&
media5200_irq
.
lock
);
media5200_irq
.
irqhost
=
irq_alloc_host
(
fpga_np
,
IRQ_HOST_MAP_LINEAR
,
MEDIA5200_NUM_IRQS
,
&
media5200_irq_ops
,
-
1
);
media5200_irq
.
irqhost
=
irq_domain_add_linear
(
fpga_np
,
MEDIA5200_NUM_IRQS
,
&
media5200_irq_ops
,
&
media5200_irq
);
if
(
!
media5200_irq
.
irqhost
)
goto
out
;
pr_debug
(
"%s: allocated irqhost
\n
"
,
__func__
);
media5200_irq
.
irqhost
->
host_data
=
&
media5200_irq
;
irq_set_handler_data
(
cascade_virq
,
&
media5200_irq
);
irq_set_chained_handler
(
cascade_virq
,
media5200_irq_cascade
);
...
...
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
View file @
1f52299e
...
...
@@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");
* @regs: virtual address of GPT registers
* @lock: spinlock to coordinate between different functions.
* @gc: gpio_chip instance structure; used when GPIO is enabled
* @irqhost: Pointer to irq_
host
instance; used when IRQ mode is supported
* @irqhost: Pointer to irq_
domain
instance; used when IRQ mode is supported
* @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates
* if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates
* if the timer is actively used as wdt which blocks gpt functions
...
...
@@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {
struct
device
*
dev
;
struct
mpc52xx_gpt
__iomem
*
regs
;
spinlock_t
lock
;
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
u32
ipb_freq
;
u8
wdt_mode
;
...
...
@@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
}
}
static
int
mpc52xx_gpt_irq_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mpc52xx_gpt_irq_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
mpc52xx_gpt_priv
*
gpt
=
h
->
host_data
;
...
...
@@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
mpc52xx_gpt_irq_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
mpc52xx_gpt_irq_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
mpc52xx_gpt_irq_ops
=
{
static
const
struct
irq_domain
_ops
mpc52xx_gpt_irq_ops
=
{
.
map
=
mpc52xx_gpt_irq_map
,
.
xlate
=
mpc52xx_gpt_irq_xlate
,
};
...
...
@@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
if
(
!
cascade_virq
)
return
;
gpt
->
irqhost
=
irq_alloc_host
(
node
,
IRQ_HOST_MAP_LINEAR
,
1
,
&
mpc52xx_gpt_irq_ops
,
-
1
);
gpt
->
irqhost
=
irq_domain_add_linear
(
node
,
1
,
&
mpc52xx_gpt_irq_ops
,
gpt
);
if
(
!
gpt
->
irqhost
)
{
dev_err
(
gpt
->
dev
,
"irq_
alloc_host
() failed
\n
"
);
dev_err
(
gpt
->
dev
,
"irq_
domain_add_linear
() failed
\n
"
);
return
;
}
gpt
->
irqhost
->
host_data
=
gpt
;
irq_set_handler_data
(
cascade_virq
,
gpt
);
irq_set_chained_handler
(
cascade_virq
,
mpc52xx_gpt_irq_cascade
);
...
...
arch/powerpc/platforms/52xx/mpc52xx_pic.c
View file @
1f52299e
...
...
@@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
static
struct
mpc52xx_intr
__iomem
*
intr
;
static
struct
mpc52xx_sdma
__iomem
*
sdma
;
static
struct
irq_
host
*
mpc52xx_irqhost
=
NULL
;
static
struct
irq_
domain
*
mpc52xx_irqhost
=
NULL
;
static
unsigned
char
mpc52xx_map_senses
[
4
]
=
{
IRQ_TYPE_LEVEL_HIGH
,
...
...
@@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2)
/**
* mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
*/
static
int
mpc52xx_irqhost_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
mpc52xx_irqhost_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
/**
* mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
*/
static
int
mpc52xx_irqhost_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mpc52xx_irqhost_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
irq
)
{
int
l1irq
;
...
...
@@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host
_ops
mpc52xx_irqhost_ops
=
{
static
const
struct
irq_domain
_ops
mpc52xx_irqhost_ops
=
{
.
xlate
=
mpc52xx_irqhost_xlate
,
.
map
=
mpc52xx_irqhost_map
,
};
...
...
@@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void)
* As last step, add an irq host to translate the real
* hw irq information provided by the ofw to linux virq
*/
mpc52xx_irqhost
=
irq_
alloc_host
(
picnode
,
IRQ_HOST_MAP_LINEAR
,
mpc52xx_irqhost
=
irq_
domain_add_linear
(
picnode
,
MPC52xx_IRQ_HIGHTESTHWIRQ
,
&
mpc52xx_irqhost_ops
,
-
1
);
&
mpc52xx_irqhost_ops
,
NULL
);
if
(
!
mpc52xx_irqhost
)
panic
(
__FILE__
": Cannot allocate the IRQ host
\n
"
);
...
...
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
View file @
1f52299e
...
...
@@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock);
struct
pq2ads_pci_pic
{
struct
device_node
*
node
;
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
struct
{
u32
stat
;
...
...
@@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
}
}
static
int
pci_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
pci_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_status_flags
(
virq
,
IRQ_LEVEL
);
...
...
@@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host
_ops
pci_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
pci_pic_host_ops
=
{
.
map
=
pci_pic_host_map
,
};
int
__init
pq2ads_pci_init_irq
(
void
)
{
struct
pq2ads_pci_pic
*
priv
;
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
struct
device_node
*
np
;
int
ret
=
-
ENODEV
;
int
irq
;
...
...
@@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void)
out_be32
(
&
priv
->
regs
->
mask
,
~
0
);
mb
();
host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
NUM_IRQS
,
&
pci_pic_host_ops
,
NUM_IRQS
);
host
=
irq_domain_add_linear
(
np
,
NUM_IRQS
,
&
pci_pic_host_ops
,
priv
);
if
(
!
host
)
{
ret
=
-
ENOMEM
;
goto
out_unmap_regs
;
}
host
->
host_data
=
priv
;
priv
->
host
=
host
;
host
->
host_data
=
priv
;
irq_set_handler_data
(
irq
,
priv
);
irq_set_chained_handler
(
irq
,
pq2ads_pci_irq_demux
);
...
...
arch/powerpc/platforms/85xx/socrates_fpga_pic.c
View file @
1f52299e
...
...
@@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
static
DEFINE_RAW_SPINLOCK
(
socrates_fpga_pic_lock
);
static
void
__iomem
*
socrates_fpga_pic_iobase
;
static
struct
irq_
host
*
socrates_fpga_pic_irq_host
;
static
struct
irq_
domain
*
socrates_fpga_pic_irq_host
;
static
unsigned
int
socrates_fpga_irqs
[
3
];
static
inline
uint32_t
socrates_fpga_pic_read
(
int
reg
)
...
...
@@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = {
.
irq_set_type
=
socrates_fpga_pic_set_type
,
};
static
int
socrates_fpga_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
socrates_fpga_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
/* All interrupts are LEVEL sensitive */
...
...
@@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
socrates_fpga_pic_host_xlate
(
struct
irq_
host
*
h
,
static
int
socrates_fpga_pic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
...
...
@@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h,
return
0
;
}
static
struct
irq_host
_ops
socrates_fpga_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
socrates_fpga_pic_host_ops
=
{
.
map
=
socrates_fpga_pic_host_map
,
.
xlate
=
socrates_fpga_pic_host_xlate
,
};
...
...
@@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic)
unsigned
long
flags
;
int
i
;
/* Setup an irq_host structure */
socrates_fpga_pic_irq_host
=
irq_alloc_host
(
pic
,
IRQ_HOST_MAP_LINEAR
,
SOCRATES_FPGA_NUM_IRQS
,
&
socrates_fpga_pic_host_ops
,
SOCRATES_FPGA_NUM_IRQS
);
/* Setup an irq_domain structure */
socrates_fpga_pic_irq_host
=
irq_domain_add_linear
(
pic
,
SOCRATES_FPGA_NUM_IRQS
,
&
socrates_fpga_pic_host_ops
,
NULL
);
if
(
socrates_fpga_pic_irq_host
==
NULL
)
{
pr_err
(
"FPGA PIC: Unable to allocate host
\n
"
);
return
;
...
...
arch/powerpc/platforms/86xx/gef_pic.c
View file @
1f52299e
...
...
@@ -50,7 +50,7 @@
static
DEFINE_RAW_SPINLOCK
(
gef_pic_lock
);
static
void
__iomem
*
gef_pic_irq_reg_base
;
static
struct
irq_
host
*
gef_pic_irq_host
;
static
struct
irq_
domain
*
gef_pic_irq_host
;
static
int
gef_pic_cascade_irq
;
/*
...
...
@@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = {
/* When an interrupt is being configured, this call allows some flexibilty
* in deciding which irq_chip structure is used
*/
static
int
gef_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
gef_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
/* All interrupts are LEVEL sensitive */
...
...
@@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
gef_pic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
gef_pic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
...
...
@@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
gef_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
gef_pic_host_ops
=
{
.
map
=
gef_pic_host_map
,
.
xlate
=
gef_pic_host_xlate
,
};
...
...
@@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np)
return
;
}
/* Setup an irq_host structure */
gef_pic_irq_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
GEF_PIC_NUM_IRQS
,
&
gef_pic_host_ops
,
NO_IRQ
);
/* Setup an irq_domain structure */
gef_pic_irq_host
=
irq_domain_add_linear
(
np
,
GEF_PIC_NUM_IRQS
,
&
gef_pic_host_ops
,
NULL
);
if
(
gef_pic_irq_host
==
NULL
)
return
;
...
...
arch/powerpc/platforms/cell/axon_msi.c
View file @
1f52299e
...
...
@@ -67,7 +67,7 @@
struct
axon_msic
{
struct
irq_
host
*
irq_host
;
struct
irq_
domain
*
irq_domain
;
__le32
*
fifo_virt
;
dma_addr_t
fifo_phys
;
dcr_host_t
dcr_host
;
...
...
@@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
static
struct
axon_msic
*
find_msi_translator
(
struct
pci_dev
*
dev
)
{
struct
irq_
host
*
irq_host
;
struct
irq_
domain
*
irq_domain
;
struct
device_node
*
dn
,
*
tmp
;
const
phandle
*
ph
;
struct
axon_msic
*
msic
=
NULL
;
...
...
@@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
goto
out_error
;
}
irq_
host
=
irq_find_host
(
dn
);
if
(
!
irq_
host
)
{
dev_dbg
(
&
dev
->
dev
,
"axon_msi: no irq_
host
found for node %s
\n
"
,
irq_
domain
=
irq_find_host
(
dn
);
if
(
!
irq_
domain
)
{
dev_dbg
(
&
dev
->
dev
,
"axon_msi: no irq_
domain
found for node %s
\n
"
,
dn
->
full_name
);
goto
out_error
;
}
msic
=
irq_
host
->
host_data
;
msic
=
irq_
domain
->
host_data
;
out_error:
of_node_put
(
dn
);
...
...
@@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
BUILD_BUG_ON
(
NR_IRQS
>
65536
);
list_for_each_entry
(
entry
,
&
dev
->
msi_list
,
list
)
{
virq
=
irq_create_direct_mapping
(
msic
->
irq_
host
);
virq
=
irq_create_direct_mapping
(
msic
->
irq_
domain
);
if
(
virq
==
NO_IRQ
)
{
dev_warn
(
&
dev
->
dev
,
"axon_msi: virq allocation failed!
\n
"
);
...
...
@@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = {
.
name
=
"AXON-MSI"
,
};
static
int
msic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
msic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_chip_data
(
virq
,
h
->
host_data
);
...
...
@@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host
_ops
msic_host_ops
=
{
static
const
struct
irq_domain
_ops
msic_host_ops
=
{
.
map
=
msic_host_map
,
};
...
...
@@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device)
u32
tmp
;
pr_devel
(
"axon_msi: disabling %s
\n
"
,
msic
->
irq_
host
->
of_node
->
full_name
);
msic
->
irq_
domain
->
of_node
->
full_name
);
tmp
=
dcr_read
(
msic
->
dcr_host
,
MSIC_CTRL_REG
);
tmp
&=
~
MSIC_CTRL_ENABLE
&
~
MSIC_CTRL_IRQ_ENABLE
;
msic_dcr_write
(
msic
,
MSIC_CTRL_REG
,
tmp
);
...
...
@@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device)
}
memset
(
msic
->
fifo_virt
,
0xff
,
MSIC_FIFO_SIZE_BYTES
);
msic
->
irq_host
=
irq_alloc_host
(
dn
,
IRQ_HOST_MAP_NOMAP
,
NR_IRQS
,
&
msic_host_ops
,
0
);
if
(
!
msic
->
irq_host
)
{
printk
(
KERN_ERR
"axon_msi: couldn't allocate irq_host for %s
\n
"
,
msic
->
irq_domain
=
irq_domain_add_nomap
(
dn
,
&
msic_host_ops
,
msic
);
if
(
!
msic
->
irq_domain
)
{
printk
(
KERN_ERR
"axon_msi: couldn't allocate irq_domain for %s
\n
"
,
dn
->
full_name
);
goto
out_free_fifo
;
}
msic
->
irq_host
->
host_data
=
msic
;
irq_set_handler_data
(
virq
,
msic
);
irq_set_chained_handler
(
virq
,
axon_msi_cascade
);
pr_devel
(
"axon_msi: irq 0x%x setup for axon_msi
\n
"
,
virq
);
...
...
arch/powerpc/platforms/cell/beat_interrupt.c
View file @
1f52299e
...
...
@@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);
static
uint64_t
beatic_irq_mask_enable
[(
MAX_IRQS
+
255
)
/
64
];
static
uint64_t
beatic_irq_mask_ack
[(
MAX_IRQS
+
255
)
/
64
];
static
struct
irq_
host
*
beatic_host
;
static
struct
irq_
domain
*
beatic_host
;
/*
* In this implementation, "virq" == "IRQ plug number",
...
...
@@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = {
*
* Note that the number (virq) is already assigned at upper layer.
*/
static
void
beatic_pic_host_unmap
(
struct
irq_
host
*
h
,
unsigned
int
virq
)
static
void
beatic_pic_host_unmap
(
struct
irq_
domain
*
h
,
unsigned
int
virq
)
{
beat_destruct_irq_plug
(
virq
);
}
...
...
@@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
*
* Note that the number (virq) is already assigned at upper layer.
*/
static
int
beatic_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
beatic_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
int64_t
err
;
...
...
@@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
* Called from irq_create_of_mapping() only.
* Note: We have only 1 entry to translate.
*/
static
int
beatic_pic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
beatic_pic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
int
beatic_pic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
np
)
static
int
beatic_pic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
np
)
{
/* Match all */
return
1
;
}
static
struct
irq_host
_ops
beatic_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
beatic_pic_host_ops
=
{
.
map
=
beatic_pic_host_map
,
.
unmap
=
beatic_pic_host_unmap
,
.
xlate
=
beatic_pic_host_xlate
,
...
...
@@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void)
ppc_md
.
get_irq
=
beatic_get_irq
;
/* Allocate an irq host */
beatic_host
=
irq_alloc_host
(
NULL
,
IRQ_HOST_MAP_NOMAP
,
0
,
&
beatic_pic_host_ops
,
0
);
beatic_host
=
irq_domain_add_nomap
(
NULL
,
&
beatic_pic_host_ops
,
NULL
);
BUG_ON
(
beatic_host
==
NULL
);
irq_set_default_host
(
beatic_host
);
}
...
...
arch/powerpc/platforms/cell/interrupt.c
View file @
1f52299e
...
...
@@ -56,7 +56,7 @@ struct iic {
static
DEFINE_PER_CPU
(
struct
iic
,
cpu_iic
);
#define IIC_NODE_COUNT 2
static
struct
irq_
host
*
iic_host
;
static
struct
irq_
domain
*
iic_host
;
/* Convert between "pending" bits and hw irq number */
static
irq_hw_number_t
iic_pending_to_hwnum
(
struct
cbe_iic_pending_bits
bits
)
...
...
@@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg)
out_be64
(
&
per_cpu
(
cpu_iic
,
cpu
).
regs
->
generate
,
(
0xf
-
msg
)
<<
4
);
}
struct
irq_
host
*
iic_get_irq_host
(
int
node
)
struct
irq_
domain
*
iic_get_irq_host
(
int
node
)
{
return
iic_host
;
}
...
...
@@ -222,13 +222,13 @@ void iic_request_IPIs(void)
#endif
/* CONFIG_SMP */
static
int
iic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
iic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
return
of_device_is_compatible
(
node
,
"IBM,CBEA-Internal-Interrupt-Controller"
);
}
static
int
iic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
iic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
switch
(
hw
&
IIC_IRQ_TYPE_MASK
)
{
...
...
@@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
iic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
iic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
iic_host_ops
=
{
static
const
struct
irq_domain
_ops
iic_host_ops
=
{
.
match
=
iic_host_match
,
.
map
=
iic_host_map
,
.
xlate
=
iic_host_xlate
,
...
...
@@ -378,8 +378,8 @@ static int __init setup_iic(void)
void
__init
iic_init_IRQ
(
void
)
{
/* Setup an irq host data structure */
iic_host
=
irq_
alloc_host
(
NULL
,
IRQ_HOST_MAP_LINEAR
,
IIC_SOURCE_COUNT
,
&
iic_host_ops
,
IIC_IRQ_INVALID
);
iic_host
=
irq_
domain_add_linear
(
NULL
,
IIC_SOURCE_COUNT
,
&
iic_host_ops
,
NULL
);
BUG_ON
(
iic_host
==
NULL
);
irq_set_default_host
(
iic_host
);
...
...
arch/powerpc/platforms/cell/spider-pic.c
View file @
1f52299e
...
...
@@ -62,7 +62,7 @@ enum {
#define SPIDER_IRQ_INVALID 63
struct
spider_pic
{
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
void
__iomem
*
regs
;
unsigned
int
node_id
;
};
...
...
@@ -168,7 +168,7 @@ static struct irq_chip spider_pic = {
.
irq_set_type
=
spider_set_irq_type
,
};
static
int
spider_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
spider_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_chip_data
(
virq
,
h
->
host_data
);
...
...
@@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
spider_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
spider_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
spider_host_ops
=
{
static
const
struct
irq_domain
_ops
spider_host_ops
=
{
.
map
=
spider_host_map
,
.
xlate
=
spider_host_xlate
,
};
...
...
@@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip,
panic
(
"spider_pic: can't map registers !"
);
/* Allocate a host */
pic
->
host
=
irq_alloc_host
(
of_node
,
IRQ_HOST_MAP_LINEAR
,
SPIDER_SRC_COUNT
,
&
spider_host_ops
,
SPIDER_IRQ_INVALID
);
pic
->
host
=
irq_domain_add_linear
(
of_node
,
SPIDER_SRC_COUNT
,
&
spider_host_ops
,
pic
);
if
(
pic
->
host
==
NULL
)
panic
(
"spider_pic: can't allocate irq host !"
);
pic
->
host
->
host_data
=
pic
;
/* Go through all sources and disable them */
for
(
i
=
0
;
i
<
SPIDER_SRC_COUNT
;
i
++
)
{
...
...
arch/powerpc/platforms/embedded6xx/flipper-pic.c
View file @
1f52299e
...
...
@@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = {
*
*/
static
struct
irq_
host
*
flipper_irq_host
;
static
struct
irq_
domain
*
flipper_irq_host
;
static
int
flipper_pic_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
flipper_pic_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
irq_set_chip_data
(
virq
,
h
->
host_data
);
...
...
@@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
flipper_pic_match
(
struct
irq_
host
*
h
,
struct
device_node
*
np
)
static
int
flipper_pic_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
np
)
{
return
1
;
}
static
struct
irq_host_ops
flipper_irq_host
_ops
=
{
static
const
struct
irq_domain_ops
flipper_irq_domain
_ops
=
{
.
map
=
flipper_pic_map
,
.
match
=
flipper_pic_match
,
};
...
...
@@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base)
out_be32
(
io_base
+
FLIPPER_ICR
,
0xffffffff
);
}
struct
irq_
host
*
__init
flipper_pic_init
(
struct
device_node
*
np
)
struct
irq_
domain
*
__init
flipper_pic_init
(
struct
device_node
*
np
)
{
struct
device_node
*
pi
;
struct
irq_
host
*
irq_host
=
NULL
;
struct
irq_
domain
*
irq_domain
=
NULL
;
struct
resource
res
;
void
__iomem
*
io_base
;
int
retval
;
...
...
@@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np)
__flipper_quiesce
(
io_base
);
irq_
host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
FLIPPER_NR_IRQS
,
&
flipper_irq_
host_ops
,
-
1
);
if
(
!
irq_
host
)
{
pr_err
(
"failed to allocate irq_
host
\n
"
);
irq_
domain
=
irq_domain_add_linear
(
np
,
FLIPPER_NR_IRQS
,
&
flipper_irq_
domain_ops
,
io_base
);
if
(
!
irq_
domain
)
{
pr_err
(
"failed to allocate irq_
domain
\n
"
);
return
NULL
;
}
irq_host
->
host_data
=
io_base
;
out:
return
irq_
host
;
return
irq_
domain
;
}
unsigned
int
flipper_pic_get_irq
(
void
)
...
...
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
View file @
1f52299e
...
...
@@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = {
*
*/
static
struct
irq_
host
*
hlwd_irq_host
;
static
struct
irq_
domain
*
hlwd_irq_host
;
static
int
hlwd_pic_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
hlwd_pic_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
irq_set_chip_data
(
virq
,
h
->
host_data
);
...
...
@@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host_ops
hlwd_irq_host
_ops
=
{
static
const
struct
irq_domain_ops
hlwd_irq_domain
_ops
=
{
.
map
=
hlwd_pic_map
,
};
static
unsigned
int
__hlwd_pic_get_irq
(
struct
irq_
host
*
h
)
static
unsigned
int
__hlwd_pic_get_irq
(
struct
irq_
domain
*
h
)
{
void
__iomem
*
io_base
=
h
->
host_data
;
int
irq
;
...
...
@@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
struct
irq_desc
*
desc
)
{
struct
irq_chip
*
chip
=
irq_desc_get_chip
(
desc
);
struct
irq_
host
*
irq_host
=
irq_get_handler_data
(
cascade_virq
);
struct
irq_
domain
*
irq_domain
=
irq_get_handler_data
(
cascade_virq
);
unsigned
int
virq
;
raw_spin_lock
(
&
desc
->
lock
);
chip
->
irq_mask
(
&
desc
->
irq_data
);
/* IRQ_LEVEL */
raw_spin_unlock
(
&
desc
->
lock
);
virq
=
__hlwd_pic_get_irq
(
irq_
host
);
virq
=
__hlwd_pic_get_irq
(
irq_
domain
);
if
(
virq
!=
NO_IRQ
)
generic_handle_irq
(
virq
);
else
...
...
@@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base)
out_be32
(
io_base
+
HW_BROADWAY_ICR
,
0xffffffff
);
}
struct
irq_
host
*
hlwd_pic_init
(
struct
device_node
*
np
)
struct
irq_
domain
*
hlwd_pic_init
(
struct
device_node
*
np
)
{
struct
irq_
host
*
irq_host
;
struct
irq_
domain
*
irq_domain
;
struct
resource
res
;
void
__iomem
*
io_base
;
int
retval
;
...
...
@@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np)
__hlwd_quiesce
(
io_base
);
irq_
host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
HLWD_NR_IRQS
,
&
hlwd_irq_host_ops
,
-
1
);
if
(
!
irq_
host
)
{
pr_err
(
"failed to allocate irq_
host
\n
"
);
irq_
domain
=
irq_domain_add_linear
(
np
,
HLWD_NR_IRQS
,
&
hlwd_irq_domain_ops
,
io_base
);
if
(
!
irq_
domain
)
{
pr_err
(
"failed to allocate irq_
domain
\n
"
);
return
NULL
;
}
irq_host
->
host_data
=
io_base
;
return
irq_
host
;
return
irq_
domain
;
}
unsigned
int
hlwd_pic_get_irq
(
void
)
...
...
@@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void)
void
hlwd_pic_probe
(
void
)
{
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
struct
device_node
*
np
;
const
u32
*
interrupts
;
int
cascade_virq
;
...
...
arch/powerpc/platforms/iseries/irq.c
View file @
1f52299e
...
...
@@ -342,7 +342,7 @@ unsigned int iSeries_get_irq(void)
#ifdef CONFIG_PCI
static
int
iseries_irq_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
iseries_irq_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_chip_and_handler
(
virq
,
&
iseries_pic
,
handle_fasteoi_irq
);
...
...
@@ -350,13 +350,13 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
iseries_irq_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
np
)
static
int
iseries_irq_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
np
)
{
/* Match all */
return
1
;
}
static
struct
irq_host_ops
iseries_irq_host
_ops
=
{
static
const
struct
irq_domain_ops
iseries_irq_domain
_ops
=
{
.
map
=
iseries_irq_host_map
,
.
match
=
iseries_irq_host_match
,
};
...
...
@@ -368,7 +368,7 @@ static struct irq_host_ops iseries_irq_host_ops = {
void
__init
iSeries_init_IRQ
(
void
)
{
/* Register PCI event handler and open an event path */
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
int
ret
;
/*
...
...
@@ -380,8 +380,7 @@ void __init iSeries_init_IRQ(void)
/* Create irq host. No need for a revmap since HV will give us
* back our virtual irq number
*/
host
=
irq_alloc_host
(
NULL
,
IRQ_HOST_MAP_NOMAP
,
0
,
&
iseries_irq_host_ops
,
0
);
host
=
irq_domain_add_nomap
(
NULL
,
&
iseries_irq_domain_ops
,
NULL
);
BUG_ON
(
host
==
NULL
);
irq_set_default_host
(
host
);
...
...
arch/powerpc/platforms/powermac/pic.c
View file @
1f52299e
...
...
@@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock);
static
unsigned
long
ppc_lost_interrupts
[
NR_MASK_WORDS
];
static
unsigned
long
ppc_cached_irq_mask
[
NR_MASK_WORDS
];
static
int
pmac_irq_cascade
=
-
1
;
static
struct
irq_
host
*
pmac_pic_host
;
static
struct
irq_
domain
*
pmac_pic_host
;
static
void
__pmac_retrigger
(
unsigned
int
irq_nr
)
{
...
...
@@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = {
.
name
=
"cascade"
,
};
static
int
pmac_pic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
pmac_pic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
/* We match all, we don't always have a node anyway */
return
1
;
}
static
int
pmac_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
pmac_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
if
(
hw
>=
max_irqs
)
...
...
@@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
pmac_pic_host_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
*
out_flags
=
IRQ_TYPE_NONE
;
*
out_hwirq
=
*
intspec
;
return
0
;
}
static
struct
irq_host_ops
pmac_pic_host_ops
=
{
static
const
struct
irq_domain_ops
pmac_pic_host_ops
=
{
.
match
=
pmac_pic_host_match
,
.
map
=
pmac_pic_host_map
,
.
xlate
=
pmac_pic_host_xlate
,
.
xlate
=
irq_domain_xlate_onecell
,
};
static
void
__init
pmac_pic_probe_oldstyle
(
void
)
...
...
@@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void)
/*
* Allocate an irq host
*/
pmac_pic_host
=
irq_alloc_host
(
master
,
IRQ_HOST_MAP_LINEAR
,
max_irqs
,
&
pmac_pic_host_ops
,
max_irqs
);
pmac_pic_host
=
irq_domain_add_linear
(
master
,
max_irqs
,
&
pmac_pic_host_ops
,
NULL
);
BUG_ON
(
pmac_pic_host
==
NULL
);
irq_set_default_host
(
pmac_pic_host
);
...
...
arch/powerpc/platforms/powermac/smp.c
View file @
1f52299e
...
...
@@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start;
static
int
psurge_type
=
PSURGE_NONE
;
/* irq for secondary cpus to report */
static
struct
irq_
host
*
psurge_host
;
static
struct
irq_
domain
*
psurge_host
;
int
psurge_secondary_virq
;
/*
...
...
@@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data)
psurge_set_ipi
(
cpu
);
}
static
int
psurge_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
psurge_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
irq_set_chip_and_handler
(
virq
,
&
dummy_irq_chip
,
handle_percpu_irq
);
...
...
@@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
st
ruct
irq_host
_ops
psurge_host_ops
=
{
st
atic
const
struct
irq_domain
_ops
psurge_host_ops
=
{
.
map
=
psurge_host_map
,
};
...
...
@@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void)
{
int
rc
=
-
ENOMEM
;
psurge_host
=
irq_alloc_host
(
NULL
,
IRQ_HOST_MAP_NOMAP
,
0
,
&
psurge_host_ops
,
0
);
psurge_host
=
irq_domain_add_nomap
(
NULL
,
&
psurge_host_ops
,
NULL
);
if
(
psurge_host
)
psurge_secondary_virq
=
irq_create_direct_mapping
(
psurge_host
);
...
...
arch/powerpc/platforms/ps3/interrupt.c
View file @
1f52299e
...
...
@@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
static
void
dump_bmp
(
struct
ps3_private
*
pd
)
{};
#endif
/* defined(DEBUG) */
static
int
ps3_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
ps3_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
DBG
(
"%s:%d: hwirq %lu, virq %u
\n
"
,
__func__
,
__LINE__
,
hwirq
,
...
...
@@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
ps3_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
np
)
static
int
ps3_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
np
)
{
/* Match all */
return
1
;
}
static
struct
irq_host
_ops
ps3_host_ops
=
{
static
const
struct
irq_domain
_ops
ps3_host_ops
=
{
.
map
=
ps3_host_map
,
.
match
=
ps3_host_match
,
};
...
...
@@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void)
{
int
result
;
unsigned
cpu
;
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
host
=
irq_alloc_host
(
NULL
,
IRQ_HOST_MAP_NOMAP
,
0
,
&
ps3_host_ops
,
PS3_INVALID_OUTLET
);
host
=
irq_domain_add_nomap
(
NULL
,
&
ps3_host_ops
,
NULL
);
irq_set_default_host
(
host
);
irq_set_virq_count
(
PS3_PLUG_MAX
+
1
);
...
...
arch/powerpc/platforms/wsp/opb_pic.c
View file @
1f52299e
...
...
@@ -30,7 +30,7 @@
static
int
opb_index
=
0
;
struct
opb_pic
{
struct
irq_
host
*
host
;
struct
irq_
domain
*
host
;
void
*
regs
;
int
index
;
spinlock_t
lock
;
...
...
@@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = {
.
irq_set_type
=
opb_set_irq_type
};
static
int
opb_host_map
(
struct
irq_
host
*
host
,
unsigned
int
virq
,
static
int
opb_host_map
(
struct
irq_
domain
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
struct
opb_pic
*
opb
;
...
...
@@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq,
return
0
;
}
static
int
opb_host_xlate
(
struct
irq_host
*
host
,
struct
device_node
*
dn
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
)
{
/* Interrupt size must == 2 */
BUG_ON
(
intsize
!=
2
);
*
out_hwirq
=
intspec
[
0
];
*
out_type
=
intspec
[
1
];
return
0
;
}
static
struct
irq_host_ops
opb_host_ops
=
{
static
const
struct
irq_domain_ops
opb_host_ops
=
{
.
map
=
opb_host_map
,
.
xlate
=
opb_host_xlate
,
.
xlate
=
irq_domain_xlate_twocell
,
};
irqreturn_t
opb_irq_handler
(
int
irq
,
void
*
private
)
...
...
@@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
goto
free_opb
;
}
/* Allocate an irq
host
so that Linux knows that despite only
/* Allocate an irq
domain
so that Linux knows that despite only
* having one interrupt to issue, we're the controller for multiple
* hardware IRQs, so later we can lookup their virtual IRQs. */
opb
->
host
=
irq_alloc_host
(
dn
,
IRQ_HOST_MAP_LINEAR
,
OPB_NR_IRQS
,
&
opb_host_ops
,
-
1
);
opb
->
host
=
irq_domain_add_linear
(
dn
,
OPB_NR_IRQS
,
&
opb_host_ops
,
opb
);
if
(
!
opb
->
host
)
{
printk
(
KERN_ERR
"opb: Failed to allocate IRQ host!
\n
"
);
goto
free_regs
;
...
...
@@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)
opb
->
index
=
opb_index
++
;
spin_lock_init
(
&
opb
->
lock
);
opb
->
host
->
host_data
=
opb
;
/* Disable all interrupts by default */
opb_out
(
opb
,
OPB_MLSASIER
,
0
);
...
...
arch/powerpc/sysdev/cpm1.c
View file @
1f52299e
...
...
@@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
immap_t
__iomem
*
mpc8xx_immr
;
static
cpic8xx_t
__iomem
*
cpic_reg
;
static
struct
irq_
host
*
cpm_pic_host
;
static
struct
irq_
domain
*
cpm_pic_host
;
static
void
cpm_mask_irq
(
struct
irq_data
*
d
)
{
...
...
@@ -98,7 +98,7 @@ int cpm_get_irq(void)
return
irq_linear_revmap
(
cpm_pic_host
,
cpm_vec
);
}
static
int
cpm_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
cpm_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
pr_debug
(
"cpm_pic_host_map(%d, 0x%lx)
\n
"
,
virq
,
hw
);
...
...
@@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = {
.
name
=
"error"
,
};
static
struct
irq_host
_ops
cpm_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
cpm_pic_host_ops
=
{
.
map
=
cpm_pic_host_map
,
};
...
...
@@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void)
out_be32
(
&
cpic_reg
->
cpic_cimr
,
0
);
cpm_pic_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
64
,
&
cpm_pic_host_ops
,
64
);
cpm_pic_host
=
irq_domain_add_linear
(
np
,
64
,
&
cpm_pic_host_ops
,
NULL
);
if
(
cpm_pic_host
==
NULL
)
{
printk
(
KERN_ERR
"CPM2 PIC: failed to allocate irq host!
\n
"
);
sirq
=
NO_IRQ
;
...
...
arch/powerpc/sysdev/cpm2_pic.c
View file @
1f52299e
...
...
@@ -50,7 +50,7 @@
static
intctl_cpm2_t
__iomem
*
cpm2_intctl
;
static
struct
irq_
host
*
cpm2_pic_host
;
static
struct
irq_
domain
*
cpm2_pic_host
;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static
unsigned
long
ppc_cached_irq_mask
[
NR_MASK_WORDS
];
...
...
@@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void)
return
irq_linear_revmap
(
cpm2_pic_host
,
irq
);
}
static
int
cpm2_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
cpm2_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
pr_debug
(
"cpm2_pic_host_map(%d, 0x%lx)
\n
"
,
virq
,
hw
);
...
...
@@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
cpm2_pic_host_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
*
out_hwirq
=
intspec
[
0
];
if
(
intsize
>
1
)
*
out_flags
=
intspec
[
1
];
else
*
out_flags
=
IRQ_TYPE_NONE
;
return
0
;
}
static
struct
irq_host_ops
cpm2_pic_host_ops
=
{
static
const
struct
irq_domain_ops
cpm2_pic_host_ops
=
{
.
map
=
cpm2_pic_host_map
,
.
xlate
=
cpm2_pic_host_xlate
,
.
xlate
=
irq_domain_xlate_onetwocell
,
};
void
cpm2_pic_init
(
struct
device_node
*
node
)
...
...
@@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node)
out_be32
(
&
cpm2_intctl
->
ic_scprrl
,
0x05309770
);
/* create a legacy host */
cpm2_pic_host
=
irq_alloc_host
(
node
,
IRQ_HOST_MAP_LINEAR
,
64
,
&
cpm2_pic_host_ops
,
64
);
cpm2_pic_host
=
irq_domain_add_linear
(
node
,
64
,
&
cpm2_pic_host_ops
,
NULL
);
if
(
cpm2_pic_host
==
NULL
)
{
printk
(
KERN_ERR
"CPM2 PIC: failed to allocate irq host!
\n
"
);
return
;
...
...
arch/powerpc/sysdev/ehv_pic.c
View file @
1f52299e
...
...
@@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void)
return
irq_linear_revmap
(
global_ehv_pic
->
irqhost
,
irq
);
}
static
int
ehv_pic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
ehv_pic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
/* Exact match, unless ehv_pic node is NULL */
return
h
->
of_node
==
NULL
||
h
->
of_node
==
node
;
}
static
int
ehv_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
ehv_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
ehv_pic
*
ehv_pic
=
h
->
host_data
;
...
...
@@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
ehv_pic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
ehv_pic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_host
_ops
ehv_pic_host_ops
=
{
static
const
struct
irq_domain
_ops
ehv_pic_host_ops
=
{
.
match
=
ehv_pic_host_match
,
.
map
=
ehv_pic_host_map
,
.
xlate
=
ehv_pic_host_xlate
,
...
...
@@ -275,9 +275,8 @@ void __init ehv_pic_init(void)
return
;
}
ehv_pic
->
irqhost
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
NR_EHV_PIC_INTS
,
&
ehv_pic_host_ops
,
0
);
ehv_pic
->
irqhost
=
irq_domain_add_linear
(
np
,
NR_EHV_PIC_INTS
,
&
ehv_pic_host_ops
,
ehv_pic
);
if
(
!
ehv_pic
->
irqhost
)
{
of_node_put
(
np
);
kfree
(
ehv_pic
);
...
...
@@ -293,7 +292,6 @@ void __init ehv_pic_init(void)
of_node_put
(
np2
);
}
ehv_pic
->
irqhost
->
host_data
=
ehv_pic
;
ehv_pic
->
hc_irq
=
ehv_pic_irq_chip
;
ehv_pic
->
hc_irq
.
irq_set_affinity
=
ehv_pic_set_affinity
;
ehv_pic
->
coreint_flag
=
coreint_flag
;
...
...
arch/powerpc/sysdev/fsl_msi.c
View file @
1f52299e
...
...
@@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = {
.
name
=
"FSL-MSI"
,
};
static
int
fsl_msi_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
fsl_msi_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
fsl_msi
*
msi_data
=
h
->
host_data
;
...
...
@@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_host
_ops
fsl_msi_host_ops
=
{
static
const
struct
irq_domain
_ops
fsl_msi_host_ops
=
{
.
map
=
fsl_msi_host_map
,
};
...
...
@@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
}
platform_set_drvdata
(
dev
,
msi
);
msi
->
irqhost
=
irq_
alloc_host
(
dev
->
dev
.
of_node
,
IRQ_HOST_MAP_LINEAR
,
NR_MSI_IRQS
,
&
fsl_msi_host_ops
,
0
);
msi
->
irqhost
=
irq_
domain_add_linear
(
dev
->
dev
.
of_node
,
NR_MSI_IRQS
,
&
fsl_msi_host_ops
,
msi
);
if
(
msi
->
irqhost
==
NULL
)
{
dev_err
(
&
dev
->
dev
,
"No memory for MSI irqhost
\n
"
);
...
...
@@ -420,8 +420,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
msi
->
feature
=
features
->
fsl_pic_ip
;
msi
->
irqhost
->
host_data
=
msi
;
/*
* Remember the phandle, so that we can match with any PCI nodes
* that have an "fsl,msi" property.
...
...
arch/powerpc/sysdev/fsl_msi.h
View file @
1f52299e
...
...
@@ -26,7 +26,7 @@
#define FSL_PIC_IP_VMPIC 0x00000003
struct
fsl_msi
{
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
unsigned
long
cascade_irq
;
...
...
arch/powerpc/sysdev/i8259.c
View file @
1f52299e
...
...
@@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };
static
DEFINE_RAW_SPINLOCK
(
i8259_lock
);
static
struct
irq_
host
*
i8259_host
;
static
struct
irq_
domain
*
i8259_host
;
/*
* Acknowledge the IRQ using either the PCI host bridge's interrupt
...
...
@@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = {
.
flags
=
IORESOURCE_BUSY
,
};
static
int
i8259_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
i8259_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
return
h
->
of_node
==
NULL
||
h
->
of_node
==
node
;
}
static
int
i8259_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
i8259_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
pr_debug
(
"i8259_host_map(%d, 0x%lx)
\n
"
,
virq
,
hw
);
...
...
@@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
i8259_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
i8259_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
...
...
@@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_
host
_ops
i8259_host_ops
=
{
static
struct
irq_
domain
_ops
i8259_host_ops
=
{
.
match
=
i8259_host_match
,
.
map
=
i8259_host_map
,
.
xlate
=
i8259_host_xlate
,
};
struct
irq_
host
*
i8259_get_host
(
void
)
struct
irq_
domain
*
i8259_get_host
(
void
)
{
return
i8259_host
;
}
...
...
@@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
raw_spin_unlock_irqrestore
(
&
i8259_lock
,
flags
);
/* create a legacy host */
i8259_host
=
irq_alloc_host
(
node
,
IRQ_HOST_MAP_LEGACY
,
0
,
&
i8259_host_ops
,
0
);
i8259_host
=
irq_domain_add_legacy_isa
(
node
,
&
i8259_host_ops
,
NULL
);
if
(
i8259_host
==
NULL
)
{
printk
(
KERN_ERR
"i8259: failed to allocate irq host !
\n
"
);
return
;
...
...
arch/powerpc/sysdev/ipic.c
View file @
1f52299e
...
...
@@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = {
.
irq_set_type
=
ipic_set_irq_type
,
};
static
int
ipic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
ipic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
/* Exact match, unless ipic node is NULL */
return
h
->
of_node
==
NULL
||
h
->
of_node
==
node
;
}
static
int
ipic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
ipic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
ipic
*
ipic
=
h
->
host_data
;
...
...
@@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
ipic_host_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
/* interrupt sense values coming from the device tree equal either
* LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change)
*/
*
out_hwirq
=
intspec
[
0
];
if
(
intsize
>
1
)
*
out_flags
=
intspec
[
1
];
else
*
out_flags
=
IRQ_TYPE_NONE
;
return
0
;
}
static
struct
irq_host_ops
ipic_host_ops
=
{
static
struct
irq_domain_ops
ipic_host_ops
=
{
.
match
=
ipic_host_match
,
.
map
=
ipic_host_map
,
.
xlate
=
i
pic_host_xlate
,
.
xlate
=
i
rq_domain_xlate_onetwocell
,
};
struct
ipic
*
__init
ipic_init
(
struct
device_node
*
node
,
unsigned
int
flags
)
...
...
@@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
if
(
ipic
==
NULL
)
return
NULL
;
ipic
->
irqhost
=
irq_alloc_host
(
node
,
IRQ_HOST_MAP_LINEAR
,
NR_IPIC_INTS
,
&
ipic_host_ops
,
0
);
ipic
->
irqhost
=
irq_domain_add_linear
(
node
,
NR_IPIC_INTS
,
&
ipic_host_ops
,
ipic
);
if
(
ipic
->
irqhost
==
NULL
)
{
kfree
(
ipic
);
return
NULL
;
...
...
@@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
ipic
->
regs
=
ioremap
(
res
.
start
,
resource_size
(
&
res
));
ipic
->
irqhost
->
host_data
=
ipic
;
/* init hw */
ipic_write
(
ipic
->
regs
,
IPIC_SICNR
,
0x0
);
...
...
arch/powerpc/sysdev/ipic.h
View file @
1f52299e
...
...
@@ -43,7 +43,7 @@ struct ipic {
volatile
u32
__iomem
*
regs
;
/* The remapper for this IPIC */
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
};
struct
ipic_info
{
...
...
arch/powerpc/sysdev/mpc8xx_pic.c
View file @
1f52299e
...
...
@@ -17,7 +17,7 @@
extern
int
cpm_get_irq
(
struct
pt_regs
*
regs
);
static
struct
irq_
host
*
mpc8xx_pic_host
;
static
struct
irq_
domain
*
mpc8xx_pic_host
;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static
unsigned
long
ppc_cached_irq_mask
[
NR_MASK_WORDS
];
static
sysconf8xx_t
__iomem
*
siu_reg
;
...
...
@@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void)
}
static
int
mpc8xx_pic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mpc8xx_pic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
pr_debug
(
"mpc8xx_pic_host_map(%d, 0x%lx)
\n
"
,
virq
,
hw
);
...
...
@@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
}
static
int
mpc8xx_pic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
mpc8xx_pic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
...
...
@@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
}
static
struct
irq_
host
_ops
mpc8xx_pic_host_ops
=
{
static
struct
irq_
domain
_ops
mpc8xx_pic_host_ops
=
{
.
map
=
mpc8xx_pic_host_map
,
.
xlate
=
mpc8xx_pic_host_xlate
,
};
...
...
@@ -171,8 +171,7 @@ int mpc8xx_pic_init(void)
goto
out
;
}
mpc8xx_pic_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
64
,
&
mpc8xx_pic_host_ops
,
64
);
mpc8xx_pic_host
=
irq_domain_add_linear
(
np
,
64
,
&
mpc8xx_pic_host_ops
,
NULL
);
if
(
mpc8xx_pic_host
==
NULL
)
{
printk
(
KERN_ERR
"MPC8xx PIC: failed to allocate irq host!
\n
"
);
ret
=
-
ENOMEM
;
...
...
arch/powerpc/sysdev/mpic.c
View file @
1f52299e
...
...
@@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = {
#endif
/* CONFIG_MPIC_U3_HT_IRQS */
static
int
mpic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
mpic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
/* Exact match, unless mpic node is NULL */
return
h
->
of_node
==
NULL
||
h
->
of_node
==
node
;
}
static
int
mpic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mpic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
mpic
*
mpic
=
h
->
host_data
;
...
...
@@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
mpic_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
mpic_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
BUG_ON
(
!
(
mpic
->
flags
&
MPIC_SECONDARY
));
virq
=
mpic_get_one_irq
(
mpic
);
if
(
virq
!=
NO_IRQ
)
if
(
virq
)
generic_handle_irq
(
virq
);
chip
->
irq_eoi
(
&
desc
->
irq_data
);
}
static
struct
irq_
host
_ops
mpic_host_ops
=
{
static
struct
irq_
domain
_ops
mpic_host_ops
=
{
.
match
=
mpic_host_match
,
.
map
=
mpic_host_map
,
.
xlate
=
mpic_host_xlate
,
...
...
@@ -1345,10 +1345,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic
->
isu_shift
=
1
+
__ilog2
(
mpic
->
isu_size
-
1
);
mpic
->
isu_mask
=
(
1
<<
mpic
->
isu_shift
)
-
1
;
mpic
->
irqhost
=
irq_
alloc_host
(
mpic
->
node
,
IRQ_HOST_MAP_LINEAR
,
mpic
->
irqhost
=
irq_
domain_add_linear
(
mpic
->
node
,
isu_size
?
isu_size
:
mpic
->
num_sources
,
&
mpic_host_ops
,
flags
&
MPIC_LARGE_VECTORS
?
2048
:
256
);
&
mpic_host_ops
,
mpic
);
/*
* FIXME: The code leaks the MPIC object and mappings here; this
...
...
@@ -1357,8 +1356,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
if
(
mpic
->
irqhost
==
NULL
)
return
NULL
;
mpic
->
irqhost
->
host_data
=
mpic
;
/* Display version */
switch
(
greg_feature
&
MPIC_GREG_FEATURE_VERSION_MASK
)
{
case
1
:
...
...
arch/powerpc/sysdev/mpic_msi.c
View file @
1f52299e
...
...
@@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
static
int
mpic_msi_reserve_u3_hwirqs
(
struct
mpic
*
mpic
)
{
irq_hw_number_t
hwirq
;
struct
irq_host
_ops
*
ops
=
mpic
->
irqhost
->
ops
;
const
struct
irq_domain
_ops
*
ops
=
mpic
->
irqhost
->
ops
;
struct
device_node
*
np
;
int
flags
,
index
,
i
;
struct
of_irq
oirq
;
...
...
arch/powerpc/sysdev/mv64x60_pic.c
View file @
1f52299e
...
...
@@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask;
static
u32
mv64x60_cached_high_mask
=
MV64X60_HIGH_GPP_GROUPS
;
static
u32
mv64x60_cached_gpp_mask
;
static
struct
irq_
host
*
mv64x60_irq_host
;
static
struct
irq_
domain
*
mv64x60_irq_host
;
/*
* mv64x60_chip_low functions
...
...
@@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = {
[
MV64x60_LEVEL1_GPP
]
=
&
mv64x60_chip_gpp
,
};
static
int
mv64x60_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mv64x60_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
int
level1
;
...
...
@@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_
host
_ops
mv64x60_host_ops
=
{
static
struct
irq_
domain
_ops
mv64x60_host_ops
=
{
.
map
=
mv64x60_host_map
,
};
...
...
@@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void)
paddr
=
of_translate_address
(
np
,
reg
);
mv64x60_irq_reg_base
=
ioremap
(
paddr
,
reg
[
1
]);
mv64x60_irq_host
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
MV64x60_NUM_IRQS
,
&
mv64x60_host_ops
,
MV64x60_NUM_IRQS
);
mv64x60_irq_host
=
irq_domain_add_linear
(
np
,
MV64x60_NUM_IRQS
,
&
mv64x60_host_ops
,
NULL
);
spin_lock_irqsave
(
&
mv64x60_lock
,
flags
);
out_le32
(
mv64x60_gpp_reg_base
+
MV64x60_GPP_INTR_MASK
,
...
...
arch/powerpc/sysdev/qe_lib/qe_ic.c
View file @
1f52299e
...
...
@@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = {
.
irq_mask_ack
=
qe_ic_mask_irq
,
};
static
int
qe_ic_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
qe_ic_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
/* Exact match, unless qe_ic node is NULL */
return
h
->
of_node
==
NULL
||
h
->
of_node
==
node
;
}
static
int
qe_ic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
qe_ic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
qe_ic
*
qe_ic
=
h
->
host_data
;
...
...
@@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
qe_ic_host_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
*
out_hwirq
=
intspec
[
0
];
if
(
intsize
>
1
)
*
out_flags
=
intspec
[
1
];
else
*
out_flags
=
IRQ_TYPE_NONE
;
return
0
;
}
static
struct
irq_host_ops
qe_ic_host_ops
=
{
static
struct
irq_domain_ops
qe_ic_host_ops
=
{
.
match
=
qe_ic_host_match
,
.
map
=
qe_ic_host_map
,
.
xlate
=
qe_ic_host_xlate
,
.
xlate
=
irq_domain_xlate_onetwocell
,
};
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
...
...
@@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
if
(
qe_ic
==
NULL
)
return
;
qe_ic
->
irqhost
=
irq_
alloc_host
(
node
,
IRQ_HOST_MAP_LINEAR
,
NR_QE_IC_INTS
,
&
qe_ic_host_ops
,
0
);
qe_ic
->
irqhost
=
irq_
domain_add_linear
(
node
,
NR_QE_IC_INTS
,
&
qe_ic_host_ops
,
qe_ic
);
if
(
qe_ic
->
irqhost
==
NULL
)
{
kfree
(
qe_ic
);
return
;
...
...
@@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
qe_ic
->
regs
=
ioremap
(
res
.
start
,
resource_size
(
&
res
));
qe_ic
->
irqhost
->
host_data
=
qe_ic
;
qe_ic
->
hc_irq
=
qe_ic_irq_chip
;
qe_ic
->
virq_high
=
irq_of_parse_and_map
(
node
,
0
);
...
...
arch/powerpc/sysdev/qe_lib/qe_ic.h
View file @
1f52299e
...
...
@@ -79,7 +79,7 @@ struct qe_ic {
volatile
u32
__iomem
*
regs
;
/* The remapper for this QEIC */
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
/* The "linux" controller struct */
struct
irq_chip
hc_irq
;
...
...
arch/powerpc/sysdev/tsi108_pci.c
View file @
1f52299e
...
...
@@ -51,7 +51,7 @@
u32
tsi108_pci_cfg_base
;
static
u32
tsi108_pci_cfg_phys
;
u32
tsi108_csr_vir_base
;
static
struct
irq_
host
*
pci_irq_host
;
static
struct
irq_
domain
*
pci_irq_host
;
extern
u32
get_vir_csrbase
(
void
);
extern
u32
tsi108_read_reg
(
u32
reg_offset
);
...
...
@@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = {
.
irq_unmask
=
tsi108_pci_irq_unmask
,
};
static
int
pci_irq_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
pci_irq_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
...
...
@@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
int
pci_irq_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
pci_irq_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
unsigned
int
irq
;
DBG
(
"%s(%d, 0x%lx)
\n
"
,
__func__
,
virq
,
hw
);
...
...
@@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_
host_ops
pci_irq_host
_ops
=
{
static
struct
irq_
domain_ops
pci_irq_domain
_ops
=
{
.
map
=
pci_irq_host_map
,
.
xlate
=
pci_irq_host_xlate
,
};
...
...
@@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node)
{
DBG
(
"Tsi108_pci_int_init: initializing PCI interrupts
\n
"
);
pci_irq_host
=
irq_alloc_host
(
node
,
IRQ_HOST_MAP_LEGACY
,
0
,
&
pci_irq_host_ops
,
0
);
pci_irq_host
=
irq_domain_add_legacy_isa
(
node
,
&
pci_irq_domain_ops
,
NULL
);
if
(
pci_irq_host
==
NULL
)
{
printk
(
KERN_ERR
"pci_irq_host: failed to allocate irq
host
!
\n
"
);
printk
(
KERN_ERR
"pci_irq_host: failed to allocate irq
domain
!
\n
"
);
return
;
}
...
...
arch/powerpc/sysdev/uic.c
View file @
1f52299e
...
...
@@ -49,7 +49,7 @@ struct uic {
raw_spinlock_t
lock
;
/* The remapper for this UIC */
struct
irq_
host
*
irqhost
;
struct
irq_
domain
*
irqhost
;
};
static
void
uic_unmask_irq
(
struct
irq_data
*
d
)
...
...
@@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = {
.
irq_set_type
=
uic_set_irq_type
,
};
static
int
uic_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
uic_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
uic
*
uic
=
h
->
host_data
;
...
...
@@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
uic_host_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
)
{
/* UIC intspecs must have 2 cells */
BUG_ON
(
intsize
!=
2
);
*
out_hwirq
=
intspec
[
0
];
*
out_type
=
intspec
[
1
];
return
0
;
}
static
struct
irq_host_ops
uic_host_ops
=
{
static
struct
irq_domain_ops
uic_host_ops
=
{
.
map
=
uic_host_map
,
.
xlate
=
uic_host_xlate
,
.
xlate
=
irq_domain_xlate_twocell
,
};
void
uic_irq_cascade
(
unsigned
int
virq
,
struct
irq_desc
*
desc
)
...
...
@@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node)
}
uic
->
dcrbase
=
*
dcrreg
;
uic
->
irqhost
=
irq_
alloc_host
(
node
,
IRQ_HOST_MAP_LINEAR
,
NR_UIC_INTS
,
&
uic_host_ops
,
-
1
);
uic
->
irqhost
=
irq_
domain_add_linear
(
node
,
NR_UIC_INTS
,
&
uic_host_ops
,
uic
);
if
(
!
uic
->
irqhost
)
return
NULL
;
/* FIXME: panic? */
uic
->
irqhost
->
host_data
=
uic
;
/* Start with all interrupts disabled, level and non-critical */
mtdcr
(
uic
->
dcrbase
+
UIC_ER
,
0
);
mtdcr
(
uic
->
dcrbase
+
UIC_CR
,
0
);
...
...
arch/powerpc/sysdev/xics/xics-common.c
View file @
1f52299e
...
...
@@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size = 8;
DEFINE_PER_CPU
(
struct
xics_cppr
,
xics_cppr
);
struct
irq_
host
*
xics_host
;
struct
irq_
domain
*
xics_host
;
static
LIST_HEAD
(
ics_list
);
...
...
@@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void)
/* We can't set affinity on ISA interrupts */
if
(
virq
<
NUM_ISA_INTERRUPTS
)
continue
;
if
(
!
virq_is_host
(
virq
,
xics_host
))
continue
;
irq
=
(
unsigned
int
)
virq_to_hw
(
virq
);
/* We need to get IPIs still. */
if
(
irq
==
XICS_IPI
||
irq
==
XICS_IRQ_SPURIOUS
)
continue
;
desc
=
irq_to_desc
(
virq
);
/* We only need to migrate enabled IRQS */
if
(
!
desc
||
!
desc
->
action
)
continue
;
if
(
desc
->
irq_data
.
domain
!=
xics_host
)
continue
;
irq
=
desc
->
irq_data
.
hwirq
;
/* We need to get IPIs still. */
if
(
irq
==
XICS_IPI
||
irq
==
XICS_IRQ_SPURIOUS
)
continue
;
chip
=
irq_desc_get_chip
(
desc
);
if
(
!
chip
||
!
chip
->
irq_set_affinity
)
continue
;
...
...
@@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
}
#endif
/* CONFIG_SMP */
static
int
xics_host_match
(
struct
irq_
host
*
h
,
struct
device_node
*
node
)
static
int
xics_host_match
(
struct
irq_
domain
*
h
,
struct
device_node
*
node
)
{
struct
ics
*
ics
;
...
...
@@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = {
.
irq_unmask
=
xics_ipi_unmask
,
};
static
int
xics_host_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
xics_host_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
ics
*
ics
;
...
...
@@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
return
-
EINVAL
;
}
static
int
xics_host_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
xics_host_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
struct
irq_
host
_ops
xics_host_ops
=
{
static
struct
irq_
domain
_ops
xics_host_ops
=
{
.
match
=
xics_host_match
,
.
map
=
xics_host_map
,
.
xlate
=
xics_host_xlate
,
...
...
@@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = {
static
void
__init
xics_init_host
(
void
)
{
xics_host
=
irq_alloc_host
(
NULL
,
IRQ_HOST_MAP_TREE
,
0
,
&
xics_host_ops
,
XICS_IRQ_SPURIOUS
);
xics_host
=
irq_domain_add_tree
(
NULL
,
&
xics_host_ops
,
NULL
);
BUG_ON
(
xics_host
==
NULL
);
irq_set_default_host
(
xics_host
);
}
...
...
arch/powerpc/sysdev/xilinx_intc.c
View file @
1f52299e
...
...
@@ -40,7 +40,7 @@
#define XINTC_IVR 24
/* Interrupt Vector */
#define XINTC_MER 28
/* Master Enable */
static
struct
irq_
host
*
master_irqhost
;
static
struct
irq_
domain
*
master_irqhost
;
#define XILINX_INTC_MAXIRQS (32)
...
...
@@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = {
/**
* xilinx_intc_xlate - translate virq# from device tree interrupts property
*/
static
int
xilinx_intc_xlate
(
struct
irq_
host
*
h
,
struct
device_node
*
ct
,
static
int
xilinx_intc_xlate
(
struct
irq_
domain
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
...
...
@@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,
return
0
;
}
static
int
xilinx_intc_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
xilinx_intc_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
irq
)
{
irq_set_chip_data
(
virq
,
h
->
host_data
);
...
...
@@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
struct
irq_
host
_ops
xilinx_intc_ops
=
{
static
struct
irq_
domain
_ops
xilinx_intc_ops
=
{
.
map
=
xilinx_intc_map
,
.
xlate
=
xilinx_intc_xlate
,
};
struct
irq_
host
*
__init
struct
irq_
domain
*
__init
xilinx_intc_init
(
struct
device_node
*
np
)
{
struct
irq_
host
*
irq
;
struct
irq_
domain
*
irq
;
void
*
regs
;
/* Find and map the intc registers */
...
...
@@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np)
out_be32
(
regs
+
XINTC_IAR
,
~
(
u32
)
0
);
/* Acknowledge pending irqs */
out_be32
(
regs
+
XINTC_MER
,
0x3UL
);
/* Turn on the Master Enable. */
/* Allocate and initialize an irq_
host
structure. */
irq
=
irq_
alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
XILINX_INTC_MAXIRQS
,
&
xilinx_intc_ops
,
-
1
);
/* Allocate and initialize an irq_
domain
structure. */
irq
=
irq_
domain_add_linear
(
np
,
XILINX_INTC_MAXIRQS
,
&
xilinx_intc_ops
,
regs
);
if
(
!
irq
)
panic
(
__FILE__
": Cannot allocate IRQ host
\n
"
);
irq
->
host_data
=
regs
;
return
irq
;
}
...
...
arch/sparc/include/asm/prom.h
View file @
1f52299e
...
...
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
#include <linux/irqdomain.h>
#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
...
...
@@ -55,15 +56,6 @@ struct resource;
extern
void
__iomem
*
of_ioremap
(
struct
resource
*
res
,
unsigned
long
offset
,
unsigned
long
size
,
char
*
name
);
extern
void
of_iounmap
(
struct
resource
*
res
,
void
__iomem
*
base
,
unsigned
long
size
);
/* These routines are here to provide compatibility with how powerpc
* handles IRQ mapping for OF device nodes. We precompute and permanently
* register them in the platform_device objects, whereas powerpc computes them
* on request.
*/
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
}
extern
struct
device_node
*
of_console_device
;
extern
char
*
of_console_path
;
extern
char
*
of_console_options
;
...
...
arch/x86/Kconfig
View file @
1f52299e
...
...
@@ -398,6 +398,7 @@ config X86_INTEL_CE
select X86_REBOOTFIXUPS
select OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
---help---
Select for the Intel CE media processor (CE4100) SOC.
This option compiles in support for the CE4100 SOC for settop
...
...
@@ -2076,6 +2077,7 @@ config OLPC
select GPIOLIB
select OF
select OF_PROMTREE
select IRQ_DOMAIN
---help---
Add support for detecting the unique features of the OLPC
XO hardware.
...
...
arch/x86/include/asm/irq_controller.h
deleted
100644 → 0
View file @
ffd76d8b
#ifndef __IRQ_CONTROLLER__
#define __IRQ_CONTROLLER__
struct
irq_domain
{
int
(
*
xlate
)(
struct
irq_domain
*
h
,
const
u32
*
intspec
,
u32
intsize
,
u32
*
out_hwirq
,
u32
*
out_type
);
void
*
priv
;
struct
device_node
*
controller
;
struct
list_head
l
;
};
#endif
arch/x86/include/asm/prom.h
View file @
1f52299e
...
...
@@ -21,7 +21,6 @@
#include <asm/irq.h>
#include <linux/atomic.h>
#include <asm/setup.h>
#include <asm/irq_controller.h>
#ifdef CONFIG_OF
extern
int
of_ioapic
;
...
...
@@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE];
#define pci_address_to_pio pci_address_to_pio
unsigned
long
pci_address_to_pio
(
phys_addr_t
addr
);
/**
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
*
* FIXME: We really should implement proper virq handling like power,
* but that's going to be major surgery.
*/
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
}
#define HAVE_ARCH_DEVTREE_FIXUPS
#endif
/* __ASSEMBLY__ */
...
...
arch/x86/kernel/devicetree.c
View file @
1f52299e
...
...
@@ -4,6 +4,7 @@
#include <linux/bootmem.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/of.h>
...
...
@@ -17,64 +18,14 @@
#include <linux/initrd.h>
#include <asm/hpet.h>
#include <asm/irq_controller.h>
#include <asm/apic.h>
#include <asm/pci_x86.h>
__initdata
u64
initial_dtb
;
char
__initdata
cmd_line
[
COMMAND_LINE_SIZE
];
static
LIST_HEAD
(
irq_domains
);
static
DEFINE_RAW_SPINLOCK
(
big_irq_lock
);
int
__initdata
of_ioapic
;
#ifdef CONFIG_X86_IO_APIC
static
void
add_interrupt_host
(
struct
irq_domain
*
ih
)
{
unsigned
long
flags
;
raw_spin_lock_irqsave
(
&
big_irq_lock
,
flags
);
list_add
(
&
ih
->
l
,
&
irq_domains
);
raw_spin_unlock_irqrestore
(
&
big_irq_lock
,
flags
);
}
#endif
static
struct
irq_domain
*
get_ih_from_node
(
struct
device_node
*
controller
)
{
struct
irq_domain
*
ih
,
*
found
=
NULL
;
unsigned
long
flags
;
raw_spin_lock_irqsave
(
&
big_irq_lock
,
flags
);
list_for_each_entry
(
ih
,
&
irq_domains
,
l
)
{
if
(
ih
->
controller
==
controller
)
{
found
=
ih
;
break
;
}
}
raw_spin_unlock_irqrestore
(
&
big_irq_lock
,
flags
);
return
found
;
}
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
struct
irq_domain
*
ih
;
u32
virq
,
type
;
int
ret
;
ih
=
get_ih_from_node
(
controller
);
if
(
!
ih
)
return
0
;
ret
=
ih
->
xlate
(
ih
,
intspec
,
intsize
,
&
virq
,
&
type
);
if
(
ret
)
return
0
;
if
(
type
==
IRQ_TYPE_NONE
)
return
virq
;
irq_set_irq_type
(
virq
,
type
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
unsigned
long
pci_address_to_pio
(
phys_addr_t
address
)
{
/*
...
...
@@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] =
},
};
static
int
ioapic_xlate
(
struct
irq_domain
*
id
,
const
u32
*
intspec
,
u32
intsize
,
u32
*
out_hwirq
,
u32
*
out_type
)
static
int
ioapic_xlate
(
struct
irq_domain
*
domain
,
struct
device_node
*
controller
,
const
u32
*
intspec
,
u32
intsize
,
irq_hw_number_t
*
out_hwirq
,
u32
*
out_type
)
{
struct
mp_ioapic_gsi
*
gsi_cfg
;
struct
io_apic_irq_attr
attr
;
struct
of_ioapic_type
*
it
;
u32
line
,
idx
,
type
;
u32
line
,
idx
;
int
rc
;
if
(
intsize
<
2
)
if
(
WARN_ON
(
intsize
<
2
)
)
return
-
EINVAL
;
line
=
*
intspec
;
idx
=
(
u32
)
id
->
priv
;
gsi_cfg
=
mp_ioapic_gsi_routing
(
idx
);
*
out_hwirq
=
line
+
gsi_cfg
->
gsi_base
;
intspec
++
;
type
=
*
intspec
;
line
=
intspec
[
0
];
if
(
type
>=
ARRAY_SIZE
(
of_ioapic_type
))
if
(
intspec
[
1
]
>=
ARRAY_SIZE
(
of_ioapic_type
))
return
-
EINVAL
;
it
=
of_ioapic_type
+
type
;
*
out_type
=
it
->
out_type
;
it
=
&
of_ioapic_type
[
intspec
[
1
]];
idx
=
(
u32
)
domain
->
host_data
;
set_io_apic_irq_attr
(
&
attr
,
idx
,
line
,
it
->
trigger
,
it
->
polarity
);
return
io_apic_setup_irq_pin_once
(
*
out_hwirq
,
cpu_to_node
(
0
),
&
attr
);
rc
=
io_apic_setup_irq_pin_once
(
irq_find_mapping
(
domain
,
line
),
cpu_to_node
(
0
),
&
attr
);
if
(
rc
)
return
rc
;
*
out_hwirq
=
line
;
*
out_type
=
it
->
out_type
;
return
0
;
}
const
struct
irq_domain_ops
ioapic_irq_domain_ops
=
{
.
xlate
=
ioapic_xlate
,
};
static
void
__init
ioapic_add_ofnode
(
struct
device_node
*
np
)
{
struct
resource
r
;
...
...
@@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)
for
(
i
=
0
;
i
<
nr_ioapics
;
i
++
)
{
if
(
r
.
start
==
mpc_ioapic_addr
(
i
))
{
struct
irq_domain
*
id
;
struct
mp_ioapic_gsi
*
gsi_cfg
;
gsi_cfg
=
mp_ioapic_gsi_routing
(
i
);
id
=
kzalloc
(
sizeof
(
*
id
),
GFP_KERNEL
);
id
=
irq_domain_add_legacy
(
np
,
32
,
gsi_cfg
->
gsi_base
,
0
,
&
ioapic_irq_domain_ops
,
(
void
*
)
i
);
BUG_ON
(
!
id
);
id
->
controller
=
np
;
id
->
xlate
=
ioapic_xlate
;
id
->
priv
=
(
void
*
)
i
;
add_interrupt_host
(
id
);
return
;
}
}
...
...
drivers/gpio/gpio-mpc8xxx.c
View file @
1f52299e
...
...
@@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip {
* open drain mode safely
*/
u32
data
;
struct
irq_
host
*
irq
;
struct
irq_
domain
*
irq
;
void
*
of_dev_id_data
;
};
...
...
@@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = {
.
irq_set_type
=
mpc8xxx_irq_set_type
,
};
static
int
mpc8xxx_gpio_irq_map
(
struct
irq_
host
*
h
,
unsigned
int
virq
,
static
int
mpc8xxx_gpio_irq_map
(
struct
irq_
domain
*
h
,
unsigned
int
virq
,
irq_hw_number_t
hw
)
{
struct
mpc8xxx_gpio_chip
*
mpc8xxx_gc
=
h
->
host_data
;
...
...
@@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
return
0
;
}
static
int
mpc8xxx_gpio_irq_xlate
(
struct
irq_host
*
h
,
struct
device_node
*
ct
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_flags
)
{
/* interrupt sense values coming from the device tree equal either
* EDGE_FALLING or EDGE_BOTH
*/
*
out_hwirq
=
intspec
[
0
];
*
out_flags
=
intspec
[
1
];
return
0
;
}
static
struct
irq_host_ops
mpc8xxx_gpio_irq_ops
=
{
static
struct
irq_domain_ops
mpc8xxx_gpio_irq_ops
=
{
.
map
=
mpc8xxx_gpio_irq_map
,
.
xlate
=
mpc8xxx_gpio_irq_xlate
,
.
xlate
=
irq_domain_xlate_twocell
,
};
static
struct
of_device_id
mpc8xxx_gpio_ids
[]
__initdata
=
{
...
...
@@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
if
(
hwirq
==
NO_IRQ
)
goto
skip_irq
;
mpc8xxx_gc
->
irq
=
irq_alloc_host
(
np
,
IRQ_HOST_MAP_LINEAR
,
MPC8XXX_GPIO_PINS
,
&
mpc8xxx_gpio_irq_ops
,
MPC8XXX_GPIO_PINS
);
mpc8xxx_gc
->
irq
=
irq_domain_add_linear
(
np
,
MPC8XXX_GPIO_PINS
,
&
mpc8xxx_gpio_irq_ops
,
mpc8xxx_gc
);
if
(
!
mpc8xxx_gc
->
irq
)
goto
skip_irq
;
...
...
@@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
if
(
id
)
mpc8xxx_gc
->
of_dev_id_data
=
id
->
data
;
mpc8xxx_gc
->
irq
->
host_data
=
mpc8xxx_gc
;
/* ack and mask all irqs */
out_be32
(
mm_gc
->
regs
+
GPIO_IER
,
0xffffffff
);
out_be32
(
mm_gc
->
regs
+
GPIO_IMR
,
0
);
...
...
drivers/mfd/Kconfig
View file @
1f52299e
...
...
@@ -201,6 +201,7 @@ config MENELAUS
config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y && GENERIC_HARDIRQS
select IRQ_DOMAIN
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
...
...
drivers/mfd/twl-core.c
View file @
1f52299e
...
...
@@ -149,7 +149,7 @@
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
#define TWL4030_NR_IRQS
8
#define TWL4030_NR_IRQS
34
/* core:8, power:8, gpio: 18 */
#define TWL6030_NR_IRQS 20
/* Base Address defns for twl4030_map[] */
...
...
@@ -263,10 +263,6 @@ struct twl_client {
static
struct
twl_client
twl_modules
[
TWL_NUM_SLAVES
];
#ifdef CONFIG_IRQ_DOMAIN
static
struct
irq_domain
domain
;
#endif
/* mapping the module id to slave id and base address */
struct
twl_mapping
{
unsigned
char
sid
;
/* Slave ID */
...
...
@@ -1227,14 +1223,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
pdata
->
irq_base
=
status
;
pdata
->
irq_end
=
pdata
->
irq_base
+
nr_irqs
;
#ifdef CONFIG_IRQ_DOMAIN
domain
.
irq_base
=
pdata
->
irq_base
;
domain
.
nr_irq
=
nr_irqs
;
domain
.
of_node
=
of_node_get
(
node
);
domain
.
ops
=
&
irq_domain_simple_ops
;
irq_domain_add
(
&
domain
);
#endif
irq_domain_add_legacy
(
node
,
nr_irqs
,
pdata
->
irq_base
,
0
,
&
irq_domain_simple_ops
,
NULL
);
if
(
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_I2C
)
==
0
)
{
dev_dbg
(
&
client
->
dev
,
"can't talk I2C?
\n
"
);
...
...
@@ -1315,11 +1305,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8
(
TWL4030_MODULE_INTBR
,
temp
,
REG_GPPUPDCTR1
);
}
#ifdef CONFIG_OF_DEVICE
status
=
-
ENODEV
;
if
(
node
)
status
=
of_platform_populate
(
node
,
NULL
,
NULL
,
&
client
->
dev
);
else
#endif
if
(
status
)
status
=
add_children
(
pdata
,
id
->
driver_data
);
fail:
...
...
drivers/net/phy/mdio-gpio.c
View file @
1f52299e
...
...
@@ -255,13 +255,13 @@ static inline int __init mdio_ofgpio_init(void)
return
platform_driver_register
(
&
mdio_ofgpio_driver
);
}
static
inline
void
__exit
mdio_ofgpio_exit
(
void
)
static
inline
void
mdio_ofgpio_exit
(
void
)
{
platform_driver_unregister
(
&
mdio_ofgpio_driver
);
}
#else
static
inline
int
__init
mdio_ofgpio_init
(
void
)
{
return
0
;
}
static
inline
void
__exit
mdio_ofgpio_exit
(
void
)
{
}
static
inline
void
mdio_ofgpio_exit
(
void
)
{
}
#endif
/* CONFIG_OF_GPIO */
static
struct
platform_driver
mdio_gpio_driver
=
{
...
...
drivers/of/platform.c
View file @
1f52299e
...
...
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
#include <asm/dcr.h>
#endif
#if
!defined(CONFIG_SPARC)
#if
def CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
* each applicable node.
...
...
@@ -462,4 +462,4 @@ int of_platform_populate(struct device_node *root,
of_node_put
(
root
);
return
rc
;
}
#endif
/*
!CONFIG_SPARC
*/
#endif
/*
CONFIG_OF_ADDRESS
*/
include/linux/irqdomain.h
View file @
1f52299e
...
...
@@ -9,99 +9,182 @@
* representation into a hardware irq number that can be mapped back to a
* Linux irq number without any extra platform support code.
*
* irq_domain is expected to be embedded in an interrupt controller's private
* data structure.
* 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.
*
* The host code and data structures are agnostic to whether or not
* we use an open firmware device-tree. We do have references to struct
* device_node in two places: in irq_find_host() to find the host matching
* a given interrupt controller node, and of course as an argument to its
* counterpart domain->ops->match() callback. However, those are treated as
* generic pointers by the core and the fact that it's actually a device-node
* pointer is purely a convention between callers and implementation. This
* code could thus be used on other architectures by replacing those two
* by some sort of arch-specific void * "token" used to identify interrupt
* controllers.
*/
#ifndef _LINUX_IRQDOMAIN_H
#define _LINUX_IRQDOMAIN_H
#include <linux/
irq
.h>
#include <linux/
mod_devicetabl
e.h>
#include <linux/
types
.h>
#include <linux/
radix-tre
e.h>
#ifdef CONFIG_IRQ_DOMAIN
struct
device_node
;
struct
irq_domain
;
struct
of_device_id
;
/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16
/* 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
* @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)
* @dt_translate: Given a device tree node and interrupt specifier, decode
* the hardware irq number and linux irq type value.
* @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
* @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
{
unsigned
int
(
*
to_irq
)(
struct
irq_domain
*
d
,
unsigned
long
hwirq
);
#ifdef CONFIG_OF
int
(
*
dt_translate
)(
struct
irq_domain
*
d
,
struct
device_node
*
node
,
const
u32
*
intspec
,
unsigned
int
intsize
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
);
#endif
/* CONFIG_OF */
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
);
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
* @list: Element in global irq_domain list.
* @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
* @ops: pointer to irq_domain methods
* @priv: private data pointer for use by owner. Not touched by irq_domain
* core code.
* @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
list
;
unsigned
int
irq_base
;
unsigned
int
nr_irq
;
unsigned
int
hwirq_base
;
struct
list_head
link
;
/* type of reverse mapping_technique */
unsigned
int
revmap_type
;
union
{
struct
{
unsigned
int
size
;
unsigned
int
first_irq
;
irq_hw_number_t
first_hwirq
;
}
legacy
;
struct
{
unsigned
int
size
;
unsigned
int
*
revmap
;
}
linear
;
struct
radix_tree_root
tree
;
}
revmap_data
;
const
struct
irq_domain_ops
*
ops
;
void
*
priv
;
void
*
host_data
;
irq_hw_number_t
inval_irq
;
/* Optional device node pointer */
struct
device_node
*
of_node
;
};
/**
* 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
)
#ifdef CONFIG_IRQ_DOMAIN
struct
irq_domain
*
irq_domain_add_legacy
(
struct
device_node
*
of_node
,
unsigned
int
size
,
unsigned
int
first_irq
,
irq_hw_number_t
first_hwirq
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
);
struct
irq_domain
*
irq_domain_add_linear
(
struct
device_node
*
of_node
,
unsigned
int
size
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
);
struct
irq_domain
*
irq_domain_add_nomap
(
struct
device_node
*
of_node
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
);
struct
irq_domain
*
irq_domain_add_tree
(
struct
device_node
*
of_node
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
);
extern
struct
irq_domain
*
irq_find_host
(
struct
device_node
*
node
);
extern
void
irq_set_default_host
(
struct
irq_domain
*
host
);
extern
void
irq_set_virq_count
(
unsigned
int
count
);
static
inline
struct
irq_domain
*
irq_domain_add_legacy_isa
(
struct
device_node
*
of_node
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
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
;
return
irq_domain_add_legacy
(
of_node
,
NUM_ISA_INTERRUPTS
,
0
,
0
,
ops
,
host_data
);
}
extern
struct
irq_domain
*
irq_find_host
(
struct
device_node
*
node
);
extern
void
irq_set_default_host
(
struct
irq_domain
*
host
);
extern
void
irq_set_virq_count
(
unsigned
int
count
);
#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
unsigned
int
irq_create_mapping
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
);
extern
void
irq_dispose_mapping
(
unsigned
int
virq
);
extern
unsigned
int
irq_find_mapping
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
);
extern
unsigned
int
irq_create_direct_mapping
(
struct
irq_domain
*
host
);
extern
void
irq_radix_revmap_insert
(
struct
irq_domain
*
host
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
);
extern
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
);
extern
unsigned
int
irq_linear_revmap
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
);
extern
void
irq_domain_add
(
struct
irq_domain
*
domain
);
extern
void
irq_domain_del
(
struct
irq_domain
*
domain
);
extern
const
struct
irq_domain_ops
irq_domain_simple_ops
;
extern
struct
irq_domain_ops
irq_domain_simple_ops
;
#endif
/* CONFIG_IRQ_DOMAIN */
/* stock xlate functions */
int
irq_domain_xlate_onecell
(
struct
irq_domain
*
d
,
struct
device_node
*
ctrlr
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
);
int
irq_domain_xlate_twocell
(
struct
irq_domain
*
d
,
struct
device_node
*
ctrlr
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
);
int
irq_domain_xlate_onetwocell
(
struct
irq_domain
*
d
,
struct
device_node
*
ctrlr
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
);
#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
extern
void
irq_domain_add_simple
(
struct
device_node
*
controller
,
int
irq_base
);
#if defined(CONFIG_OF_IRQ)
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 */
#else
/* 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
/* !CONFIG_OF_IRQ */
#else
/* CONFIG_IRQ_DOMAIN */
static
inline
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
}
#endif
/* !CONFIG_IRQ_DOMAIN */
#endif
/* _LINUX_IRQDOMAIN_H */
include/linux/of_address.h
View file @
1f52299e
...
...
@@ -4,6 +4,7 @@
#include <linux/errno.h>
#include <linux/of.h>
#ifdef CONFIG_OF_ADDRESS
extern
u64
of_translate_address
(
struct
device_node
*
np
,
const
__be32
*
addr
);
extern
int
of_address_to_resource
(
struct
device_node
*
dev
,
int
index
,
struct
resource
*
r
);
...
...
@@ -25,12 +26,37 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
#define pci_address_to_pio pci_address_to_pio
#endif
#ifdef CONFIG_PCI
#else
/* CONFIG_OF_ADDRESS */
static
inline
int
of_address_to_resource
(
struct
device_node
*
dev
,
int
index
,
struct
resource
*
r
)
{
return
-
EINVAL
;
}
static
inline
struct
device_node
*
of_find_matching_node_by_address
(
struct
device_node
*
from
,
const
struct
of_device_id
*
matches
,
u64
base_address
)
{
return
NULL
;
}
static
inline
void
__iomem
*
of_iomap
(
struct
device_node
*
device
,
int
index
)
{
return
NULL
;
}
static
inline
const
u32
*
of_get_address
(
struct
device_node
*
dev
,
int
index
,
u64
*
size
,
unsigned
int
*
flags
)
{
return
NULL
;
}
#endif
/* CONFIG_OF_ADDRESS */
#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)
extern
const
__be32
*
of_get_pci_address
(
struct
device_node
*
dev
,
int
bar_no
,
u64
*
size
,
unsigned
int
*
flags
);
extern
int
of_pci_address_to_resource
(
struct
device_node
*
dev
,
int
bar
,
struct
resource
*
r
);
#else
/* CONFIG_PCI */
#else
/* CONFIG_
OF_ADDRESS && CONFIG_
PCI */
static
inline
int
of_pci_address_to_resource
(
struct
device_node
*
dev
,
int
bar
,
struct
resource
*
r
)
{
...
...
@@ -42,8 +68,7 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev,
{
return
NULL
;
}
#endif
/* CONFIG_PCI */
#endif
/* CONFIG_OF_ADDRESS && CONFIG_PCI */
#endif
/* __OF_ADDRESS_H */
include/linux/of_irq.h
View file @
1f52299e
...
...
@@ -6,6 +6,7 @@ struct of_irq;
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/ioport.h>
#include <linux/of.h>
...
...
@@ -65,9 +66,6 @@ extern int of_irq_map_one(struct device_node *device, int index,
extern
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
);
#ifdef CONFIG_IRQ_DOMAIN
extern
void
irq_dispose_mapping
(
unsigned
int
irq
);
#endif
extern
int
of_irq_to_resource
(
struct
device_node
*
dev
,
int
index
,
struct
resource
*
r
);
extern
int
of_irq_count
(
struct
device_node
*
dev
);
...
...
include/linux/of_platform.h
View file @
1f52299e
...
...
@@ -81,7 +81,7 @@ extern struct platform_device *of_device_alloc(struct device_node *np,
struct
device
*
parent
);
extern
struct
platform_device
*
of_find_device_by_node
(
struct
device_node
*
np
);
#if
!defined(CONFIG_SPARC)
/* SPARC has its own device registration method
*/
#if
def CONFIG_OF_ADDRESS
/* device reg helpers depend on OF_ADDRESS
*/
/* Platform devices and busses creation */
extern
struct
platform_device
*
of_platform_device_create
(
struct
device_node
*
np
,
const
char
*
bus_id
,
...
...
@@ -94,7 +94,15 @@ extern int of_platform_populate(struct device_node *root,
const
struct
of_device_id
*
matches
,
const
struct
of_dev_auxdata
*
lookup
,
struct
device
*
parent
);
#endif
/* !CONFIG_SPARC */
#else
static
inline
int
of_platform_populate
(
struct
device_node
*
root
,
const
struct
of_device_id
*
matches
,
const
struct
of_dev_auxdata
*
lookup
,
struct
device
*
parent
)
{
return
-
ENODEV
;
}
#endif
/* !CONFIG_OF_ADDRESS */
#endif
/* CONFIG_OF_DEVICE */
...
...
kernel/irq/irqdomain.c
View file @
1f52299e
#include <linux/debugfs.h>
#include <linux/hardirq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/fs.h>
#define IRQ_DOMAIN_MAP_LEGACY 0
/* driver allocated fixed range of irqs.
* ie. 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 */
static
LIST_HEAD
(
irq_domain_list
);
static
DEFINE_MUTEX
(
irq_domain_mutex
);
static
DEFINE_MUTEX
(
revmap_trees_mutex
);
static
unsigned
int
irq_virq_count
=
NR_IRQS
;
static
struct
irq_domain
*
irq_default_domain
;
/**
* irq_domain_add() - Register an irq_domain
* @domain: ptr to initialized irq_domain structure
* irq_domain_alloc() - Allocate a new irq_domain data structure
* @of_node: optional device-tree node of the interrupt controller
* @revmap_type: type of reverse mapping to use
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*
*
Registers an irq_domain structure. The irq_domain must at a minimum be
*
initialized with an ops structure pointer, and either a ->to_irq hook o
r
*
a valid irq_base value. Everything else is optional
.
*
Allocates and initialize and irq_domain structure. Caller is expected to
*
register allocated irq_domain with irq_domain_register(). Returns pointe
r
*
to IRQ domain, or NULL on failure
.
*/
void
irq_domain_add
(
struct
irq_domain
*
domain
)
static
struct
irq_domain
*
irq_domain_alloc
(
struct
device_node
*
of_node
,
unsigned
int
revmap_type
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
struct
irq_data
*
d
;
int
hwirq
,
irq
;
struct
irq_domain
*
domain
;
/*
* This assumes that the irq_domain owner has already allocated
* the irq_descs. This block will be removed when support for dynamic
* allocation of irq_descs is added to irq_domain.
*/
irq_domain_for_each_irq
(
domain
,
hwirq
,
irq
)
{
d
=
irq_get_irq_data
(
irq
);
if
(
!
d
)
{
WARN
(
1
,
"error: assigning domain to non existant irq_desc"
);
return
;
}
if
(
d
->
domain
)
{
/* things are broken; just report, don't clean up */
WARN
(
1
,
"error: irq_desc already assigned to a domain"
);
return
;
domain
=
kzalloc
(
sizeof
(
*
domain
),
GFP_KERNEL
);
if
(
WARN_ON
(
!
domain
))
return
NULL
;
/* Fill structure */
domain
->
revmap_type
=
revmap_type
;
domain
->
ops
=
ops
;
domain
->
host_data
=
host_data
;
domain
->
of_node
=
of_node_get
(
of_node
);
return
domain
;
}
static
void
irq_domain_add
(
struct
irq_domain
*
domain
)
{
mutex_lock
(
&
irq_domain_mutex
);
list_add
(
&
domain
->
link
,
&
irq_domain_list
);
mutex_unlock
(
&
irq_domain_mutex
);
pr_debug
(
"irq: Allocated domain of type %d @0x%p
\n
"
,
domain
->
revmap_type
,
domain
);
}
static
unsigned
int
irq_domain_legacy_revmap
(
struct
irq_domain
*
domain
,
irq_hw_number_t
hwirq
)
{
irq_hw_number_t
first_hwirq
=
domain
->
revmap_data
.
legacy
.
first_hwirq
;
int
size
=
domain
->
revmap_data
.
legacy
.
size
;
if
(
WARN_ON
(
hwirq
<
first_hwirq
||
hwirq
>=
first_hwirq
+
size
))
return
0
;
return
hwirq
-
first_hwirq
+
domain
->
revmap_data
.
legacy
.
first_irq
;
}
/**
* irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
* @size: total number of irqs in legacy mapping
* @first_irq: first number of irq block assigned to the domain
* @first_hwirq: first hwirq number to use for the translation. Should normally
* be '0', but a positive integer can be used if the effective
* hwirqs numbering does not begin at zero.
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*
* Note: the map() callback will be called before this function returns
* for all legacy interrupts except 0 (which is always the invalid irq for
* a legacy controller).
*/
struct
irq_domain
*
irq_domain_add_legacy
(
struct
device_node
*
of_node
,
unsigned
int
size
,
unsigned
int
first_irq
,
irq_hw_number_t
first_hwirq
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
struct
irq_domain
*
domain
;
unsigned
int
i
;
domain
=
irq_domain_alloc
(
of_node
,
IRQ_DOMAIN_MAP_LEGACY
,
ops
,
host_data
);
if
(
!
domain
)
return
NULL
;
domain
->
revmap_data
.
legacy
.
first_irq
=
first_irq
;
domain
->
revmap_data
.
legacy
.
first_hwirq
=
first_hwirq
;
domain
->
revmap_data
.
legacy
.
size
=
size
;
mutex_lock
(
&
irq_domain_mutex
);
/* Verify that all the irqs are available */
for
(
i
=
0
;
i
<
size
;
i
++
)
{
int
irq
=
first_irq
+
i
;
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
irq
);
if
(
WARN_ON
(
!
irq_data
||
irq_data
->
domain
))
{
mutex_unlock
(
&
irq_domain_mutex
);
of_node_put
(
domain
->
of_node
);
kfree
(
domain
);
return
NULL
;
}
d
->
domain
=
domain
;
d
->
hwirq
=
hwirq
;
}
mutex_lock
(
&
irq_domain_mutex
);
list_add
(
&
domain
->
list
,
&
irq_domain_list
);
/* Claim all of the irqs before registering a legacy domain */
for
(
i
=
0
;
i
<
size
;
i
++
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
first_irq
+
i
);
irq_data
->
hwirq
=
first_hwirq
+
i
;
irq_data
->
domain
=
domain
;
}
mutex_unlock
(
&
irq_domain_mutex
);
for
(
i
=
0
;
i
<
size
;
i
++
)
{
int
irq
=
first_irq
+
i
;
int
hwirq
=
first_hwirq
+
i
;
/* IRQ0 gets ignored */
if
(
!
irq
)
continue
;
/* Legacy flags are left to default at this point,
* one can then use irq_create_mapping() to
* explicitly change them
*/
ops
->
map
(
domain
,
irq
,
hwirq
);
/* Clear norequest flags */
irq_clear_status_flags
(
irq
,
IRQ_NOREQUEST
);
}
irq_domain_add
(
domain
);
return
domain
;
}
/**
* irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*/
struct
irq_domain
*
irq_domain_add_linear
(
struct
device_node
*
of_node
,
unsigned
int
size
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
struct
irq_domain
*
domain
;
unsigned
int
*
revmap
;
revmap
=
kzalloc
(
sizeof
(
*
revmap
)
*
size
,
GFP_KERNEL
);
if
(
WARN_ON
(
!
revmap
))
return
NULL
;
domain
=
irq_domain_alloc
(
of_node
,
IRQ_DOMAIN_MAP_LINEAR
,
ops
,
host_data
);
if
(
!
domain
)
{
kfree
(
revmap
);
return
NULL
;
}
domain
->
revmap_data
.
linear
.
size
=
size
;
domain
->
revmap_data
.
linear
.
revmap
=
revmap
;
irq_domain_add
(
domain
);
return
domain
;
}
struct
irq_domain
*
irq_domain_add_nomap
(
struct
device_node
*
of_node
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
struct
irq_domain
*
domain
=
irq_domain_alloc
(
of_node
,
IRQ_DOMAIN_MAP_NOMAP
,
ops
,
host_data
);
if
(
domain
)
irq_domain_add
(
domain
);
return
domain
;
}
/**
* irq_domain_add_tree()
* @of_node: pointer to interrupt controller's device tree node.
* @ops: map/unmap domain callbacks
*
* Note: The radix tree will be allocated later during boot automatically
* (the reverse mapping will use the slow path until that happens).
*/
struct
irq_domain
*
irq_domain_add_tree
(
struct
device_node
*
of_node
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
struct
irq_domain
*
domain
=
irq_domain_alloc
(
of_node
,
IRQ_DOMAIN_MAP_TREE
,
ops
,
host_data
);
if
(
domain
)
{
INIT_RADIX_TREE
(
&
domain
->
revmap_data
.
tree
,
GFP_KERNEL
);
irq_domain_add
(
domain
);
}
return
domain
;
}
/**
* irq_
domain_del() - Unregister an irq_domain
* @
domain: ptr to registered irq_domain.
* irq_
find_host() - Locates a domain for a given device node
* @
node: device-tree node of the interrupt controller
*/
void
irq_domain_del
(
struct
irq_domain
*
domain
)
struct
irq_domain
*
irq_find_host
(
struct
device_node
*
node
)
{
struct
irq_d
ata
*
d
;
int
hwirq
,
irq
;
struct
irq_d
omain
*
h
,
*
found
=
NULL
;
int
rc
;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*/
mutex_lock
(
&
irq_domain_mutex
);
list_del
(
&
domain
->
list
);
list_for_each_entry
(
h
,
&
irq_domain_list
,
link
)
{
if
(
h
->
ops
->
match
)
rc
=
h
->
ops
->
match
(
h
,
node
);
else
rc
=
(
h
->
of_node
!=
NULL
)
&&
(
h
->
of_node
==
node
);
if
(
rc
)
{
found
=
h
;
break
;
}
}
mutex_unlock
(
&
irq_domain_mutex
);
return
found
;
}
EXPORT_SYMBOL_GPL
(
irq_find_host
);
/**
* irq_set_default_host() - Set a "default" irq domain
* @domain: default domain pointer
*
* For convenience, it's possible to set a "default" domain that will be used
* whenever NULL is passed to irq_create_mapping(). It makes life easier for
* platforms that want to manipulate a few hard coded interrupt numbers that
* aren't properly represented in the device-tree.
*/
void
irq_set_default_host
(
struct
irq_domain
*
domain
)
{
pr_debug
(
"irq: Default domain set to @0x%p
\n
"
,
domain
);
irq_default_domain
=
domain
;
}
/**
* irq_set_virq_count() - Set the maximum number of linux irqs
* @count: number of linux irqs, capped with NR_IRQS
*
* This is mainly for use by platforms like iSeries who want to program
* the virtual irq number in the controller to avoid the reverse mapping
*/
void
irq_set_virq_count
(
unsigned
int
count
)
{
pr_debug
(
"irq: Trying to set virq count to %d
\n
"
,
count
);
/* Clear the irq_domain assignments */
irq_domain_for_each_irq
(
domain
,
hwirq
,
irq
)
{
d
=
irq_get_irq_data
(
irq
);
d
->
domain
=
NULL
;
BUG_ON
(
count
<
NUM_ISA_INTERRUPTS
);
if
(
count
<
NR_IRQS
)
irq_virq_count
=
count
;
}
static
int
irq_setup_virq
(
struct
irq_domain
*
domain
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
irq_data
->
hwirq
=
hwirq
;
irq_data
->
domain
=
domain
;
if
(
domain
->
ops
->
map
(
domain
,
virq
,
hwirq
))
{
pr_debug
(
"irq: -> mapping failed, freeing
\n
"
);
irq_data
->
domain
=
NULL
;
irq_data
->
hwirq
=
0
;
return
-
1
;
}
irq_clear_status_flags
(
virq
,
IRQ_NOREQUEST
);
return
0
;
}
#if defined(CONFIG_OF_IRQ)
/**
* irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
* irq_create_direct_mapping() - Allocate an irq for direct mapping
* @domain: domain to allocate the irq for or NULL for default domain
*
* Used by the device tree interrupt mapping code to translate a device tree
* interrupt specifier to a valid linux irq number. Returns either a valid
* linux IRQ number or 0.
* This routine is used for irq controllers which can choose the hardware
* interrupt numbers they generate. In such a case it's simplest to use
* the linux irq as the hardware interrupt number.
*/
unsigned
int
irq_create_direct_mapping
(
struct
irq_domain
*
domain
)
{
unsigned
int
virq
;
if
(
domain
==
NULL
)
domain
=
irq_default_domain
;
BUG_ON
(
domain
==
NULL
);
WARN_ON
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_NOMAP
);
virq
=
irq_alloc_desc_from
(
1
,
0
);
if
(
!
virq
)
{
pr_debug
(
"irq: create_direct virq allocation failed
\n
"
);
return
0
;
}
if
(
virq
>=
irq_virq_count
)
{
pr_err
(
"ERROR: no free irqs available below %i maximum
\n
"
,
irq_virq_count
);
irq_free_desc
(
virq
);
return
0
;
}
pr_debug
(
"irq: create_direct obtained virq %d
\n
"
,
virq
);
if
(
irq_setup_virq
(
domain
,
virq
,
virq
))
{
irq_free_desc
(
virq
);
return
0
;
}
return
virq
;
}
/**
* irq_create_mapping() - Map a hardware interrupt into linux irq space
* @domain: domain owning this hardware interrupt or NULL for default domain
* @hwirq: hardware irq number in that domain space
*
* When the caller no longer need the irq number returned by this function it
* should arrange to call irq_dispose_mapping().
* Only one mapping per hardware interrupt is permitted. Returns a linux
* irq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
unsigned
int
irq_create_mapping
(
struct
irq_domain
*
domain
,
irq_hw_number_t
hwirq
)
{
unsigned
int
virq
,
hint
;
pr_debug
(
"irq: irq_create_mapping(0x%p, 0x%lx)
\n
"
,
domain
,
hwirq
);
/* Look for default domain if nececssary */
if
(
domain
==
NULL
)
domain
=
irq_default_domain
;
if
(
domain
==
NULL
)
{
printk
(
KERN_WARNING
"irq_create_mapping called for"
" NULL domain, hwirq=%lx
\n
"
,
hwirq
);
WARN_ON
(
1
);
return
0
;
}
pr_debug
(
"irq: -> using domain @%p
\n
"
,
domain
);
/* Check if mapping already exists */
virq
=
irq_find_mapping
(
domain
,
hwirq
);
if
(
virq
)
{
pr_debug
(
"irq: -> existing mapping on virq %d
\n
"
,
virq
);
return
virq
;
}
/* Get a virtual interrupt number */
if
(
domain
->
revmap_type
==
IRQ_DOMAIN_MAP_LEGACY
)
return
irq_domain_legacy_revmap
(
domain
,
hwirq
);
/* Allocate a virtual interrupt number */
hint
=
hwirq
%
irq_virq_count
;
if
(
hint
==
0
)
hint
++
;
virq
=
irq_alloc_desc_from
(
hint
,
0
);
if
(
!
virq
)
virq
=
irq_alloc_desc_from
(
1
,
0
);
if
(
!
virq
)
{
pr_debug
(
"irq: -> virq allocation failed
\n
"
);
return
0
;
}
if
(
irq_setup_virq
(
domain
,
virq
,
hwirq
))
{
if
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_LEGACY
)
irq_free_desc
(
virq
);
return
0
;
}
pr_debug
(
"irq: irq %lu on domain %s mapped to virtual irq %u
\n
"
,
hwirq
,
domain
->
of_node
?
domain
->
of_node
->
full_name
:
"null"
,
virq
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_mapping
);
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
struct
irq_domain
*
domain
;
unsigned
long
hwirq
;
unsigned
int
irq
,
type
;
int
rc
=
-
EINVAL
;
irq_hw_number_t
hwirq
;
unsigned
int
type
=
IRQ_TYPE_NONE
;
unsigned
int
virq
;
/* Find a domain which can translate the irq spec */
mutex_lock
(
&
irq_domain_mutex
);
list_for_each_entry
(
domain
,
&
irq_domain_list
,
list
)
{
if
(
!
domain
->
ops
->
dt_translate
)
continue
;
rc
=
domain
->
ops
->
dt_translate
(
domain
,
controller
,
intspec
,
intsize
,
&
hwirq
,
&
type
);
if
(
rc
==
0
)
break
;
domain
=
controller
?
irq_find_host
(
controller
)
:
irq_default_domain
;
if
(
!
domain
)
{
#ifdef CONFIG_MIPS
/*
* Workaround to avoid breaking interrupt controller drivers
* that don't yet register an irq_domain. This is temporary
* code. ~~~gcl, Feb 24, 2012
*
* Scheduled for removal in Linux v3.6. That should be enough
* time.
*/
if
(
intsize
>
0
)
return
intspec
[
0
];
#endif
printk
(
KERN_WARNING
"irq: no irq domain found for %s !
\n
"
,
controller
->
full_name
);
return
0
;
}
mutex_unlock
(
&
irq_domain_mutex
);
if
(
rc
!=
0
)
return
0
;
/* If domain has no translation, then we assume interrupt line */
if
(
domain
->
ops
->
xlate
==
NULL
)
hwirq
=
intspec
[
0
];
else
{
if
(
domain
->
ops
->
xlate
(
domain
,
controller
,
intspec
,
intsize
,
&
hwirq
,
&
type
))
return
0
;
}
/* Create mapping */
virq
=
irq_create_mapping
(
domain
,
hwirq
);
if
(
!
virq
)
return
virq
;
irq
=
irq_domain_to_irq
(
domain
,
hwirq
);
if
(
type
!=
IRQ_TYPE_NONE
)
irq_set_irq_type
(
irq
,
type
);
pr_debug
(
"%s: mapped hwirq=%i to irq=%i, flags=%x
\n
"
,
controller
->
full_name
,
(
int
)
hwirq
,
irq
,
type
);
return
irq
;
/* Set type if specified and different than the current one */
if
(
type
!=
IRQ_TYPE_NONE
&&
type
!=
(
irqd_get_trigger_type
(
irq_get_irq_data
(
virq
))))
irq_set_irq_type
(
virq
,
type
);
return
virq
;
}
EXPORT_SYMBOL_GPL
(
irq_create_of_mapping
);
/**
* irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
* @irq: linux irq number to be discarded
* irq_dispose_mapping() - Unmap an interrupt
* @virq: linux irq number of the interrupt to unmap
*/
void
irq_dispose_mapping
(
unsigned
int
virq
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
struct
irq_domain
*
domain
;
irq_hw_number_t
hwirq
;
if
(
!
virq
||
!
irq_data
)
return
;
domain
=
irq_data
->
domain
;
if
(
WARN_ON
(
domain
==
NULL
))
return
;
/* Never unmap legacy interrupts */
if
(
domain
->
revmap_type
==
IRQ_DOMAIN_MAP_LEGACY
)
return
;
irq_set_status_flags
(
virq
,
IRQ_NOREQUEST
);
/* remove chip and handler */
irq_set_chip_and_handler
(
virq
,
NULL
,
NULL
);
/* Make sure it's completed */
synchronize_irq
(
virq
);
/* Tell the PIC about it */
if
(
domain
->
ops
->
unmap
)
domain
->
ops
->
unmap
(
domain
,
virq
);
smp_mb
();
/* Clear reverse map */
hwirq
=
irq_data
->
hwirq
;
switch
(
domain
->
revmap_type
)
{
case
IRQ_DOMAIN_MAP_LINEAR
:
if
(
hwirq
<
domain
->
revmap_data
.
linear
.
size
)
domain
->
revmap_data
.
linear
.
revmap
[
hwirq
]
=
0
;
break
;
case
IRQ_DOMAIN_MAP_TREE
:
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_delete
(
&
domain
->
revmap_data
.
tree
,
hwirq
);
mutex_unlock
(
&
revmap_trees_mutex
);
break
;
}
irq_free_desc
(
virq
);
}
EXPORT_SYMBOL_GPL
(
irq_dispose_mapping
);
/**
* irq_find_mapping() - Find a linux irq from an hw irq number.
* @domain: domain owning this hardware interrupt
* @hwirq: hardware irq number in that domain space
*
* This is a slow path, for use by generic code. It's expected that an
* irq controller implementation directly calls the appropriate low level
* mapping function.
*/
unsigned
int
irq_find_mapping
(
struct
irq_domain
*
domain
,
irq_hw_number_t
hwirq
)
{
unsigned
int
i
;
unsigned
int
hint
=
hwirq
%
irq_virq_count
;
/* Look for default domain if nececssary */
if
(
domain
==
NULL
)
domain
=
irq_default_domain
;
if
(
domain
==
NULL
)
return
0
;
/* legacy -> bail early */
if
(
domain
->
revmap_type
==
IRQ_DOMAIN_MAP_LEGACY
)
return
irq_domain_legacy_revmap
(
domain
,
hwirq
);
/* Slow path does a linear search of the map */
if
(
hint
==
0
)
hint
=
1
;
i
=
hint
;
do
{
struct
irq_data
*
data
=
irq_get_irq_data
(
i
);
if
(
data
&&
(
data
->
domain
==
domain
)
&&
(
data
->
hwirq
==
hwirq
))
return
i
;
i
++
;
if
(
i
>=
irq_virq_count
)
i
=
1
;
}
while
(
i
!=
hint
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_find_mapping
);
/**
* irq_radix_revmap_lookup() - Find a linux irq from a hw irq number.
* @domain: domain owning this hardware interrupt
* @hwirq: hardware irq number in that domain space
*
*
Calling this function indicates the caller no longer needs a reference to
*
the linux irq number returned by a prior call to irq_create_of_mapping().
*
This is a fast path, for use by irq controller code that uses radix tree
*
revmaps
*/
void
irq_dispose_mapping
(
unsigned
int
irq
)
unsigned
int
irq_radix_revmap_lookup
(
struct
irq_domain
*
domain
,
irq_hw_number_t
hwirq
)
{
struct
irq_data
*
irq_data
;
if
(
WARN_ON_ONCE
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_TREE
))
return
irq_find_mapping
(
domain
,
hwirq
);
/*
* Freeing an irq can delete nodes along the path to
* do the lookup via call_rcu.
*/
rcu_read_lock
();
irq_data
=
radix_tree_lookup
(
&
domain
->
revmap_data
.
tree
,
hwirq
);
rcu_read_unlock
();
/*
* nothing yet; will be filled when support for dynamic allocation of
* irq_descs is added to irq_domain
* If found in radix tree, then fine.
* Else fallback to linear lookup - this should not happen in practice
* as it means that we failed to insert the node in the radix tree.
*/
return
irq_data
?
irq_data
->
irq
:
irq_find_mapping
(
domain
,
hwirq
);
}
EXPORT_SYMBOL_GPL
(
irq_dispose_mapping
);
int
irq_domain_simple_dt_translate
(
struct
irq_domain
*
d
,
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
)
/**
* irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
* @domain: domain owning this hardware interrupt
* @virq: linux irq number
* @hwirq: hardware irq number in that domain space
*
* This is for use by irq controllers that use a radix tree reverse
* mapping for fast lookup.
*/
void
irq_radix_revmap_insert
(
struct
irq_domain
*
domain
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
{
if
(
d
->
of_node
!=
controller
)
return
-
EINVAL
;
if
(
intsize
<
1
)
return
-
EINVAL
;
if
(
d
->
nr_irq
&&
((
intspec
[
0
]
<
d
->
hwirq_base
)
||
(
intspec
[
0
]
>=
d
->
hwirq_base
+
d
->
nr_irq
)))
return
-
EINVAL
;
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
if
(
WARN_ON
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_TREE
))
return
;
if
(
virq
)
{
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_insert
(
&
domain
->
revmap_data
.
tree
,
hwirq
,
irq_data
);
mutex_unlock
(
&
revmap_trees_mutex
);
}
}
/**
* irq_linear_revmap() - Find a linux irq from a hw irq number.
* @domain: domain owning this hardware interrupt
* @hwirq: hardware irq number in that domain space
*
* This is a fast path, for use by irq controller code that uses linear
* revmaps. It does fallback to the slow path if the revmap doesn't exist
* yet and will create the revmap entry with appropriate locking
*/
unsigned
int
irq_linear_revmap
(
struct
irq_domain
*
domain
,
irq_hw_number_t
hwirq
)
{
unsigned
int
*
revmap
;
if
(
WARN_ON_ONCE
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_LINEAR
))
return
irq_find_mapping
(
domain
,
hwirq
);
/* Check revmap bounds */
if
(
unlikely
(
hwirq
>=
domain
->
revmap_data
.
linear
.
size
))
return
irq_find_mapping
(
domain
,
hwirq
);
/* Check if revmap was allocated */
revmap
=
domain
->
revmap_data
.
linear
.
revmap
;
if
(
unlikely
(
revmap
==
NULL
))
return
irq_find_mapping
(
domain
,
hwirq
);
/* Fill up revmap with slow path if no mapping found */
if
(
unlikely
(
!
revmap
[
hwirq
]))
revmap
[
hwirq
]
=
irq_find_mapping
(
domain
,
hwirq
);
return
revmap
[
hwirq
];
}
#ifdef CONFIG_VIRQ_DEBUG
static
int
virq_debug_show
(
struct
seq_file
*
m
,
void
*
private
)
{
unsigned
long
flags
;
struct
irq_desc
*
desc
;
const
char
*
p
;
static
const
char
none
[]
=
"none"
;
void
*
data
;
int
i
;
seq_printf
(
m
,
"%-5s %-7s %-15s %-18s %s
\n
"
,
"virq"
,
"hwirq"
,
"chip name"
,
"chip data"
,
"domain name"
);
for
(
i
=
1
;
i
<
nr_irqs
;
i
++
)
{
desc
=
irq_to_desc
(
i
);
if
(
!
desc
)
continue
;
raw_spin_lock_irqsave
(
&
desc
->
lock
,
flags
);
if
(
desc
->
action
&&
desc
->
action
->
handler
)
{
struct
irq_chip
*
chip
;
seq_printf
(
m
,
"%5d "
,
i
);
seq_printf
(
m
,
"0x%05lx "
,
desc
->
irq_data
.
hwirq
);
chip
=
irq_desc_get_chip
(
desc
);
if
(
chip
&&
chip
->
name
)
p
=
chip
->
name
;
else
p
=
none
;
seq_printf
(
m
,
"%-15s "
,
p
);
data
=
irq_desc_get_chip_data
(
desc
);
seq_printf
(
m
,
"0x%16p "
,
data
);
if
(
desc
->
irq_data
.
domain
->
of_node
)
p
=
desc
->
irq_data
.
domain
->
of_node
->
full_name
;
else
p
=
none
;
seq_printf
(
m
,
"%s
\n
"
,
p
);
}
raw_spin_unlock_irqrestore
(
&
desc
->
lock
,
flags
);
}
return
0
;
}
static
int
virq_debug_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
virq_debug_show
,
inode
->
i_private
);
}
static
const
struct
file_operations
virq_debug_fops
=
{
.
open
=
virq_debug_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
__init
irq_debugfs_init
(
void
)
{
if
(
debugfs_create_file
(
"virq_mapping"
,
S_IRUGO
,
powerpc_debugfs_root
,
NULL
,
&
virq_debug_fops
)
==
NULL
)
return
-
ENOMEM
;
return
0
;
}
__initcall
(
irq_debugfs_init
);
#endif
/* CONFIG_VIRQ_DEBUG */
int
irq_domain_simple_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
irq_hw_number_t
hwirq
)
{
return
0
;
}
/**
* irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
*
* Device Tree IRQ specifier translation function which works with one cell
* bindings where the cell value maps directly to the hwirq number.
*/
int
irq_domain_xlate_onecell
(
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
=
intspec
[
0
];
*
out_type
=
IRQ_TYPE_NONE
;
if
(
intsize
>
1
)
*
out_type
=
intspec
[
1
]
&
IRQ_TYPE_SENSE_MASK
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_domain_xlate_onecell
);
/**
* irq_domain_create_simple() - Set up a 'simple' translation range
* irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings
*
* Device Tree IRQ specifier translation function which works with two cell
* bindings where the cell values map directly to the hwirq number
* and linux irq flags.
*/
void
irq_domain_add_simple
(
struct
device_node
*
controller
,
int
irq_base
)
int
irq_domain_xlate_twocell
(
struct
irq_domain
*
d
,
struct
device_node
*
ctrlr
,
const
u32
*
intspec
,
unsigned
int
intsize
,
irq_hw_number_t
*
out_hwirq
,
unsigned
int
*
out_type
)
{
struct
irq_domain
*
domain
;
domain
=
kzalloc
(
sizeof
(
*
domain
),
GFP_KERNEL
)
;
if
(
!
domain
)
{
WARN_ON
(
1
)
;
return
;
}
if
(
WARN_ON
(
intsize
<
2
))
return
-
EINVAL
;
*
out_hwirq
=
intspec
[
0
]
;
*
out_type
=
intspec
[
1
]
&
IRQ_TYPE_SENSE_MASK
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_domain_xlate_twocell
);
domain
->
irq_base
=
irq_base
;
domain
->
of_node
=
of_node_get
(
controller
);
domain
->
ops
=
&
irq_domain_simple_ops
;
irq_domain_add
(
domain
);
/**
* irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings
*
* Device Tree IRQ specifier translation function which works with either one
* or two cell bindings where the cell values map directly to the hwirq number
* and linux irq flags.
*
* Note: don't use this function unless your interrupt controller explicitly
* supports both one and two cell bindings. For the majority of controllers
* the _onecell() or _twocell() variants above should be used.
*/
int
irq_domain_xlate_onetwocell
(
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
=
intspec
[
0
];
*
out_type
=
(
intsize
>
1
)
?
intspec
[
1
]
:
IRQ_TYPE_NONE
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_domain_
add_simple
);
EXPORT_SYMBOL_GPL
(
irq_domain_
xlate_onetwocell
);
const
struct
irq_domain_ops
irq_domain_simple_ops
=
{
.
map
=
irq_domain_simple_map
,
.
xlate
=
irq_domain_xlate_onetwocell
,
};
EXPORT_SYMBOL_GPL
(
irq_domain_simple_ops
);
#ifdef CONFIG_OF_IRQ
void
irq_domain_generate_simple
(
const
struct
of_device_id
*
match
,
u64
phys_base
,
unsigned
int
irq_start
)
{
struct
device_node
*
node
;
pr_
info
(
"looking for phys_base=%llx, irq_start=%i
\n
"
,
pr_
debug
(
"looking for phys_base=%llx, irq_start=%i
\n
"
,
(
unsigned
long
long
)
phys_base
,
(
int
)
irq_start
);
node
=
of_find_matching_node_by_address
(
NULL
,
match
,
phys_base
);
if
(
node
)
irq_domain_add_simple
(
node
,
irq_start
);
else
pr_info
(
"no node found
\n
"
);
irq_domain_add_legacy
(
node
,
32
,
irq_start
,
0
,
&
irq_domain_simple_ops
,
NULL
);
}
EXPORT_SYMBOL_GPL
(
irq_domain_generate_simple
);
#endif
/* CONFIG_OF_IRQ */
struct
irq_domain_ops
irq_domain_simple_ops
=
{
#ifdef CONFIG_OF_IRQ
.
dt_translate
=
irq_domain_simple_dt_translate
,
#endif
/* CONFIG_OF_IRQ */
};
EXPORT_SYMBOL_GPL
(
irq_domain_simple_ops
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment