Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
885d078b
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
885d078b
编写于
7月 01, 2014
作者:
J
Jason Cooper
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'irqchip/crossbar' into irqchip/core
上级
4db8e6d2
d360892d
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
179 addition
and
25 deletion
+179
-25
Documentation/devicetree/bindings/arm/omap/crossbar.txt
Documentation/devicetree/bindings/arm/omap/crossbar.txt
+36
-0
drivers/irqchip/irq-crossbar.c
drivers/irqchip/irq-crossbar.c
+143
-25
未找到文件。
Documentation/devicetree/bindings/arm/omap/crossbar.txt
浏览文件 @
885d078b
...
@@ -10,6 +10,7 @@ Required properties:
...
@@ -10,6 +10,7 @@ Required properties:
- compatible : Should be "ti,irq-crossbar"
- compatible : Should be "ti,irq-crossbar"
- reg: Base address and the size of the crossbar registers.
- reg: Base address and the size of the crossbar registers.
- ti,max-irqs: Total number of irqs available at the interrupt controller.
- ti,max-irqs: Total number of irqs available at the interrupt controller.
- ti,max-crossbar-sources: Maximum number of crossbar sources that can be routed.
- ti,reg-size: Size of a individual register in bytes. Every individual
- ti,reg-size: Size of a individual register in bytes. Every individual
register is assumed to be of same size. Valid sizes are 1, 2, 4.
register is assumed to be of same size. Valid sizes are 1, 2, 4.
- ti,irqs-reserved: List of the reserved irq lines that are not muxed using
- ti,irqs-reserved: List of the reserved irq lines that are not muxed using
...
@@ -17,11 +18,46 @@ Required properties:
...
@@ -17,11 +18,46 @@ Required properties:
so crossbar bar driver should not consider them as free
so crossbar bar driver should not consider them as free
lines.
lines.
Optional properties:
- ti,irqs-skip: This is similar to "ti,irqs-reserved", but these are for
SOC-specific hard-wiring of those irqs which unexpectedly bypasses the
crossbar. These irqs have a crossbar register, but still cannot be used.
- ti,irqs-safe-map: integer which maps to a safe configuration to use
when the interrupt controller irq is unused (when not provided, default is 0)
Examples:
Examples:
crossbar_mpu: @4a020000 {
crossbar_mpu: @4a020000 {
compatible = "ti,irq-crossbar";
compatible = "ti,irq-crossbar";
reg = <0x4a002a48 0x130>;
reg = <0x4a002a48 0x130>;
ti,max-irqs = <160>;
ti,max-irqs = <160>;
ti,max-crossbar-sources = <400>;
ti,reg-size = <2>;
ti,reg-size = <2>;
ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>;
ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>;
ti,irqs-skip = <10 133 139 140>;
};
};
Consumer:
========
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and
Documentation/devicetree/bindings/arm/gic.txt for further details.
An interrupt consumer on an SoC using crossbar will use:
interrupts = <GIC_SPI request_number interrupt_level>
When the request number is between 0 to that described by
"ti,max-crossbar-sources", it is assumed to be a crossbar mapping. If the
request_number is greater than "ti,max-crossbar-sources", then it is mapped as a
quirky hardware mapping direct to GIC.
Example:
device_x@0x4a023000 {
/* Crossbar 8 used */
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
...
};
device_y@0x4a033000 {
/* Direct mapped GIC SPI 1 used */
interrupts = <GIC_SPI DIRECT_IRQ(1) IRQ_TYPE_LEVEL_HIGH>;
...
};
drivers/irqchip/irq-crossbar.c
浏览文件 @
885d078b
...
@@ -15,22 +15,31 @@
...
@@ -15,22 +15,31 @@
#include <linux/of_irq.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/irq-crossbar.h>
#define IRQ_FREE -1
#define IRQ_FREE -1
#define IRQ_RESERVED -2
#define IRQ_SKIP -3
#define GIC_IRQ_START 32
#define GIC_IRQ_START 32
/*
/**
* struct crossbar_device - crossbar device description
* @int_max: maximum number of supported interrupts
* @int_max: maximum number of supported interrupts
* @safe_map: safe default value to initialize the crossbar
* @max_crossbar_sources: Maximum number of crossbar sources
* @irq_map: array of interrupts to crossbar number mapping
* @irq_map: array of interrupts to crossbar number mapping
* @crossbar_base: crossbar base address
* @crossbar_base: crossbar base address
* @register_offsets: offsets for each irq number
* @register_offsets: offsets for each irq number
* @write: register write function pointer
*/
*/
struct
crossbar_device
{
struct
crossbar_device
{
uint
int_max
;
uint
int_max
;
uint
safe_map
;
uint
max_crossbar_sources
;
uint
*
irq_map
;
uint
*
irq_map
;
void
__iomem
*
crossbar_base
;
void
__iomem
*
crossbar_base
;
int
*
register_offsets
;
int
*
register_offsets
;
void
(
*
write
)
(
int
,
int
);
void
(
*
write
)(
int
,
int
);
};
};
static
struct
crossbar_device
*
cb
;
static
struct
crossbar_device
*
cb
;
...
@@ -50,11 +59,22 @@ static inline void crossbar_writeb(int irq_no, int cb_no)
...
@@ -50,11 +59,22 @@ static inline void crossbar_writeb(int irq_no, int cb_no)
writeb
(
cb_no
,
cb
->
crossbar_base
+
cb
->
register_offsets
[
irq_no
]);
writeb
(
cb_no
,
cb
->
crossbar_base
+
cb
->
register_offsets
[
irq_no
]);
}
}
static
inline
int
get_prev_map_irq
(
int
cb_no
)
{
int
i
;
for
(
i
=
cb
->
int_max
-
1
;
i
>=
0
;
i
--
)
if
(
cb
->
irq_map
[
i
]
==
cb_no
)
return
i
;
return
-
ENODEV
;
}
static
inline
int
allocate_free_irq
(
int
cb_no
)
static
inline
int
allocate_free_irq
(
int
cb_no
)
{
{
int
i
;
int
i
;
for
(
i
=
0
;
i
<
cb
->
int_max
;
i
++
)
{
for
(
i
=
cb
->
int_max
-
1
;
i
>=
0
;
i
--
)
{
if
(
cb
->
irq_map
[
i
]
==
IRQ_FREE
)
{
if
(
cb
->
irq_map
[
i
]
==
IRQ_FREE
)
{
cb
->
irq_map
[
i
]
=
cb_no
;
cb
->
irq_map
[
i
]
=
cb_no
;
return
i
;
return
i
;
...
@@ -64,19 +84,47 @@ static inline int allocate_free_irq(int cb_no)
...
@@ -64,19 +84,47 @@ static inline int allocate_free_irq(int cb_no)
return
-
ENODEV
;
return
-
ENODEV
;
}
}
static
inline
bool
needs_crossbar_write
(
irq_hw_number_t
hw
)
{
int
cb_no
;
if
(
hw
>
GIC_IRQ_START
)
{
cb_no
=
cb
->
irq_map
[
hw
-
GIC_IRQ_START
];
if
(
cb_no
!=
IRQ_RESERVED
&&
cb_no
!=
IRQ_SKIP
)
return
true
;
}
return
false
;
}
static
int
crossbar_domain_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
static
int
crossbar_domain_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
irq_hw_number_t
hw
)
irq_hw_number_t
hw
)
{
{
cb
->
write
(
hw
-
GIC_IRQ_START
,
cb
->
irq_map
[
hw
-
GIC_IRQ_START
]);
if
(
needs_crossbar_write
(
hw
))
cb
->
write
(
hw
-
GIC_IRQ_START
,
cb
->
irq_map
[
hw
-
GIC_IRQ_START
]);
return
0
;
return
0
;
}
}
/**
* crossbar_domain_unmap - unmap a crossbar<->irq connection
* @d: domain of irq to unmap
* @irq: virq number
*
* We do not maintain a use count of total number of map/unmap
* calls for a particular irq to find out if a irq can be really
* unmapped. This is because unmap is called during irq_dispose_mapping(irq),
* after which irq is anyways unusable. So an explicit map has to be called
* after that.
*/
static
void
crossbar_domain_unmap
(
struct
irq_domain
*
d
,
unsigned
int
irq
)
static
void
crossbar_domain_unmap
(
struct
irq_domain
*
d
,
unsigned
int
irq
)
{
{
irq_hw_number_t
hw
=
irq_get_irq_data
(
irq
)
->
hwirq
;
irq_hw_number_t
hw
=
irq_get_irq_data
(
irq
)
->
hwirq
;
if
(
hw
>
GIC_IRQ_START
)
if
(
needs_crossbar_write
(
hw
))
{
cb
->
irq_map
[
hw
-
GIC_IRQ_START
]
=
IRQ_FREE
;
cb
->
irq_map
[
hw
-
GIC_IRQ_START
]
=
IRQ_FREE
;
cb
->
write
(
hw
-
GIC_IRQ_START
,
cb
->
safe_map
);
}
}
}
static
int
crossbar_domain_xlate
(
struct
irq_domain
*
d
,
static
int
crossbar_domain_xlate
(
struct
irq_domain
*
d
,
...
@@ -85,18 +133,41 @@ static int crossbar_domain_xlate(struct irq_domain *d,
...
@@ -85,18 +133,41 @@ static int crossbar_domain_xlate(struct irq_domain *d,
unsigned
long
*
out_hwirq
,
unsigned
long
*
out_hwirq
,
unsigned
int
*
out_type
)
unsigned
int
*
out_type
)
{
{
unsigned
long
ret
;
int
ret
;
int
req_num
=
intspec
[
1
];
int
direct_map_num
;
if
(
req_num
>=
cb
->
max_crossbar_sources
)
{
direct_map_num
=
req_num
-
cb
->
max_crossbar_sources
;
if
(
direct_map_num
<
cb
->
int_max
)
{
ret
=
cb
->
irq_map
[
direct_map_num
];
if
(
ret
==
IRQ_RESERVED
||
ret
==
IRQ_SKIP
)
{
/* We use the interrupt num as h/w irq num */
ret
=
direct_map_num
;
goto
found
;
}
}
pr_err
(
"%s: requested crossbar number %d > max %d
\n
"
,
__func__
,
req_num
,
cb
->
max_crossbar_sources
);
return
-
EINVAL
;
}
ret
=
allocate_free_irq
(
intspec
[
1
]);
ret
=
get_prev_map_irq
(
req_num
);
if
(
ret
>=
0
)
goto
found
;
if
(
IS_ERR_VALUE
(
ret
))
ret
=
allocate_free_irq
(
req_num
);
if
(
ret
<
0
)
return
ret
;
return
ret
;
found:
*
out_hwirq
=
ret
+
GIC_IRQ_START
;
*
out_hwirq
=
ret
+
GIC_IRQ_START
;
return
0
;
return
0
;
}
}
const
struct
irq_domain_ops
routable_irq_domain_ops
=
{
static
const
struct
irq_domain_ops
routable_irq_domain_ops
=
{
.
map
=
crossbar_domain_map
,
.
map
=
crossbar_domain_map
,
.
unmap
=
crossbar_domain_unmap
,
.
unmap
=
crossbar_domain_unmap
,
.
xlate
=
crossbar_domain_xlate
.
xlate
=
crossbar_domain_xlate
...
@@ -104,22 +175,36 @@ const struct irq_domain_ops routable_irq_domain_ops = {
...
@@ -104,22 +175,36 @@ const struct irq_domain_ops routable_irq_domain_ops = {
static
int
__init
crossbar_of_init
(
struct
device_node
*
node
)
static
int
__init
crossbar_of_init
(
struct
device_node
*
node
)
{
{
int
i
,
size
,
max
,
reserved
=
0
,
entry
;
int
i
,
size
,
max
=
0
,
reserved
=
0
,
entry
;
const
__be32
*
irqsr
;
const
__be32
*
irqsr
;
int
ret
=
-
ENOMEM
;
cb
=
kzalloc
(
sizeof
(
*
cb
),
GFP_KERNEL
);
cb
=
kzalloc
(
sizeof
(
*
cb
),
GFP_KERNEL
);
if
(
!
cb
)
if
(
!
cb
)
return
-
ENOMEM
;
return
ret
;
cb
->
crossbar_base
=
of_iomap
(
node
,
0
);
cb
->
crossbar_base
=
of_iomap
(
node
,
0
);
if
(
!
cb
->
crossbar_base
)
if
(
!
cb
->
crossbar_base
)
goto
err1
;
goto
err_cb
;
of_property_read_u32
(
node
,
"ti,max-crossbar-sources"
,
&
cb
->
max_crossbar_sources
);
if
(
!
cb
->
max_crossbar_sources
)
{
pr_err
(
"missing 'ti,max-crossbar-sources' property
\n
"
);
ret
=
-
EINVAL
;
goto
err_base
;
}
of_property_read_u32
(
node
,
"ti,max-irqs"
,
&
max
);
of_property_read_u32
(
node
,
"ti,max-irqs"
,
&
max
);
cb
->
irq_map
=
kzalloc
(
max
*
sizeof
(
int
),
GFP_KERNEL
);
if
(
!
max
)
{
pr_err
(
"missing 'ti,max-irqs' property
\n
"
);
ret
=
-
EINVAL
;
goto
err_base
;
}
cb
->
irq_map
=
kcalloc
(
max
,
sizeof
(
int
),
GFP_KERNEL
);
if
(
!
cb
->
irq_map
)
if
(
!
cb
->
irq_map
)
goto
err
2
;
goto
err
_base
;
cb
->
int_max
=
max
;
cb
->
int_max
=
max
;
...
@@ -137,15 +222,35 @@ static int __init crossbar_of_init(struct device_node *node)
...
@@ -137,15 +222,35 @@ static int __init crossbar_of_init(struct device_node *node)
i
,
&
entry
);
i
,
&
entry
);
if
(
entry
>
max
)
{
if
(
entry
>
max
)
{
pr_err
(
"Invalid reserved entry
\n
"
);
pr_err
(
"Invalid reserved entry
\n
"
);
goto
err3
;
ret
=
-
EINVAL
;
goto
err_irq_map
;
}
cb
->
irq_map
[
entry
]
=
IRQ_RESERVED
;
}
}
/* Skip irqs hardwired to bypass the crossbar */
irqsr
=
of_get_property
(
node
,
"ti,irqs-skip"
,
&
size
);
if
(
irqsr
)
{
size
/=
sizeof
(
__be32
);
for
(
i
=
0
;
i
<
size
;
i
++
)
{
of_property_read_u32_index
(
node
,
"ti,irqs-skip"
,
i
,
&
entry
);
if
(
entry
>
max
)
{
pr_err
(
"Invalid skip entry
\n
"
);
ret
=
-
EINVAL
;
goto
err_irq_map
;
}
}
cb
->
irq_map
[
entry
]
=
0
;
cb
->
irq_map
[
entry
]
=
IRQ_SKIP
;
}
}
}
}
cb
->
register_offsets
=
kzalloc
(
max
*
sizeof
(
int
),
GFP_KERNEL
);
cb
->
register_offsets
=
kcalloc
(
max
,
sizeof
(
int
),
GFP_KERNEL
);
if
(
!
cb
->
register_offsets
)
if
(
!
cb
->
register_offsets
)
goto
err
3
;
goto
err
_irq_map
;
of_property_read_u32
(
node
,
"ti,reg-size"
,
&
size
);
of_property_read_u32
(
node
,
"ti,reg-size"
,
&
size
);
...
@@ -161,7 +266,8 @@ static int __init crossbar_of_init(struct device_node *node)
...
@@ -161,7 +266,8 @@ static int __init crossbar_of_init(struct device_node *node)
break
;
break
;
default:
default:
pr_err
(
"Invalid reg-size property
\n
"
);
pr_err
(
"Invalid reg-size property
\n
"
);
goto
err4
;
ret
=
-
EINVAL
;
goto
err_reg_offset
;
break
;
break
;
}
}
...
@@ -170,25 +276,37 @@ static int __init crossbar_of_init(struct device_node *node)
...
@@ -170,25 +276,37 @@ static int __init crossbar_of_init(struct device_node *node)
* reserved irqs. so find and store the offsets once.
* reserved irqs. so find and store the offsets once.
*/
*/
for
(
i
=
0
;
i
<
max
;
i
++
)
{
for
(
i
=
0
;
i
<
max
;
i
++
)
{
if
(
!
cb
->
irq_map
[
i
]
)
if
(
cb
->
irq_map
[
i
]
==
IRQ_RESERVED
)
continue
;
continue
;
cb
->
register_offsets
[
i
]
=
reserved
;
cb
->
register_offsets
[
i
]
=
reserved
;
reserved
+=
size
;
reserved
+=
size
;
}
}
of_property_read_u32
(
node
,
"ti,irqs-safe-map"
,
&
cb
->
safe_map
);
/* Initialize the crossbar with safe map to start with */
for
(
i
=
0
;
i
<
max
;
i
++
)
{
if
(
cb
->
irq_map
[
i
]
==
IRQ_RESERVED
||
cb
->
irq_map
[
i
]
==
IRQ_SKIP
)
continue
;
cb
->
write
(
i
,
cb
->
safe_map
);
}
register_routable_domain_ops
(
&
routable_irq_domain_ops
);
register_routable_domain_ops
(
&
routable_irq_domain_ops
);
return
0
;
return
0
;
err
4
:
err
_reg_offset
:
kfree
(
cb
->
register_offsets
);
kfree
(
cb
->
register_offsets
);
err
3
:
err
_irq_map
:
kfree
(
cb
->
irq_map
);
kfree
(
cb
->
irq_map
);
err
2
:
err
_base
:
iounmap
(
cb
->
crossbar_base
);
iounmap
(
cb
->
crossbar_base
);
err
1
:
err
_cb
:
kfree
(
cb
);
kfree
(
cb
);
return
-
ENOMEM
;
cb
=
NULL
;
return
ret
;
}
}
static
const
struct
of_device_id
crossbar_match
[]
__initconst
=
{
static
const
struct
of_device_id
crossbar_match
[]
__initconst
=
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录