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
Kirill Smelkov
linux
Commits
5e8bd41a
Commit
5e8bd41a
authored
Jun 10, 2013
by
Grant Likely
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'tip/irq/for-arm' into irqdomain/next
parents
317ddd25
e8bd834f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
316 additions
and
50 deletions
+316
-50
include/linux/irq.h
include/linux/irq.h
+46
-1
include/linux/irqdomain.h
include/linux/irqdomain.h
+12
-0
kernel/irq/generic-chip.c
kernel/irq/generic-chip.c
+258
-43
kernel/irq/irqdomain.c
kernel/irq/irqdomain.c
+0
-6
No files found.
include/linux/irq.h
View file @
5e8bd41a
...
...
@@ -119,6 +119,7 @@ struct irq_domain;
/**
* struct irq_data - per irq and irq chip data passed down to chip functions
* @mask: precomputed bitmask for accessing the chip registers
* @irq: interrupt number
* @hwirq: hardware interrupt number, local to the interrupt domain
* @node: node index useful for balancing
...
...
@@ -138,6 +139,7 @@ struct irq_domain;
* irq_data.
*/
struct
irq_data
{
u32
mask
;
unsigned
int
irq
;
unsigned
long
hwirq
;
unsigned
int
node
;
...
...
@@ -294,6 +296,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* @irq_suspend: function called from core code on suspend once per chip
* @irq_resume: function called from core code on resume once per chip
* @irq_pm_shutdown: function called from core code on shutdown once per chip
* @irq_calc_mask: Optional function to set irq_data.mask for special cases
* @irq_print_chip: optional to print special chip info in show_interrupts
* @flags: chip specific flags
*/
...
...
@@ -325,6 +328,8 @@ struct irq_chip {
void
(
*
irq_resume
)(
struct
irq_data
*
data
);
void
(
*
irq_pm_shutdown
)(
struct
irq_data
*
data
);
void
(
*
irq_calc_mask
)(
struct
irq_data
*
data
);
void
(
*
irq_print_chip
)(
struct
irq_data
*
data
,
struct
seq_file
*
p
);
unsigned
long
flags
;
...
...
@@ -644,6 +649,8 @@ struct irq_chip_regs {
* @regs: Register offsets for this chip
* @handler: Flow handler associated with this chip
* @type: Chip can handle these flow types
* @mask_cache_priv: Cached mask register private to the chip type
* @mask_cache: Pointer to cached mask register
*
* A irq_generic_chip can have several instances of irq_chip_type when
* it requires different functions and register offsets for different
...
...
@@ -654,6 +661,8 @@ struct irq_chip_type {
struct
irq_chip_regs
regs
;
irq_flow_handler_t
handler
;
u32
type
;
u32
mask_cache_priv
;
u32
*
mask_cache
;
};
/**
...
...
@@ -662,13 +671,16 @@ struct irq_chip_type {
* @reg_base: Register base address (virtual)
* @irq_base: Interrupt base nr for this chip
* @irq_cnt: Number of interrupts handled by this chip
* @mask_cache: Cached mask register
* @mask_cache: Cached mask register
shared between all chip types
* @type_cache: Cached type register
* @polarity_cache: Cached polarity register
* @wake_enabled: Interrupt can wakeup from suspend
* @wake_active: Interrupt is marked as an wakeup from suspend source
* @num_ct: Number of available irq_chip_type instances (usually 1)
* @private: Private data for non generic chip callbacks
* @installed: bitfield to denote installed interrupts
* @unused: bitfield to denote unused interrupts
* @domain: irq domain pointer
* @list: List head for keeping track of instances
* @chip_types: Array of interrupt irq_chip_types
*
...
...
@@ -690,6 +702,9 @@ struct irq_chip_generic {
u32
wake_active
;
unsigned
int
num_ct
;
void
*
private
;
unsigned
long
installed
;
unsigned
long
unused
;
struct
irq_domain
*
domain
;
struct
list_head
list
;
struct
irq_chip_type
chip_types
[
0
];
};
...
...
@@ -700,10 +715,32 @@ struct irq_chip_generic {
* @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for
* irq chips which need to call irq_set_wake() on
* the parent irq. Usually GPIO implementations
* @IRQ_GC_MASK_CACHE_PER_TYPE: Mask cache is chip type private
* @IRQ_GC_NO_MASK: Do not calculate irq_data->mask
*/
enum
irq_gc_flags
{
IRQ_GC_INIT_MASK_CACHE
=
1
<<
0
,
IRQ_GC_INIT_NESTED_LOCK
=
1
<<
1
,
IRQ_GC_MASK_CACHE_PER_TYPE
=
1
<<
2
,
IRQ_GC_NO_MASK
=
1
<<
3
,
};
/*
* struct irq_domain_chip_generic - Generic irq chip data structure for irq domains
* @irqs_per_chip: Number of interrupts per chip
* @num_chips: Number of chips
* @irq_flags_to_set: IRQ* flags to set on irq setup
* @irq_flags_to_clear: IRQ* flags to clear on irq setup
* @gc_flags: Generic chip specific setup flags
* @gc: Array of pointers to generic interrupt chips
*/
struct
irq_domain_chip_generic
{
unsigned
int
irqs_per_chip
;
unsigned
int
num_chips
;
unsigned
int
irq_flags_to_clear
;
unsigned
int
irq_flags_to_set
;
enum
irq_gc_flags
gc_flags
;
struct
irq_chip_generic
*
gc
[
0
];
};
/* Generic chip callback functions */
...
...
@@ -729,6 +766,14 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type);
void
irq_remove_generic_chip
(
struct
irq_chip_generic
*
gc
,
u32
msk
,
unsigned
int
clr
,
unsigned
int
set
);
struct
irq_chip_generic
*
irq_get_domain_generic_chip
(
struct
irq_domain
*
d
,
unsigned
int
hw_irq
);
int
irq_alloc_domain_generic_chips
(
struct
irq_domain
*
d
,
int
irqs_per_chip
,
int
num_ct
,
const
char
*
name
,
irq_flow_handler_t
handler
,
unsigned
int
clr
,
unsigned
int
set
,
enum
irq_gc_flags
flags
);
static
inline
struct
irq_chip_type
*
irq_data_get_chip_type
(
struct
irq_data
*
d
)
{
return
container_of
(
d
->
chip
,
struct
irq_chip_type
,
chip
);
...
...
include/linux/irqdomain.h
View file @
5e8bd41a
...
...
@@ -66,6 +66,10 @@ struct irq_domain_ops {
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
);
};
extern
struct
irq_domain_ops
irq_generic_chip_ops
;
struct
irq_domain_chip_generic
;
/**
* struct irq_domain - Hardware interrupt number translation object
* @link: Element in global irq_domain list.
...
...
@@ -109,8 +113,16 @@ struct irq_domain {
/* Optional device node pointer */
struct
device_node
*
of_node
;
/* Optional pointer to generic interrupt chips */
struct
irq_domain_chip_generic
*
gc
;
};
#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 */
#ifdef CONFIG_IRQ_DOMAIN
struct
irq_domain
*
irq_domain_add_simple
(
struct
device_node
*
of_node
,
unsigned
int
size
,
...
...
kernel/irq/generic-chip.c
View file @
5e8bd41a
...
...
@@ -7,6 +7,7 @@
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/syscore_ops.h>
...
...
@@ -16,11 +17,6 @@
static
LIST_HEAD
(
gc_list
);
static
DEFINE_RAW_SPINLOCK
(
gc_lock
);
static
inline
struct
irq_chip_regs
*
cur_regs
(
struct
irq_data
*
d
)
{
return
&
container_of
(
d
->
chip
,
struct
irq_chip_type
,
chip
)
->
regs
;
}
/**
* irq_gc_noop - NOOP function
* @d: irq_data
...
...
@@ -39,11 +35,12 @@ void irq_gc_noop(struct irq_data *d)
void
irq_gc_mask_disable_reg
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
disable
);
gc
->
mask_cache
&=
~
mask
;
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
disable
);
*
ct
->
mask_cache
&=
~
mask
;
irq_gc_unlock
(
gc
);
}
...
...
@@ -57,11 +54,12 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
void
irq_gc_mask_set_bit
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
gc
->
mask_cache
|=
mask
;
irq_reg_writel
(
gc
->
mask_cache
,
gc
->
reg_base
+
cur_regs
(
d
)
->
mask
);
*
ct
->
mask_cache
|=
mask
;
irq_reg_writel
(
*
ct
->
mask_cache
,
gc
->
reg_base
+
ct
->
regs
.
mask
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -75,11 +73,12 @@ void irq_gc_mask_set_bit(struct irq_data *d)
void
irq_gc_mask_clr_bit
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
gc
->
mask_cache
&=
~
mask
;
irq_reg_writel
(
gc
->
mask_cache
,
gc
->
reg_base
+
cur_regs
(
d
)
->
mask
);
*
ct
->
mask_cache
&=
~
mask
;
irq_reg_writel
(
*
ct
->
mask_cache
,
gc
->
reg_base
+
ct
->
regs
.
mask
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -93,11 +92,12 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
void
irq_gc_unmask_enable_reg
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
enable
);
gc
->
mask_cache
|=
mask
;
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
enable
);
*
ct
->
mask_cache
|=
mask
;
irq_gc_unlock
(
gc
);
}
...
...
@@ -108,10 +108,11 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
void
irq_gc_ack_set_bit
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
ack
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
ack
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -122,10 +123,11 @@ void irq_gc_ack_set_bit(struct irq_data *d)
void
irq_gc_ack_clr_bit
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
~
(
1
<<
(
d
->
irq
-
gc
->
irq_base
));
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
~
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
ack
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
ack
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -136,11 +138,12 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
void
irq_gc_mask_disable_reg_and_ack
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
mask
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
ack
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
mask
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
ack
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -151,10 +154,11 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
void
irq_gc_eoi
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
);
struct
irq_chip_type
*
ct
=
irq_data_get_chip_type
(
d
);
u32
mask
=
d
->
mask
;
irq_gc_lock
(
gc
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
ur_regs
(
d
)
->
eoi
);
irq_reg_writel
(
mask
,
gc
->
reg_base
+
c
t
->
regs
.
eoi
);
irq_gc_unlock
(
gc
);
}
...
...
@@ -169,7 +173,7 @@ void irq_gc_eoi(struct irq_data *d)
int
irq_gc_set_wake
(
struct
irq_data
*
d
,
unsigned
int
on
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
u32
mask
=
1
<<
(
d
->
irq
-
gc
->
irq_base
)
;
u32
mask
=
d
->
mask
;
if
(
!
(
mask
&
gc
->
wake_enabled
))
return
-
EINVAL
;
...
...
@@ -183,6 +187,19 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on)
return
0
;
}
static
void
irq_init_generic_chip
(
struct
irq_chip_generic
*
gc
,
const
char
*
name
,
int
num_ct
,
unsigned
int
irq_base
,
void
__iomem
*
reg_base
,
irq_flow_handler_t
handler
)
{
raw_spin_lock_init
(
&
gc
->
lock
);
gc
->
num_ct
=
num_ct
;
gc
->
irq_base
=
irq_base
;
gc
->
reg_base
=
reg_base
;
gc
->
chip_types
->
chip
.
name
=
name
;
gc
->
chip_types
->
handler
=
handler
;
}
/**
* irq_alloc_generic_chip - Allocate a generic chip and initialize it
* @name: Name of the irq chip
...
...
@@ -203,23 +220,184 @@ irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
gc
=
kzalloc
(
sz
,
GFP_KERNEL
);
if
(
gc
)
{
raw_spin_lock_init
(
&
gc
->
lock
);
gc
->
num_ct
=
num_ct
;
gc
->
irq_base
=
irq_base
;
gc
->
reg_base
=
reg_base
;
gc
->
chip_types
->
chip
.
name
=
name
;
gc
->
chip_types
->
handler
=
handler
;
irq_init_generic_chip
(
gc
,
name
,
num_ct
,
irq_base
,
reg_base
,
handler
);
}
return
gc
;
}
EXPORT_SYMBOL_GPL
(
irq_alloc_generic_chip
);
static
void
irq_gc_init_mask_cache
(
struct
irq_chip_generic
*
gc
,
enum
irq_gc_flags
flags
)
{
struct
irq_chip_type
*
ct
=
gc
->
chip_types
;
u32
*
mskptr
=
&
gc
->
mask_cache
,
mskreg
=
ct
->
regs
.
mask
;
int
i
;
for
(
i
=
0
;
i
<
gc
->
num_ct
;
i
++
)
{
if
(
flags
&
IRQ_GC_MASK_CACHE_PER_TYPE
)
{
mskptr
=
&
ct
[
i
].
mask_cache_priv
;
mskreg
=
ct
[
i
].
regs
.
mask
;
}
ct
[
i
].
mask_cache
=
mskptr
;
if
(
flags
&
IRQ_GC_INIT_MASK_CACHE
)
*
mskptr
=
irq_reg_readl
(
gc
->
reg_base
+
mskreg
);
}
}
/**
* irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
* @d: irq domain for which to allocate chips
* @irqs_per_chip: Number of interrupts each chip handles
* @num_ct: Number of irq_chip_type instances associated with this
* @name: Name of the irq chip
* @handler: Default flow handler associated with these chips
* @clr: IRQ_* bits to clear in the mapping function
* @set: IRQ_* bits to set in the mapping function
*/
int
irq_alloc_domain_generic_chips
(
struct
irq_domain
*
d
,
int
irqs_per_chip
,
int
num_ct
,
const
char
*
name
,
irq_flow_handler_t
handler
,
unsigned
int
clr
,
unsigned
int
set
,
enum
irq_gc_flags
gcflags
)
{
struct
irq_domain_chip_generic
*
dgc
;
struct
irq_chip_generic
*
gc
;
int
numchips
,
sz
,
i
;
unsigned
long
flags
;
void
*
tmp
;
if
(
d
->
gc
)
return
-
EBUSY
;
if
(
d
->
revmap_type
!=
IRQ_DOMAIN_MAP_LINEAR
)
return
-
EINVAL
;
numchips
=
d
->
revmap_data
.
linear
.
size
/
irqs_per_chip
;
if
(
!
numchips
)
return
-
EINVAL
;
/* Allocate a pointer, generic chip and chiptypes for each chip */
sz
=
sizeof
(
*
dgc
)
+
numchips
*
sizeof
(
gc
);
sz
+=
numchips
*
(
sizeof
(
*
gc
)
+
num_ct
*
sizeof
(
struct
irq_chip_type
));
tmp
=
dgc
=
kzalloc
(
sz
,
GFP_KERNEL
);
if
(
!
dgc
)
return
-
ENOMEM
;
dgc
->
irqs_per_chip
=
irqs_per_chip
;
dgc
->
num_chips
=
numchips
;
dgc
->
irq_flags_to_set
=
set
;
dgc
->
irq_flags_to_clear
=
clr
;
dgc
->
gc_flags
=
gcflags
;
d
->
gc
=
dgc
;
/* Calc pointer to the first generic chip */
tmp
+=
sizeof
(
*
dgc
)
+
numchips
*
sizeof
(
gc
);
for
(
i
=
0
;
i
<
numchips
;
i
++
)
{
/* Store the pointer to the generic chip */
dgc
->
gc
[
i
]
=
gc
=
tmp
;
irq_init_generic_chip
(
gc
,
name
,
num_ct
,
i
*
irqs_per_chip
,
NULL
,
handler
);
gc
->
domain
=
d
;
raw_spin_lock_irqsave
(
&
gc_lock
,
flags
);
list_add_tail
(
&
gc
->
list
,
&
gc_list
);
raw_spin_unlock_irqrestore
(
&
gc_lock
,
flags
);
/* Calc pointer to the next generic chip */
tmp
+=
sizeof
(
*
gc
)
+
num_ct
*
sizeof
(
struct
irq_chip_type
);
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_alloc_domain_generic_chips
);
/**
* irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq
* @d: irq domain pointer
* @hw_irq: Hardware interrupt number
*/
struct
irq_chip_generic
*
irq_get_domain_generic_chip
(
struct
irq_domain
*
d
,
unsigned
int
hw_irq
)
{
struct
irq_domain_chip_generic
*
dgc
=
d
->
gc
;
int
idx
;
if
(
!
dgc
)
return
NULL
;
idx
=
hw_irq
/
dgc
->
irqs_per_chip
;
if
(
idx
>=
dgc
->
num_chips
)
return
NULL
;
return
dgc
->
gc
[
idx
];
}
EXPORT_SYMBOL_GPL
(
irq_get_domain_generic_chip
);
/*
* Separate lockdep class for interrupt chip which can nest irq_desc
* lock.
*/
static
struct
lock_class_key
irq_nested_lock_class
;
/**
* irq_map_generic_chip - Map a generic chip for an irq domain
*/
static
int
irq_map_generic_chip
(
struct
irq_domain
*
d
,
unsigned
int
virq
,
irq_hw_number_t
hw_irq
)
{
struct
irq_data
*
data
=
irq_get_irq_data
(
virq
);
struct
irq_domain_chip_generic
*
dgc
=
d
->
gc
;
struct
irq_chip_generic
*
gc
;
struct
irq_chip_type
*
ct
;
struct
irq_chip
*
chip
;
unsigned
long
flags
;
int
idx
;
if
(
!
d
->
gc
)
return
-
ENODEV
;
idx
=
hw_irq
/
dgc
->
irqs_per_chip
;
if
(
idx
>=
dgc
->
num_chips
)
return
-
EINVAL
;
gc
=
dgc
->
gc
[
idx
];
idx
=
hw_irq
%
dgc
->
irqs_per_chip
;
if
(
test_bit
(
idx
,
&
gc
->
unused
))
return
-
ENOTSUPP
;
if
(
test_bit
(
idx
,
&
gc
->
installed
))
return
-
EBUSY
;
ct
=
gc
->
chip_types
;
chip
=
&
ct
->
chip
;
/* We only init the cache for the first mapping of a generic chip */
if
(
!
gc
->
installed
)
{
raw_spin_lock_irqsave
(
&
gc
->
lock
,
flags
);
irq_gc_init_mask_cache
(
gc
,
dgc
->
gc_flags
);
raw_spin_unlock_irqrestore
(
&
gc
->
lock
,
flags
);
}
/* Mark the interrupt as installed */
set_bit
(
idx
,
&
gc
->
installed
);
if
(
dgc
->
gc_flags
&
IRQ_GC_INIT_NESTED_LOCK
)
irq_set_lockdep_class
(
virq
,
&
irq_nested_lock_class
);
if
(
chip
->
irq_calc_mask
)
chip
->
irq_calc_mask
(
data
);
else
data
->
mask
=
1
<<
idx
;
irq_set_chip_and_handler
(
virq
,
chip
,
ct
->
handler
);
irq_set_chip_data
(
virq
,
gc
);
irq_modify_status
(
virq
,
dgc
->
irq_flags_to_clear
,
dgc
->
irq_flags_to_set
);
return
0
;
}
struct
irq_domain_ops
irq_generic_chip_ops
=
{
.
map
=
irq_map_generic_chip
,
.
xlate
=
irq_domain_xlate_onetwocell
,
};
EXPORT_SYMBOL_GPL
(
irq_generic_chip_ops
);
/**
* irq_setup_generic_chip - Setup a range of interrupts with a generic chip
* @gc: Generic irq chip holding all data
...
...
@@ -237,15 +415,14 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
unsigned
int
set
)
{
struct
irq_chip_type
*
ct
=
gc
->
chip_types
;
struct
irq_chip
*
chip
=
&
ct
->
chip
;
unsigned
int
i
;
raw_spin_lock
(
&
gc_lock
);
list_add_tail
(
&
gc
->
list
,
&
gc_list
);
raw_spin_unlock
(
&
gc_lock
);
/* Init mask cache ? */
if
(
flags
&
IRQ_GC_INIT_MASK_CACHE
)
gc
->
mask_cache
=
irq_reg_readl
(
gc
->
reg_base
+
ct
->
regs
.
mask
);
irq_gc_init_mask_cache
(
gc
,
flags
);
for
(
i
=
gc
->
irq_base
;
msk
;
msk
>>=
1
,
i
++
)
{
if
(
!
(
msk
&
0x01
))
...
...
@@ -254,7 +431,15 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
if
(
flags
&
IRQ_GC_INIT_NESTED_LOCK
)
irq_set_lockdep_class
(
i
,
&
irq_nested_lock_class
);
irq_set_chip_and_handler
(
i
,
&
ct
->
chip
,
ct
->
handler
);
if
(
!
(
flags
&
IRQ_GC_NO_MASK
))
{
struct
irq_data
*
d
=
irq_get_irq_data
(
i
);
if
(
chip
->
irq_calc_mask
)
chip
->
irq_calc_mask
(
d
);
else
d
->
mask
=
1
<<
(
i
-
gc
->
irq_base
);
}
irq_set_chip_and_handler
(
i
,
chip
,
ct
->
handler
);
irq_set_chip_data
(
i
,
gc
);
irq_modify_status
(
i
,
clr
,
set
);
}
...
...
@@ -317,6 +502,24 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
}
EXPORT_SYMBOL_GPL
(
irq_remove_generic_chip
);
static
struct
irq_data
*
irq_gc_get_irq_data
(
struct
irq_chip_generic
*
gc
)
{
unsigned
int
virq
;
if
(
!
gc
->
domain
)
return
irq_get_irq_data
(
gc
->
irq_base
);
/*
* We don't know which of the irqs has been actually
* installed. Use the first one.
*/
if
(
!
gc
->
installed
)
return
NULL
;
virq
=
irq_find_mapping
(
gc
->
domain
,
gc
->
irq_base
+
__ffs
(
gc
->
installed
));
return
virq
?
irq_get_irq_data
(
virq
)
:
NULL
;
}
#ifdef CONFIG_PM
static
int
irq_gc_suspend
(
void
)
{
...
...
@@ -325,8 +528,12 @@ static int irq_gc_suspend(void)
list_for_each_entry
(
gc
,
&
gc_list
,
list
)
{
struct
irq_chip_type
*
ct
=
gc
->
chip_types
;
if
(
ct
->
chip
.
irq_suspend
)
ct
->
chip
.
irq_suspend
(
irq_get_irq_data
(
gc
->
irq_base
));
if
(
ct
->
chip
.
irq_suspend
)
{
struct
irq_data
*
data
=
irq_gc_get_irq_data
(
gc
);
if
(
data
)
ct
->
chip
.
irq_suspend
(
data
);
}
}
return
0
;
}
...
...
@@ -338,8 +545,12 @@ static void irq_gc_resume(void)
list_for_each_entry
(
gc
,
&
gc_list
,
list
)
{
struct
irq_chip_type
*
ct
=
gc
->
chip_types
;
if
(
ct
->
chip
.
irq_resume
)
ct
->
chip
.
irq_resume
(
irq_get_irq_data
(
gc
->
irq_base
));
if
(
ct
->
chip
.
irq_resume
)
{
struct
irq_data
*
data
=
irq_gc_get_irq_data
(
gc
);
if
(
data
)
ct
->
chip
.
irq_resume
(
data
);
}
}
}
#else
...
...
@@ -354,8 +565,12 @@ static void irq_gc_shutdown(void)
list_for_each_entry
(
gc
,
&
gc_list
,
list
)
{
struct
irq_chip_type
*
ct
=
gc
->
chip_types
;
if
(
ct
->
chip
.
irq_pm_shutdown
)
ct
->
chip
.
irq_pm_shutdown
(
irq_get_irq_data
(
gc
->
irq_base
));
if
(
ct
->
chip
.
irq_pm_shutdown
)
{
struct
irq_data
*
data
=
irq_gc_get_irq_data
(
gc
);
if
(
data
)
ct
->
chip
.
irq_pm_shutdown
(
data
);
}
}
}
...
...
kernel/irq/irqdomain.c
View file @
5e8bd41a
...
...
@@ -16,12 +16,6 @@
#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
);
...
...
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