Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
f3877047
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
f3877047
编写于
8月 01, 2012
作者:
P
Paul Mundt
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'common/irqdomain' into sh-latest
上级
1ca8fe38
1d6a21b0
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
333 addition
and
174 deletion
+333
-174
Documentation/IRQ-domain.txt
Documentation/IRQ-domain.txt
+5
-0
arch/powerpc/sysdev/xics/icp-hv.c
arch/powerpc/sysdev/xics/icp-hv.c
+1
-1
arch/powerpc/sysdev/xics/icp-native.c
arch/powerpc/sysdev/xics/icp-native.c
+1
-1
arch/powerpc/sysdev/xics/xics-common.c
arch/powerpc/sysdev/xics/xics-common.c
+0
-3
drivers/sh/intc/Kconfig
drivers/sh/intc/Kconfig
+4
-0
drivers/sh/intc/Makefile
drivers/sh/intc/Makefile
+1
-1
drivers/sh/intc/core.c
drivers/sh/intc/core.c
+7
-4
drivers/sh/intc/internals.h
drivers/sh/intc/internals.h
+5
-0
drivers/sh/intc/irqdomain.c
drivers/sh/intc/irqdomain.c
+68
-0
include/linux/irqdomain.h
include/linux/irqdomain.h
+24
-4
include/linux/of.h
include/linux/of.h
+10
-5
kernel/irq/irqdomain.c
kernel/irq/irqdomain.c
+207
-155
未找到文件。
Documentation/IRQ-domain.txt
浏览文件 @
f3877047
...
...
@@ -93,6 +93,7 @@ Linux IRQ number into the hardware.
Most drivers cannot use this mapping.
==== Legacy ====
irq_domain_add_simple()
irq_domain_add_legacy()
irq_domain_add_legacy_isa()
...
...
@@ -115,3 +116,7 @@ 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.
Most users of legacy mappings should use irq_domain_add_simple() which
will use a legacy domain only if an IRQ range is supplied by the
system and will otherwise use a linear domain mapping.
arch/powerpc/sysdev/xics/icp-hv.c
浏览文件 @
f3877047
...
...
@@ -111,7 +111,7 @@ static unsigned int icp_hv_get_irq(void)
if
(
vec
==
XICS_IRQ_SPURIOUS
)
return
NO_IRQ
;
irq
=
irq_
radix_revmap_lookup
(
xics_host
,
vec
);
irq
=
irq_
find_mapping
(
xics_host
,
vec
);
if
(
likely
(
irq
!=
NO_IRQ
))
{
xics_push_cppr
(
vec
);
return
irq
;
...
...
arch/powerpc/sysdev/xics/icp-native.c
浏览文件 @
f3877047
...
...
@@ -119,7 +119,7 @@ static unsigned int icp_native_get_irq(void)
if
(
vec
==
XICS_IRQ_SPURIOUS
)
return
NO_IRQ
;
irq
=
irq_
radix_revmap_lookup
(
xics_host
,
vec
);
irq
=
irq_
find_mapping
(
xics_host
,
vec
);
if
(
likely
(
irq
!=
NO_IRQ
))
{
xics_push_cppr
(
vec
);
return
irq
;
...
...
arch/powerpc/sysdev/xics/xics-common.c
浏览文件 @
f3877047
...
...
@@ -329,9 +329,6 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq,
pr_devel
(
"xics: map virq %d, hwirq 0x%lx
\n
"
,
virq
,
hw
);
/* Insert the interrupt mapping into the radix tree for fast lookup */
irq_radix_revmap_insert
(
xics_host
,
virq
,
hw
);
/* They aren't all level sensitive but we just don't really know */
irq_set_status_flags
(
virq
,
IRQ_LEVEL
);
...
...
drivers/sh/intc/Kconfig
浏览文件 @
f3877047
config SH_INTC
def_bool y
select IRQ_DOMAIN
comment "Interrupt controller options"
config INTC_USERIMASK
...
...
drivers/sh/intc/Makefile
浏览文件 @
f3877047
obj-y
:=
access.o chip.o core.o handle.o virq.o
obj-y
:=
access.o chip.o core.o handle.o
irqdomain.o
virq.o
obj-$(CONFIG_INTC_BALANCING)
+=
balancing.o
obj-$(CONFIG_INTC_USERIMASK)
+=
userimask.o
...
...
drivers/sh/intc/core.c
浏览文件 @
f3877047
...
...
@@ -25,6 +25,7 @@
#include <linux/stat.h>
#include <linux/interrupt.h>
#include <linux/sh_intc.h>
#include <linux/irqdomain.h>
#include <linux/device.h>
#include <linux/syscore_ops.h>
#include <linux/list.h>
...
...
@@ -310,6 +311,8 @@ int __init register_intc_controller(struct intc_desc *desc)
BUG_ON
(
k
>
256
);
/* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
intc_irq_domain_init
(
d
,
hw
);
/* register the vectors one by one */
for
(
i
=
0
;
i
<
hw
->
nr_vectors
;
i
++
)
{
struct
intc_vect
*
vect
=
hw
->
vectors
+
i
;
...
...
@@ -319,8 +322,8 @@ int __init register_intc_controller(struct intc_desc *desc)
if
(
!
vect
->
enum_id
)
continue
;
res
=
irq_
alloc_desc_at
(
irq
,
numa_node_id
()
);
if
(
res
!=
irq
&&
res
!=
-
EEXIST
)
{
res
=
irq_
create_identity_mapping
(
d
->
domain
,
irq
);
if
(
unlikely
(
res
)
)
{
pr_err
(
"can't get irq_desc for %d
\n
"
,
irq
);
continue
;
}
...
...
@@ -340,8 +343,8 @@ int __init register_intc_controller(struct intc_desc *desc)
* IRQ support, each vector still needs to have
* its own backing irq_desc.
*/
res
=
irq_
alloc_desc_at
(
irq2
,
numa_node_id
()
);
if
(
res
!=
irq2
&&
res
!=
-
EEXIST
)
{
res
=
irq_
create_identity_mapping
(
d
->
domain
,
irq2
);
if
(
unlikely
(
res
)
)
{
pr_err
(
"can't get irq_desc for %d
\n
"
,
irq2
);
continue
;
}
...
...
drivers/sh/intc/internals.h
浏览文件 @
f3877047
#include <linux/sh_intc.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/types.h>
...
...
@@ -66,6 +67,7 @@ struct intc_desc_int {
unsigned
int
nr_sense
;
struct
intc_window
*
window
;
unsigned
int
nr_windows
;
struct
irq_domain
*
domain
;
struct
irq_chip
chip
;
bool
skip_suspend
;
};
...
...
@@ -187,6 +189,9 @@ unsigned long intc_get_ack_handle(unsigned int irq);
void
intc_enable_disable_enum
(
struct
intc_desc
*
desc
,
struct
intc_desc_int
*
d
,
intc_enum
enum_id
,
int
enable
);
/* irqdomain.c */
void
intc_irq_domain_init
(
struct
intc_desc_int
*
d
,
struct
intc_hw_desc
*
hw
);
/* virq.c */
void
intc_subgroup_init
(
struct
intc_desc
*
desc
,
struct
intc_desc_int
*
d
);
void
intc_irq_xlate_set
(
unsigned
int
irq
,
intc_enum
id
,
struct
intc_desc_int
*
d
);
...
...
drivers/sh/intc/irqdomain.c
0 → 100644
浏览文件 @
f3877047
/*
* IRQ domain support for SH INTC subsystem
*
* Copyright (C) 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#define pr_fmt(fmt) "intc: " fmt
#include <linux/irqdomain.h>
#include <linux/sh_intc.h>
#include <linux/export.h>
#include "internals.h"
/**
* intc_irq_domain_evt_xlate() - Generic xlate for vectored IRQs.
*
* This takes care of exception vector to hwirq translation through
* by way of evt2irq() translation.
*
* Note: For platforms that use a flat vector space without INTEVT this
* basically just mimics irq_domain_xlate_onecell() by way of a nopped
* out evt2irq() implementation.
*/
static
int
intc_evt_xlate
(
struct
irq_domain
*
d
,
struct
device_node
*
ctrlr
,
const
u32
*
intspec
,
unsigned
int
intsize
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
)
{
if
(
WARN_ON
(
intsize
<
1
))
return
-
EINVAL
;
*
out_hwirq
=
evt2irq
(
intspec
[
0
]);
*
out_type
=
IRQ_TYPE_NONE
;
return
0
;
}
static
const
struct
irq_domain_ops
intc_evt_ops
=
{
.
xlate
=
intc_evt_xlate
,
};
void
__init
intc_irq_domain_init
(
struct
intc_desc_int
*
d
,
struct
intc_hw_desc
*
hw
)
{
unsigned
int
irq_base
,
irq_end
;
/*
* Quick linear revmap check
*/
irq_base
=
evt2irq
(
hw
->
vectors
[
0
].
vect
);
irq_end
=
evt2irq
(
hw
->
vectors
[
hw
->
nr_vectors
-
1
].
vect
);
/*
* Linear domains have a hard-wired assertion that IRQs start at
* 0 in order to make some performance optimizations. Lamely
* restrict the linear case to these conditions here, taking the
* tree penalty for linear cases with non-zero hwirq bases.
*/
if
(
irq_base
==
0
&&
irq_end
==
(
irq_base
+
hw
->
nr_vectors
-
1
))
d
->
domain
=
irq_domain_add_linear
(
NULL
,
hw
->
nr_vectors
,
&
intc_evt_ops
,
NULL
);
else
d
->
domain
=
irq_domain_add_tree
(
NULL
,
&
intc_evt_ops
,
NULL
);
BUG_ON
(
!
d
->
domain
);
}
include/linux/irqdomain.h
浏览文件 @
f3877047
...
...
@@ -112,6 +112,11 @@ struct irq_domain {
};
#ifdef CONFIG_IRQ_DOMAIN
struct
irq_domain
*
irq_domain_add_simple
(
struct
device_node
*
of_node
,
unsigned
int
size
,
unsigned
int
first_irq
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
);
struct
irq_domain
*
irq_domain_add_legacy
(
struct
device_node
*
of_node
,
unsigned
int
size
,
unsigned
int
first_irq
,
...
...
@@ -144,16 +149,31 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
extern
void
irq_domain_remove
(
struct
irq_domain
*
host
);
extern
int
irq_domain_associate_many
(
struct
irq_domain
*
domain
,
unsigned
int
irq_base
,
irq_hw_number_t
hwirq_base
,
int
count
);
static
inline
int
irq_domain_associate
(
struct
irq_domain
*
domain
,
unsigned
int
irq
,
irq_hw_number_t
hwirq
)
{
return
irq_domain_associate_many
(
domain
,
irq
,
hwirq
,
1
);
}
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
int
irq_create_strict_mappings
(
struct
irq_domain
*
domain
,
unsigned
int
irq_base
,
irq_hw_number_t
hwirq_base
,
int
count
);
static
inline
int
irq_create_identity_mapping
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
)
{
return
irq_create_strict_mappings
(
host
,
hwirq
,
hwirq
,
1
);
}
extern
unsigned
int
irq_linear_revmap
(
struct
irq_domain
*
host
,
irq_hw_number_t
hwirq
);
...
...
include/linux/of.h
浏览文件 @
f3877047
...
...
@@ -21,6 +21,7 @@
#include <linux/kref.h>
#include <linux/mod_devicetable.h>
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
...
...
@@ -158,11 +159,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
#define OF_BAD_ADDR ((u64)-1)
#ifndef of_node_to_nid
static
inline
int
of_node_to_nid
(
struct
device_node
*
np
)
{
return
-
1
;
}
#define of_node_to_nid of_node_to_nid
#endif
static
inline
const
char
*
of_node_full_name
(
struct
device_node
*
np
)
{
return
np
?
np
->
full_name
:
"<no-node>"
;
...
...
@@ -427,6 +423,15 @@ static inline int of_machine_is_compatible(const char *compat)
while (0)
#endif
/* CONFIG_OF */
#ifndef of_node_to_nid
static
inline
int
of_node_to_nid
(
struct
device_node
*
np
)
{
return
numa_node_id
();
}
#define of_node_to_nid of_node_to_nid
#endif
/**
* of_property_read_bool - Findfrom a property
* @np: device node from which the property value is to be read.
...
...
kernel/irq/irqdomain.c
浏览文件 @
f3877047
...
...
@@ -10,6 +10,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/topology.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/smp.h>
...
...
@@ -45,7 +46,8 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
{
struct
irq_domain
*
domain
;
domain
=
kzalloc
(
sizeof
(
*
domain
),
GFP_KERNEL
);
domain
=
kzalloc_node
(
sizeof
(
*
domain
),
GFP_KERNEL
,
of_node_to_nid
(
of_node
));
if
(
WARN_ON
(
!
domain
))
return
NULL
;
...
...
@@ -137,6 +139,36 @@ static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
return
hwirq
-
first_hwirq
+
domain
->
revmap_data
.
legacy
.
first_irq
;
}
/**
* irq_domain_add_simple() - Allocate and register a simple irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
* @size: total number of irqs in mapping
* @first_irq: first number of irq block assigned to the domain
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*
* Allocates a legacy irq_domain if irq_base is positive or a linear
* domain otherwise.
*
* This is intended to implement the expected behaviour for most
* interrupt controllers which is that a linear mapping should
* normally be used unless the system requires a legacy mapping in
* order to support supplying interrupt numbers during non-DT
* registration of devices.
*/
struct
irq_domain
*
irq_domain_add_simple
(
struct
device_node
*
of_node
,
unsigned
int
size
,
unsigned
int
first_irq
,
const
struct
irq_domain_ops
*
ops
,
void
*
host_data
)
{
if
(
first_irq
>
0
)
return
irq_domain_add_legacy
(
of_node
,
size
,
first_irq
,
0
,
ops
,
host_data
);
else
return
irq_domain_add_linear
(
of_node
,
size
,
ops
,
host_data
);
}
/**
* irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
...
...
@@ -203,7 +235,8 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
* one can then use irq_create_mapping() to
* explicitly change them
*/
ops
->
map
(
domain
,
irq
,
hwirq
);
if
(
ops
->
map
)
ops
->
map
(
domain
,
irq
,
hwirq
);
/* Clear norequest flags */
irq_clear_status_flags
(
irq
,
IRQ_NOREQUEST
);
...
...
@@ -215,7 +248,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
EXPORT_SYMBOL_GPL
(
irq_domain_add_legacy
);
/**
* irq_domain_add_linear() - Allocate and register a l
egacy
revmap irq_domain.
* irq_domain_add_linear() - Allocate and register a l
inear
revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
* @size: Number of interrupts in the domain.
* @ops: map/unmap domain callbacks
...
...
@@ -229,7 +262,8 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
struct
irq_domain
*
domain
;
unsigned
int
*
revmap
;
revmap
=
kzalloc
(
sizeof
(
*
revmap
)
*
size
,
GFP_KERNEL
);
revmap
=
kzalloc_node
(
sizeof
(
*
revmap
)
*
size
,
GFP_KERNEL
,
of_node_to_nid
(
of_node
));
if
(
WARN_ON
(
!
revmap
))
return
NULL
;
...
...
@@ -330,24 +364,112 @@ void irq_set_default_host(struct irq_domain *domain)
}
EXPORT_SYMBOL_GPL
(
irq_set_default_host
);
static
int
irq_setup_virq
(
struct
irq_domain
*
domain
,
unsigned
int
virq
,
irq_hw_number_t
hwirq
)
static
void
irq_domain_disassociate_many
(
struct
irq_domain
*
domain
,
unsigned
int
irq_base
,
int
count
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
/*
* disassociate in reverse order;
* not strictly necessary, but nice for unwinding
*/
while
(
count
--
)
{
int
irq
=
irq_base
+
count
;
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
irq
);
irq_hw_number_t
hwirq
=
irq_data
->
hwirq
;
if
(
WARN_ON
(
!
irq_data
||
irq_data
->
domain
!=
domain
))
continue
;
irq_set_status_flags
(
irq
,
IRQ_NOREQUEST
);
/* remove chip and handler */
irq_set_chip_and_handler
(
irq
,
NULL
,
NULL
);
/* Make sure it's completed */
synchronize_irq
(
irq
);
/* Tell the PIC about it */
if
(
domain
->
ops
->
unmap
)
domain
->
ops
->
unmap
(
domain
,
irq
);
smp_mb
();
irq_data
->
hwirq
=
hwirq
;
irq_data
->
domain
=
domain
;
if
(
domain
->
ops
->
map
(
domain
,
virq
,
hwirq
))
{
pr_debug
(
"irq-%i==>hwirq-0x%lx mapping failed
\n
"
,
virq
,
hwirq
);
irq_data
->
domain
=
NULL
;
irq_data
->
hwirq
=
0
;
return
-
1
;
/* Clear reverse map */
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
;
}
}
}
int
irq_domain_associate_many
(
struct
irq_domain
*
domain
,
unsigned
int
irq_base
,
irq_hw_number_t
hwirq_base
,
int
count
)
{
unsigned
int
virq
=
irq_base
;
irq_hw_number_t
hwirq
=
hwirq_base
;
int
i
,
ret
;
pr_debug
(
"%s(%s, irqbase=%i, hwbase=%i, count=%i)
\n
"
,
__func__
,
of_node_full_name
(
domain
->
of_node
),
irq_base
,
(
int
)
hwirq_base
,
count
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
+
i
);
if
(
WARN
(
!
irq_data
,
"error: irq_desc not allocated; "
"irq=%i hwirq=0x%x
\n
"
,
virq
+
i
,
(
int
)
hwirq
+
i
))
return
-
EINVAL
;
if
(
WARN
(
irq_data
->
domain
,
"error: irq_desc already associated; "
"irq=%i hwirq=0x%x
\n
"
,
virq
+
i
,
(
int
)
hwirq
+
i
))
return
-
EINVAL
;
};
for
(
i
=
0
;
i
<
count
;
i
++
,
virq
++
,
hwirq
++
)
{
struct
irq_data
*
irq_data
=
irq_get_irq_data
(
virq
);
irq_data
->
hwirq
=
hwirq
;
irq_data
->
domain
=
domain
;
if
(
domain
->
ops
->
map
)
{
ret
=
domain
->
ops
->
map
(
domain
,
virq
,
hwirq
);
if
(
ret
!=
0
)
{
pr_err
(
"irq-%i==>hwirq-0x%lx mapping failed: %d
\n
"
,
virq
,
hwirq
,
ret
);
WARN_ON
(
1
);
irq_data
->
domain
=
NULL
;
irq_data
->
hwirq
=
0
;
goto
err_unmap
;
}
}
irq_clear_status_flags
(
virq
,
IRQ_NOREQUEST
);
switch
(
domain
->
revmap_type
)
{
case
IRQ_DOMAIN_MAP_LINEAR
:
if
(
hwirq
<
domain
->
revmap_data
.
linear
.
size
)
domain
->
revmap_data
.
linear
.
revmap
[
hwirq
]
=
virq
;
break
;
case
IRQ_DOMAIN_MAP_TREE
:
mutex_lock
(
&
revmap_trees_mutex
);
radix_tree_insert
(
&
domain
->
revmap_data
.
tree
,
hwirq
,
irq_data
);
mutex_unlock
(
&
revmap_trees_mutex
);
break
;
}
irq_clear_status_flags
(
virq
,
IRQ_NOREQUEST
);
}
return
0
;
err_unmap:
irq_domain_disassociate_many
(
domain
,
irq_base
,
i
);
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
irq_domain_associate_many
);
/**
* irq_create_direct_mapping() - Allocate an irq for direct mapping
...
...
@@ -364,10 +486,10 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
if
(
domain
==
NULL
)
domain
=
irq_default_domain
;
BUG_ON
(
domain
==
NULL
);
WARN_ON
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_NOMAP
)
;
if
(
WARN_ON
(
!
domain
||
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_NOMAP
))
return
0
;
virq
=
irq_alloc_desc_from
(
1
,
0
);
virq
=
irq_alloc_desc_from
(
1
,
of_node_to_nid
(
domain
->
of_node
)
);
if
(
!
virq
)
{
pr_debug
(
"create_direct virq allocation failed
\n
"
);
return
0
;
...
...
@@ -380,7 +502,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
}
pr_debug
(
"create_direct obtained virq %d
\n
"
,
virq
);
if
(
irq_
setup_virq
(
domain
,
virq
,
virq
))
{
if
(
irq_
domain_associate
(
domain
,
virq
,
virq
))
{
irq_free_desc
(
virq
);
return
0
;
}
...
...
@@ -433,17 +555,16 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
hint
=
hwirq
%
nr_irqs
;
if
(
hint
==
0
)
hint
++
;
virq
=
irq_alloc_desc_from
(
hint
,
0
);
virq
=
irq_alloc_desc_from
(
hint
,
of_node_to_nid
(
domain
->
of_node
)
);
if
(
virq
<=
0
)
virq
=
irq_alloc_desc_from
(
1
,
0
);
virq
=
irq_alloc_desc_from
(
1
,
of_node_to_nid
(
domain
->
of_node
)
);
if
(
virq
<=
0
)
{
pr_debug
(
"-> 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
);
if
(
irq_domain_associate
(
domain
,
virq
,
hwirq
))
{
irq_free_desc
(
virq
);
return
0
;
}
...
...
@@ -454,6 +575,44 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
}
EXPORT_SYMBOL_GPL
(
irq_create_mapping
);
/**
* irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
* @domain: domain owning the interrupt range
* @irq_base: beginning of linux IRQ range
* @hwirq_base: beginning of hardware IRQ range
* @count: Number of interrupts to map
*
* This routine is used for allocating and mapping a range of hardware
* irqs to linux irqs where the linux irq numbers are at pre-defined
* locations. For use by controllers that already have static mappings
* to insert in to the domain.
*
* Non-linear users can use irq_create_identity_mapping() for IRQ-at-a-time
* domain insertion.
*
* 0 is returned upon success, while any failure to establish a static
* mapping is treated as an error.
*/
int
irq_create_strict_mappings
(
struct
irq_domain
*
domain
,
unsigned
int
irq_base
,
irq_hw_number_t
hwirq_base
,
int
count
)
{
int
ret
;
ret
=
irq_alloc_descs
(
irq_base
,
irq_base
,
count
,
of_node_to_nid
(
domain
->
of_node
));
if
(
unlikely
(
ret
<
0
))
return
ret
;
ret
=
irq_domain_associate_many
(
domain
,
irq_base
,
hwirq_base
,
count
);
if
(
unlikely
(
ret
<
0
))
{
irq_free_descs
(
irq_base
,
count
);
return
ret
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
irq_create_strict_mappings
);
unsigned
int
irq_create_of_mapping
(
struct
device_node
*
controller
,
const
u32
*
intspec
,
unsigned
int
intsize
)
{
...
...
@@ -511,7 +670,6 @@ 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
;
...
...
@@ -524,33 +682,7 @@ void irq_dispose_mapping(unsigned int virq)
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_domain_disassociate_many
(
domain
,
virq
,
1
);
irq_free_desc
(
virq
);
}
EXPORT_SYMBOL_GPL
(
irq_dispose_mapping
);
...
...
@@ -559,16 +691,11 @@ 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
%
nr_irqs
;
struct
irq_data
*
data
;
/* Look for default domain if nececssary */
if
(
domain
==
NULL
)
...
...
@@ -576,115 +703,47 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
if
(
domain
==
NULL
)
return
0
;
/* legacy -> bail early */
if
(
domain
->
revmap_type
==
IRQ_DOMAIN_MAP_LEGACY
)
switch
(
domain
->
revmap_type
)
{
case
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
);
case
IRQ_DOMAIN_MAP_LINEAR
:
return
irq_linear_revmap
(
domain
,
hwirq
);
case
IRQ_DOMAIN_MAP_TREE
:
rcu_read_lock
();
data
=
radix_tree_lookup
(
&
domain
->
revmap_data
.
tree
,
hwirq
);
rcu_read_unlock
();
if
(
data
)
return
data
->
irq
;
break
;
case
IRQ_DOMAIN_MAP_NOMAP
:
data
=
irq_get_irq_data
(
hwirq
);
if
(
data
&&
(
data
->
domain
==
domain
)
&&
(
data
->
hwirq
==
hwirq
))
return
i
;
i
++
;
if
(
i
>=
nr_irqs
)
i
=
1
;
}
while
(
i
!=
hint
);
return
hwirq
;
break
;
}
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
*
* This is a fast path, for use by irq controller code that uses radix tree
* revmaps
*/
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
();
/*
* 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_radix_revmap_lookup
);
/**
* 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
)
{
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
);
}
}
EXPORT_SYMBOL_GPL
(
irq_radix_revmap_insert
);
/**
* 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
* This is a fast path that can be called directly by irq controller code to
* save a handful of instructions.
*/
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
);
BUG_ON
(
domain
->
revmap_type
!=
IRQ_DOMAIN_MAP_LINEAR
);
/* 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
);
/* Check revmap bounds; complain if exceeded */
if
(
WARN_ON
(
hwirq
>=
domain
->
revmap_data
.
linear
.
size
))
return
0
;
return
revmap
[
hwirq
];
return
domain
->
revmap_data
.
linear
.
revmap
[
hwirq
];
}
EXPORT_SYMBOL_GPL
(
irq_linear_revmap
);
...
...
@@ -761,12 +820,6 @@ static int __init irq_debugfs_init(void)
__initcall
(
irq_debugfs_init
);
#endif
/* CONFIG_IRQ_DOMAIN_DEBUG */
static
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
*
...
...
@@ -829,7 +882,6 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d,
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
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录