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
179c1e3c
Commit
179c1e3c
authored
Jul 11, 2014
by
Christoffer Dall
Browse files
Options
Browse Files
Download
Plain Diff
Merge tag 'deps-irqchip-gic-3.17' of
git://git.infradead.org/users/jcooper/linux.git
parents
1df08ba0
021f6537
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1065 additions
and
56 deletions
+1065
-56
arch/arm64/Kconfig
arch/arm64/Kconfig
+1
-0
arch/arm64/kernel/head.S
arch/arm64/kernel/head.S
+18
-0
arch/arm64/kernel/hyp-stub.S
arch/arm64/kernel/hyp-stub.S
+1
-0
drivers/irqchip/Kconfig
drivers/irqchip/Kconfig
+5
-0
drivers/irqchip/Makefile
drivers/irqchip/Makefile
+2
-1
drivers/irqchip/irq-gic-common.c
drivers/irqchip/irq-gic-common.c
+115
-0
drivers/irqchip/irq-gic-common.h
drivers/irqchip/irq-gic-common.h
+29
-0
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic-v3.c
+692
-0
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-gic.c
+4
-55
include/linux/irqchip/arm-gic-v3.h
include/linux/irqchip/arm-gic-v3.h
+198
-0
No files found.
arch/arm64/Kconfig
View file @
179c1e3c
...
@@ -9,6 +9,7 @@ config ARM64
...
@@ -9,6 +9,7 @@ config ARM64
select ARM_AMBA
select ARM_AMBA
select ARM_ARCH_TIMER
select ARM_ARCH_TIMER
select ARM_GIC
select ARM_GIC
select ARM_GIC_V3
select BUILDTIME_EXTABLE_SORT
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select CLONE_BACKWARDS
select COMMON_CLK
select COMMON_CLK
...
...
arch/arm64/kernel/head.S
View file @
179c1e3c
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
#include <linux/linkage.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/assembler.h>
#include <asm/assembler.h>
#include <asm/ptrace.h>
#include <asm/ptrace.h>
...
@@ -296,6 +297,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1
...
@@ -296,6 +297,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1
msr
cnthctl_el2
,
x0
msr
cnthctl_el2
,
x0
msr
cntvoff_el2
,
xzr
//
Clear
virtual
offset
msr
cntvoff_el2
,
xzr
//
Clear
virtual
offset
#ifdef CONFIG_ARM_GIC_V3
/
*
GICv3
system
register
access
*/
mrs
x0
,
id_aa64pfr0_el1
ubfx
x0
,
x0
,
#
24
,
#
4
cmp
x0
,
#
1
b.ne
3
f
mrs
x0
,
ICC_SRE_EL2
orr
x0
,
x0
,
#
ICC_SRE_EL2_SRE
//
Set
ICC_SRE_EL2
.
SRE
==
1
orr
x0
,
x0
,
#
ICC_SRE_EL2_ENABLE
//
Set
ICC_SRE_EL2
.
Enable
==
1
msr
ICC_SRE_EL2
,
x0
isb
//
Make
sure
SRE
is
now
set
msr
ICH_HCR_EL2
,
xzr
//
Reset
ICC_HCR_EL2
to
defaults
3
:
#endif
/
*
Populate
ID
registers
.
*/
/
*
Populate
ID
registers
.
*/
mrs
x0
,
midr_el1
mrs
x0
,
midr_el1
mrs
x1
,
mpidr_el1
mrs
x1
,
mpidr_el1
...
...
arch/arm64/kernel/hyp-stub.S
View file @
179c1e3c
...
@@ -19,6 +19,7 @@
...
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/linkage.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/assembler.h>
#include <asm/assembler.h>
#include <asm/ptrace.h>
#include <asm/ptrace.h>
...
...
drivers/irqchip/Kconfig
View file @
179c1e3c
...
@@ -10,6 +10,11 @@ config ARM_GIC
...
@@ -10,6 +10,11 @@ config ARM_GIC
config GIC_NON_BANKED
config GIC_NON_BANKED
bool
bool
config ARM_GIC_V3
bool
select IRQ_DOMAIN
select MULTI_IRQ_HANDLER
config ARM_NVIC
config ARM_NVIC
bool
bool
select IRQ_DOMAIN
select IRQ_DOMAIN
...
...
drivers/irqchip/Makefile
View file @
179c1e3c
...
@@ -15,7 +15,8 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
...
@@ -15,7 +15,8 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI)
+=
irq-sun4i.o
obj-$(CONFIG_ARCH_SUNXI)
+=
irq-sun4i.o
obj-$(CONFIG_ARCH_SUNXI)
+=
irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SUNXI)
+=
irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX)
+=
spear-shirq.o
obj-$(CONFIG_ARCH_SPEAR3XX)
+=
spear-shirq.o
obj-$(CONFIG_ARM_GIC)
+=
irq-gic.o
obj-$(CONFIG_ARM_GIC)
+=
irq-gic.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3)
+=
irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_NVIC)
+=
irq-nvic.o
obj-$(CONFIG_ARM_NVIC)
+=
irq-nvic.o
obj-$(CONFIG_ARM_VIC)
+=
irq-vic.o
obj-$(CONFIG_ARM_VIC)
+=
irq-vic.o
obj-$(CONFIG_IMGPDC_IRQ)
+=
irq-imgpdc.o
obj-$(CONFIG_IMGPDC_IRQ)
+=
irq-imgpdc.o
...
...
drivers/irqchip/irq-gic-common.c
0 → 100644
View file @
179c1e3c
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip/arm-gic.h>
#include "irq-gic-common.h"
void
gic_configure_irq
(
unsigned
int
irq
,
unsigned
int
type
,
void
__iomem
*
base
,
void
(
*
sync_access
)(
void
))
{
u32
enablemask
=
1
<<
(
irq
%
32
);
u32
enableoff
=
(
irq
/
32
)
*
4
;
u32
confmask
=
0x2
<<
((
irq
%
16
)
*
2
);
u32
confoff
=
(
irq
/
16
)
*
4
;
bool
enabled
=
false
;
u32
val
;
/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
val
=
readl_relaxed
(
base
+
GIC_DIST_CONFIG
+
confoff
);
if
(
type
==
IRQ_TYPE_LEVEL_HIGH
)
val
&=
~
confmask
;
else
if
(
type
==
IRQ_TYPE_EDGE_RISING
)
val
|=
confmask
;
/*
* As recommended by the spec, disable the interrupt before changing
* the configuration
*/
if
(
readl_relaxed
(
base
+
GIC_DIST_ENABLE_SET
+
enableoff
)
&
enablemask
)
{
writel_relaxed
(
enablemask
,
base
+
GIC_DIST_ENABLE_CLEAR
+
enableoff
);
if
(
sync_access
)
sync_access
();
enabled
=
true
;
}
/*
* Write back the new configuration, and possibly re-enable
* the interrupt.
*/
writel_relaxed
(
val
,
base
+
GIC_DIST_CONFIG
+
confoff
);
if
(
enabled
)
writel_relaxed
(
enablemask
,
base
+
GIC_DIST_ENABLE_SET
+
enableoff
);
if
(
sync_access
)
sync_access
();
}
void
__init
gic_dist_config
(
void
__iomem
*
base
,
int
gic_irqs
,
void
(
*
sync_access
)(
void
))
{
unsigned
int
i
;
/*
* Set all global interrupts to be level triggered, active low.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
16
)
writel_relaxed
(
0
,
base
+
GIC_DIST_CONFIG
+
i
/
4
);
/*
* Set priority on all global interrupts.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
4
)
writel_relaxed
(
0xa0a0a0a0
,
base
+
GIC_DIST_PRI
+
i
);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as they are enabled by redistributor registers.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
32
)
writel_relaxed
(
0xffffffff
,
base
+
GIC_DIST_ENABLE_CLEAR
+
i
/
8
);
if
(
sync_access
)
sync_access
();
}
void
gic_cpu_config
(
void
__iomem
*
base
,
void
(
*
sync_access
)(
void
))
{
int
i
;
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel_relaxed
(
0xffff0000
,
base
+
GIC_DIST_ENABLE_CLEAR
);
writel_relaxed
(
0x0000ffff
,
base
+
GIC_DIST_ENABLE_SET
);
/*
* Set priority on PPI and SGI interrupts
*/
for
(
i
=
0
;
i
<
32
;
i
+=
4
)
writel_relaxed
(
0xa0a0a0a0
,
base
+
GIC_DIST_PRI
+
i
*
4
/
4
);
if
(
sync_access
)
sync_access
();
}
drivers/irqchip/irq-gic-common.h
0 → 100644
View file @
179c1e3c
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _IRQ_GIC_COMMON_H
#define _IRQ_GIC_COMMON_H
#include <linux/of.h>
#include <linux/irqdomain.h>
void
gic_configure_irq
(
unsigned
int
irq
,
unsigned
int
type
,
void
__iomem
*
base
,
void
(
*
sync_access
)(
void
));
void
gic_dist_config
(
void
__iomem
*
base
,
int
gic_irqs
,
void
(
*
sync_access
)(
void
));
void
gic_cpu_config
(
void
__iomem
*
base
,
void
(
*
sync_access
)(
void
));
#endif
/* _IRQ_GIC_COMMON_H */
drivers/irqchip/irq-gic-v3.c
0 → 100644
View file @
179c1e3c
/*
* Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/cputype.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h"
struct
gic_chip_data
{
void
__iomem
*
dist_base
;
void
__iomem
**
redist_base
;
void
__percpu
__iomem
**
rdist
;
struct
irq_domain
*
domain
;
u64
redist_stride
;
u32
redist_regions
;
unsigned
int
irq_nr
;
};
static
struct
gic_chip_data
gic_data
__read_mostly
;
#define gic_data_rdist() (this_cpu_ptr(gic_data.rdist))
#define gic_data_rdist_rd_base() (*gic_data_rdist())
#define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K)
/* Our default, arbitrary priority value. Linux only uses one anyway. */
#define DEFAULT_PMR_VALUE 0xf0
static
inline
unsigned
int
gic_irq
(
struct
irq_data
*
d
)
{
return
d
->
hwirq
;
}
static
inline
int
gic_irq_in_rdist
(
struct
irq_data
*
d
)
{
return
gic_irq
(
d
)
<
32
;
}
static
inline
void
__iomem
*
gic_dist_base
(
struct
irq_data
*
d
)
{
if
(
gic_irq_in_rdist
(
d
))
/* SGI+PPI -> SGI_base for this CPU */
return
gic_data_rdist_sgi_base
();
if
(
d
->
hwirq
<=
1023
)
/* SPI -> dist_base */
return
gic_data
.
dist_base
;
if
(
d
->
hwirq
>=
8192
)
BUG
();
/* LPI Detected!!! */
return
NULL
;
}
static
void
gic_do_wait_for_rwp
(
void
__iomem
*
base
)
{
u32
count
=
1000000
;
/* 1s! */
while
(
readl_relaxed
(
base
+
GICD_CTLR
)
&
GICD_CTLR_RWP
)
{
count
--
;
if
(
!
count
)
{
pr_err_ratelimited
(
"RWP timeout, gone fishing
\n
"
);
return
;
}
cpu_relax
();
udelay
(
1
);
};
}
/* Wait for completion of a distributor change */
static
void
gic_dist_wait_for_rwp
(
void
)
{
gic_do_wait_for_rwp
(
gic_data
.
dist_base
);
}
/* Wait for completion of a redistributor change */
static
void
gic_redist_wait_for_rwp
(
void
)
{
gic_do_wait_for_rwp
(
gic_data_rdist_rd_base
());
}
/* Low level accessors */
static
u64
gic_read_iar
(
void
)
{
u64
irqstat
;
asm
volatile
(
"mrs %0, "
__stringify
(
ICC_IAR1_EL1
)
:
"=r"
(
irqstat
));
return
irqstat
;
}
static
void
gic_write_pmr
(
u64
val
)
{
asm
volatile
(
"msr "
__stringify
(
ICC_PMR_EL1
)
", %0"
:
:
"r"
(
val
));
}
static
void
gic_write_ctlr
(
u64
val
)
{
asm
volatile
(
"msr "
__stringify
(
ICC_CTLR_EL1
)
", %0"
:
:
"r"
(
val
));
isb
();
}
static
void
gic_write_grpen1
(
u64
val
)
{
asm
volatile
(
"msr "
__stringify
(
ICC_GRPEN1_EL1
)
", %0"
:
:
"r"
(
val
));
isb
();
}
static
void
gic_write_sgi1r
(
u64
val
)
{
asm
volatile
(
"msr "
__stringify
(
ICC_SGI1R_EL1
)
", %0"
:
:
"r"
(
val
));
}
static
void
gic_enable_sre
(
void
)
{
u64
val
;
asm
volatile
(
"mrs %0, "
__stringify
(
ICC_SRE_EL1
)
:
"=r"
(
val
));
val
|=
ICC_SRE_EL1_SRE
;
asm
volatile
(
"msr "
__stringify
(
ICC_SRE_EL1
)
", %0"
:
:
"r"
(
val
));
isb
();
/*
* Need to check that the SRE bit has actually been set. If
* not, it means that SRE is disabled at EL2. We're going to
* die painfully, and there is nothing we can do about it.
*
* Kindly inform the luser.
*/
asm
volatile
(
"mrs %0, "
__stringify
(
ICC_SRE_EL1
)
:
"=r"
(
val
));
if
(
!
(
val
&
ICC_SRE_EL1_SRE
))
pr_err
(
"GIC: unable to set SRE (disabled at EL2), panic ahead
\n
"
);
}
static
void
gic_enable_redist
(
void
)
{
void
__iomem
*
rbase
;
u32
count
=
1000000
;
/* 1s! */
u32
val
;
rbase
=
gic_data_rdist_rd_base
();
/* Wake up this CPU redistributor */
val
=
readl_relaxed
(
rbase
+
GICR_WAKER
);
val
&=
~
GICR_WAKER_ProcessorSleep
;
writel_relaxed
(
val
,
rbase
+
GICR_WAKER
);
while
(
readl_relaxed
(
rbase
+
GICR_WAKER
)
&
GICR_WAKER_ChildrenAsleep
)
{
count
--
;
if
(
!
count
)
{
pr_err_ratelimited
(
"redist didn't wake up...
\n
"
);
return
;
}
cpu_relax
();
udelay
(
1
);
};
}
/*
* Routines to disable, enable, EOI and route interrupts
*/
static
void
gic_poke_irq
(
struct
irq_data
*
d
,
u32
offset
)
{
u32
mask
=
1
<<
(
gic_irq
(
d
)
%
32
);
void
(
*
rwp_wait
)(
void
);
void
__iomem
*
base
;
if
(
gic_irq_in_rdist
(
d
))
{
base
=
gic_data_rdist_sgi_base
();
rwp_wait
=
gic_redist_wait_for_rwp
;
}
else
{
base
=
gic_data
.
dist_base
;
rwp_wait
=
gic_dist_wait_for_rwp
;
}
writel_relaxed
(
mask
,
base
+
offset
+
(
gic_irq
(
d
)
/
32
)
*
4
);
rwp_wait
();
}
static
int
gic_peek_irq
(
struct
irq_data
*
d
,
u32
offset
)
{
u32
mask
=
1
<<
(
gic_irq
(
d
)
%
32
);
void
__iomem
*
base
;
if
(
gic_irq_in_rdist
(
d
))
base
=
gic_data_rdist_sgi_base
();
else
base
=
gic_data
.
dist_base
;
return
!!
(
readl_relaxed
(
base
+
offset
+
(
gic_irq
(
d
)
/
32
)
*
4
)
&
mask
);
}
static
void
gic_mask_irq
(
struct
irq_data
*
d
)
{
gic_poke_irq
(
d
,
GICD_ICENABLER
);
}
static
void
gic_unmask_irq
(
struct
irq_data
*
d
)
{
gic_poke_irq
(
d
,
GICD_ISENABLER
);
}
static
void
gic_eoi_irq
(
struct
irq_data
*
d
)
{
gic_write_eoir
(
gic_irq
(
d
));
}
static
int
gic_set_type
(
struct
irq_data
*
d
,
unsigned
int
type
)
{
unsigned
int
irq
=
gic_irq
(
d
);
void
(
*
rwp_wait
)(
void
);
void
__iomem
*
base
;
/* Interrupt configuration for SGIs can't be changed */
if
(
irq
<
16
)
return
-
EINVAL
;
if
(
type
!=
IRQ_TYPE_LEVEL_HIGH
&&
type
!=
IRQ_TYPE_EDGE_RISING
)
return
-
EINVAL
;
if
(
gic_irq_in_rdist
(
d
))
{
base
=
gic_data_rdist_sgi_base
();
rwp_wait
=
gic_redist_wait_for_rwp
;
}
else
{
base
=
gic_data
.
dist_base
;
rwp_wait
=
gic_dist_wait_for_rwp
;
}
gic_configure_irq
(
irq
,
type
,
base
,
rwp_wait
);
return
0
;
}
static
u64
gic_mpidr_to_affinity
(
u64
mpidr
)
{
u64
aff
;
aff
=
(
MPIDR_AFFINITY_LEVEL
(
mpidr
,
3
)
<<
32
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
2
)
<<
16
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
1
)
<<
8
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
0
));
return
aff
;
}
static
asmlinkage
void
__exception_irq_entry
gic_handle_irq
(
struct
pt_regs
*
regs
)
{
u64
irqnr
;
do
{
irqnr
=
gic_read_iar
();
if
(
likely
(
irqnr
>
15
&&
irqnr
<
1020
))
{
u64
irq
=
irq_find_mapping
(
gic_data
.
domain
,
irqnr
);
if
(
likely
(
irq
))
{
handle_IRQ
(
irq
,
regs
);
continue
;
}
WARN_ONCE
(
true
,
"Unexpected SPI received!
\n
"
);
gic_write_eoir
(
irqnr
);
}
if
(
irqnr
<
16
)
{
gic_write_eoir
(
irqnr
);
#ifdef CONFIG_SMP
handle_IPI
(
irqnr
,
regs
);
#else
WARN_ONCE
(
true
,
"Unexpected SGI received!
\n
"
);
#endif
continue
;
}
}
while
(
irqnr
!=
ICC_IAR1_EL1_SPURIOUS
);
}
static
void
__init
gic_dist_init
(
void
)
{
unsigned
int
i
;
u64
affinity
;
void
__iomem
*
base
=
gic_data
.
dist_base
;
/* Disable the distributor */
writel_relaxed
(
0
,
base
+
GICD_CTLR
);
gic_dist_wait_for_rwp
();
gic_dist_config
(
base
,
gic_data
.
irq_nr
,
gic_dist_wait_for_rwp
);
/* Enable distributor with ARE, Group1 */
writel_relaxed
(
GICD_CTLR_ARE_NS
|
GICD_CTLR_ENABLE_G1A
|
GICD_CTLR_ENABLE_G1
,
base
+
GICD_CTLR
);
/*
* Set all global interrupts to the boot CPU only. ARE must be
* enabled.
*/
affinity
=
gic_mpidr_to_affinity
(
cpu_logical_map
(
smp_processor_id
()));
for
(
i
=
32
;
i
<
gic_data
.
irq_nr
;
i
++
)
writeq_relaxed
(
affinity
,
base
+
GICD_IROUTER
+
i
*
8
);
}
static
int
gic_populate_rdist
(
void
)
{
u64
mpidr
=
cpu_logical_map
(
smp_processor_id
());
u64
typer
;
u32
aff
;
int
i
;
/*
* Convert affinity to a 32bit value that can be matched to
* GICR_TYPER bits [63:32].
*/
aff
=
(
MPIDR_AFFINITY_LEVEL
(
mpidr
,
3
)
<<
24
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
2
)
<<
16
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
1
)
<<
8
|
MPIDR_AFFINITY_LEVEL
(
mpidr
,
0
));
for
(
i
=
0
;
i
<
gic_data
.
redist_regions
;
i
++
)
{
void
__iomem
*
ptr
=
gic_data
.
redist_base
[
i
];
u32
reg
;
reg
=
readl_relaxed
(
ptr
+
GICR_PIDR2
)
&
GIC_PIDR2_ARCH_MASK
;
if
(
reg
!=
GIC_PIDR2_ARCH_GICv3
&&
reg
!=
GIC_PIDR2_ARCH_GICv4
)
{
/* We're in trouble... */
pr_warn
(
"No redistributor present @%p
\n
"
,
ptr
);
break
;
}
do
{
typer
=
readq_relaxed
(
ptr
+
GICR_TYPER
);
if
((
typer
>>
32
)
==
aff
)
{
gic_data_rdist_rd_base
()
=
ptr
;
pr_info
(
"CPU%d: found redistributor %llx @%p
\n
"
,
smp_processor_id
(),
(
unsigned
long
long
)
mpidr
,
ptr
);
return
0
;
}
if
(
gic_data
.
redist_stride
)
{
ptr
+=
gic_data
.
redist_stride
;
}
else
{
ptr
+=
SZ_64K
*
2
;
/* Skip RD_base + SGI_base */
if
(
typer
&
GICR_TYPER_VLPIS
)
ptr
+=
SZ_64K
*
2
;
/* Skip VLPI_base + reserved page */
}
}
while
(
!
(
typer
&
GICR_TYPER_LAST
));
}
/* We couldn't even deal with ourselves... */
WARN
(
true
,
"CPU%d: mpidr %llx has no re-distributor!
\n
"
,
smp_processor_id
(),
(
unsigned
long
long
)
mpidr
);
return
-
ENODEV
;
}
static
void
gic_cpu_init
(
void
)
{
void
__iomem
*
rbase
;
/* Register ourselves with the rest of the world */
if
(
gic_populate_rdist
())
return
;
gic_enable_redist
();
rbase
=
gic_data_rdist_sgi_base
();
gic_cpu_config
(
rbase
,
gic_redist_wait_for_rwp
);
/* Enable system registers */
gic_enable_sre
();
/* Set priority mask register */
gic_write_pmr
(
DEFAULT_PMR_VALUE
);
/* EOI deactivates interrupt too (mode 0) */
gic_write_ctlr
(
ICC_CTLR_EL1_EOImode_drop_dir
);
/* ... and let's hit the road... */
gic_write_grpen1
(
1
);
}
#ifdef CONFIG_SMP
static
int
gic_secondary_init
(
struct
notifier_block
*
nfb
,
unsigned
long
action
,
void
*
hcpu
)
{
if
(
action
==
CPU_STARTING
||
action
==
CPU_STARTING_FROZEN
)
gic_cpu_init
();
return
NOTIFY_OK
;
}
/*
* Notifier for enabling the GIC CPU interface. Set an arbitrarily high
* priority because the GIC needs to be up before the ARM generic timers.
*/
static
struct
notifier_block
gic_cpu_notifier
=
{
.
notifier_call
=
gic_secondary_init
,
.
priority
=
100
,
};
static
u16
gic_compute_target_list
(
int
*
base_cpu
,
const
struct
cpumask
*
mask
,
u64
cluster_id
)
{
int
cpu
=
*
base_cpu
;
u64
mpidr
=
cpu_logical_map
(
cpu
);
u16
tlist
=
0
;
while
(
cpu
<
nr_cpu_ids
)
{
/*
* If we ever get a cluster of more than 16 CPUs, just
* scream and skip that CPU.
*/
if
(
WARN_ON
((
mpidr
&
0xff
)
>=
16
))
goto
out
;
tlist
|=
1
<<
(
mpidr
&
0xf
);
cpu
=
cpumask_next
(
cpu
,
mask
);
if
(
cpu
==
nr_cpu_ids
)
goto
out
;
mpidr
=
cpu_logical_map
(
cpu
);
if
(
cluster_id
!=
(
mpidr
&
~
0xffUL
))
{
cpu
--
;
goto
out
;
}
}
out:
*
base_cpu
=
cpu
;
return
tlist
;
}
static
void
gic_send_sgi
(
u64
cluster_id
,
u16
tlist
,
unsigned
int
irq
)
{
u64
val
;
val
=
(
MPIDR_AFFINITY_LEVEL
(
cluster_id
,
3
)
<<
48
|
MPIDR_AFFINITY_LEVEL
(
cluster_id
,
2
)
<<
32
|
irq
<<
24
|
MPIDR_AFFINITY_LEVEL
(
cluster_id
,
1
)
<<
16
|
tlist
);
pr_debug
(
"CPU%d: ICC_SGI1R_EL1 %llx
\n
"
,
smp_processor_id
(),
val
);
gic_write_sgi1r
(
val
);
}
static
void
gic_raise_softirq
(
const
struct
cpumask
*
mask
,
unsigned
int
irq
)
{
int
cpu
;
if
(
WARN_ON
(
irq
>=
16
))
return
;
/*
* Ensure that stores to Normal memory are visible to the
* other CPUs before issuing the IPI.
*/
smp_wmb
();
for_each_cpu_mask
(
cpu
,
*
mask
)
{
u64
cluster_id
=
cpu_logical_map
(
cpu
)
&
~
0xffUL
;
u16
tlist
;
tlist
=
gic_compute_target_list
(
&
cpu
,
mask
,
cluster_id
);
gic_send_sgi
(
cluster_id
,
tlist
,
irq
);
}
/* Force the above writes to ICC_SGI1R_EL1 to be executed */
isb
();
}
static
void
gic_smp_init
(
void
)
{
set_smp_cross_call
(
gic_raise_softirq
);
register_cpu_notifier
(
&
gic_cpu_notifier
);
}
static
int
gic_set_affinity
(
struct
irq_data
*
d
,
const
struct
cpumask
*
mask_val
,
bool
force
)
{
unsigned
int
cpu
=
cpumask_any_and
(
mask_val
,
cpu_online_mask
);
void
__iomem
*
reg
;
int
enabled
;
u64
val
;
if
(
gic_irq_in_rdist
(
d
))
return
-
EINVAL
;
/* If interrupt was enabled, disable it first */
enabled
=
gic_peek_irq
(
d
,
GICD_ISENABLER
);
if
(
enabled
)
gic_mask_irq
(
d
);
reg
=
gic_dist_base
(
d
)
+
GICD_IROUTER
+
(
gic_irq
(
d
)
*
8
);
val
=
gic_mpidr_to_affinity
(
cpu_logical_map
(
cpu
));
writeq_relaxed
(
val
,
reg
);
/*
* If the interrupt was enabled, enabled it again. Otherwise,
* just wait for the distributor to have digested our changes.
*/
if
(
enabled
)
gic_unmask_irq
(
d
);
else
gic_dist_wait_for_rwp
();
return
IRQ_SET_MASK_OK
;
}
#else
#define gic_set_affinity NULL
#define gic_smp_init() do { } while(0)
#endif
static
struct
irq_chip
gic_chip
=
{
.
name
=
"GICv3"
,
.
irq_mask
=
gic_mask_irq
,
.
irq_unmask
=
gic_unmask_irq
,
.
irq_eoi
=
gic_eoi_irq
,
.
irq_set_type
=
gic_set_type
,
.
irq_set_affinity
=
gic_set_affinity
,
};
static
int
gic_irq_domain_map
(
struct
irq_domain
*
d
,
unsigned
int
irq
,
irq_hw_number_t
hw
)
{
/* SGIs are private to the core kernel */
if
(
hw
<
16
)
return
-
EPERM
;
/* PPIs */
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
);
}
/* SPIs */
if
(
hw
>=
32
&&
hw
<
gic_data
.
irq_nr
)
{
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
;
if
(
intsize
<
3
)
return
-
EINVAL
;
switch
(
intspec
[
0
])
{
case
0
:
/* SPI */
*
out_hwirq
=
intspec
[
1
]
+
32
;
break
;
case
1
:
/* PPI */
*
out_hwirq
=
intspec
[
1
]
+
16
;
break
;
default:
return
-
EINVAL
;
}
*
out_type
=
intspec
[
2
]
&
IRQ_TYPE_SENSE_MASK
;
return
0
;
}
static
const
struct
irq_domain_ops
gic_irq_domain_ops
=
{
.
map
=
gic_irq_domain_map
,
.
xlate
=
gic_irq_domain_xlate
,
};
static
int
__init
gic_of_init
(
struct
device_node
*
node
,
struct
device_node
*
parent
)
{
void
__iomem
*
dist_base
;
void
__iomem
**
redist_base
;
u64
redist_stride
;
u32
redist_regions
;
u32
reg
;
int
gic_irqs
;
int
err
;
int
i
;
dist_base
=
of_iomap
(
node
,
0
);
if
(
!
dist_base
)
{
pr_err
(
"%s: unable to map gic dist registers
\n
"
,
node
->
full_name
);
return
-
ENXIO
;
}
reg
=
readl_relaxed
(
dist_base
+
GICD_PIDR2
)
&
GIC_PIDR2_ARCH_MASK
;
if
(
reg
!=
GIC_PIDR2_ARCH_GICv3
&&
reg
!=
GIC_PIDR2_ARCH_GICv4
)
{
pr_err
(
"%s: no distributor detected, giving up
\n
"
,
node
->
full_name
);
err
=
-
ENODEV
;
goto
out_unmap_dist
;
}
if
(
of_property_read_u32
(
node
,
"#redistributor-regions"
,
&
redist_regions
))
redist_regions
=
1
;
redist_base
=
kzalloc
(
sizeof
(
*
redist_base
)
*
redist_regions
,
GFP_KERNEL
);
if
(
!
redist_base
)
{
err
=
-
ENOMEM
;
goto
out_unmap_dist
;
}
for
(
i
=
0
;
i
<
redist_regions
;
i
++
)
{
redist_base
[
i
]
=
of_iomap
(
node
,
1
+
i
);
if
(
!
redist_base
[
i
])
{
pr_err
(
"%s: couldn't map region %d
\n
"
,
node
->
full_name
,
i
);
err
=
-
ENODEV
;
goto
out_unmap_rdist
;
}
}
if
(
of_property_read_u64
(
node
,
"redistributor-stride"
,
&
redist_stride
))
redist_stride
=
0
;
gic_data
.
dist_base
=
dist_base
;
gic_data
.
redist_base
=
redist_base
;
gic_data
.
redist_regions
=
redist_regions
;
gic_data
.
redist_stride
=
redist_stride
;
/*
* Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
*/
gic_irqs
=
readl_relaxed
(
gic_data
.
dist_base
+
GICD_TYPER
)
&
0x1f
;
gic_irqs
=
(
gic_irqs
+
1
)
*
32
;
if
(
gic_irqs
>
1020
)
gic_irqs
=
1020
;
gic_data
.
irq_nr
=
gic_irqs
;
gic_data
.
domain
=
irq_domain_add_tree
(
node
,
&
gic_irq_domain_ops
,
&
gic_data
);
gic_data
.
rdist
=
alloc_percpu
(
typeof
(
*
gic_data
.
rdist
));
if
(
WARN_ON
(
!
gic_data
.
domain
)
||
WARN_ON
(
!
gic_data
.
rdist
))
{
err
=
-
ENOMEM
;
goto
out_free
;
}
set_handle_irq
(
gic_handle_irq
);
gic_smp_init
();
gic_dist_init
();
gic_cpu_init
();
return
0
;
out_free:
if
(
gic_data
.
domain
)
irq_domain_remove
(
gic_data
.
domain
);
free_percpu
(
gic_data
.
rdist
);
out_unmap_rdist:
for
(
i
=
0
;
i
<
redist_regions
;
i
++
)
if
(
redist_base
[
i
])
iounmap
(
redist_base
[
i
]);
kfree
(
redist_base
);
out_unmap_dist:
iounmap
(
dist_base
);
return
err
;
}
IRQCHIP_DECLARE
(
gic_v3
,
"arm,gic-v3"
,
gic_of_init
);
drivers/irqchip/irq-gic.c
View file @
179c1e3c
...
@@ -46,6 +46,7 @@
...
@@ -46,6 +46,7 @@
#include <asm/exception.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
#include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h"
#include "irqchip.h"
union
gic_base
{
union
gic_base
{
...
@@ -188,12 +189,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
...
@@ -188,12 +189,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{
{
void
__iomem
*
base
=
gic_dist_base
(
d
);
void
__iomem
*
base
=
gic_dist_base
(
d
);
unsigned
int
gicirq
=
gic_irq
(
d
);
unsigned
int
gicirq
=
gic_irq
(
d
);
u32
enablemask
=
1
<<
(
gicirq
%
32
);
u32
enableoff
=
(
gicirq
/
32
)
*
4
;
u32
confmask
=
0x2
<<
((
gicirq
%
16
)
*
2
);
u32
confoff
=
(
gicirq
/
16
)
*
4
;
bool
enabled
=
false
;
u32
val
;
/* Interrupt configuration for SGIs can't be changed */
/* Interrupt configuration for SGIs can't be changed */
if
(
gicirq
<
16
)
if
(
gicirq
<
16
)
...
@@ -207,25 +202,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
...
@@ -207,25 +202,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if
(
gic_arch_extn
.
irq_set_type
)
if
(
gic_arch_extn
.
irq_set_type
)
gic_arch_extn
.
irq_set_type
(
d
,
type
);
gic_arch_extn
.
irq_set_type
(
d
,
type
);
val
=
readl_relaxed
(
base
+
GIC_DIST_CONFIG
+
confoff
);
gic_configure_irq
(
gicirq
,
type
,
base
,
NULL
);
if
(
type
==
IRQ_TYPE_LEVEL_HIGH
)
val
&=
~
confmask
;
else
if
(
type
==
IRQ_TYPE_EDGE_RISING
)
val
|=
confmask
;
/*
* As recommended by the spec, disable the interrupt before changing
* the configuration
*/
if
(
readl_relaxed
(
base
+
GIC_DIST_ENABLE_SET
+
enableoff
)
&
enablemask
)
{
writel_relaxed
(
enablemask
,
base
+
GIC_DIST_ENABLE_CLEAR
+
enableoff
);
enabled
=
true
;
}
writel_relaxed
(
val
,
base
+
GIC_DIST_CONFIG
+
confoff
);
if
(
enabled
)
writel_relaxed
(
enablemask
,
base
+
GIC_DIST_ENABLE_SET
+
enableoff
);
raw_spin_unlock
(
&
irq_controller_lock
);
raw_spin_unlock
(
&
irq_controller_lock
);
...
@@ -386,12 +363,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
...
@@ -386,12 +363,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
writel_relaxed
(
0
,
base
+
GIC_DIST_CTRL
);
writel_relaxed
(
0
,
base
+
GIC_DIST_CTRL
);
/*
* Set all global interrupts to be level triggered, active low.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
16
)
writel_relaxed
(
0
,
base
+
GIC_DIST_CONFIG
+
i
*
4
/
16
);
/*
/*
* Set all global interrupts to this CPU only.
* Set all global interrupts to this CPU only.
*/
*/
...
@@ -401,18 +372,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
...
@@ -401,18 +372,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
4
)
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
4
)
writel_relaxed
(
cpumask
,
base
+
GIC_DIST_TARGET
+
i
*
4
/
4
);
writel_relaxed
(
cpumask
,
base
+
GIC_DIST_TARGET
+
i
*
4
/
4
);
/*
gic_dist_config
(
base
,
gic_irqs
,
NULL
);
* Set priority on all global interrupts.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
4
)
writel_relaxed
(
0xa0a0a0a0
,
base
+
GIC_DIST_PRI
+
i
*
4
/
4
);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
for
(
i
=
32
;
i
<
gic_irqs
;
i
+=
32
)
writel_relaxed
(
0xffffffff
,
base
+
GIC_DIST_ENABLE_CLEAR
+
i
*
4
/
32
);
writel_relaxed
(
1
,
base
+
GIC_DIST_CTRL
);
writel_relaxed
(
1
,
base
+
GIC_DIST_CTRL
);
}
}
...
@@ -439,18 +399,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
...
@@ -439,18 +399,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
if
(
i
!=
cpu
)
if
(
i
!=
cpu
)
gic_cpu_map
[
i
]
&=
~
cpu_mask
;
gic_cpu_map
[
i
]
&=
~
cpu_mask
;
/*
gic_cpu_config
(
dist_base
,
NULL
);
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel_relaxed
(
0xffff0000
,
dist_base
+
GIC_DIST_ENABLE_CLEAR
);
writel_relaxed
(
0x0000ffff
,
dist_base
+
GIC_DIST_ENABLE_SET
);
/*
* Set priority on PPI and SGI interrupts
*/
for
(
i
=
0
;
i
<
32
;
i
+=
4
)
writel_relaxed
(
0xa0a0a0a0
,
dist_base
+
GIC_DIST_PRI
+
i
*
4
/
4
);
writel_relaxed
(
0xf0
,
base
+
GIC_CPU_PRIMASK
);
writel_relaxed
(
0xf0
,
base
+
GIC_CPU_PRIMASK
);
writel_relaxed
(
1
,
base
+
GIC_CPU_CTRL
);
writel_relaxed
(
1
,
base
+
GIC_CPU_CTRL
);
...
...
include/linux/irqchip/arm-gic-v3.h
0 → 100644
View file @
179c1e3c
/*
* Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LINUX_IRQCHIP_ARM_GIC_V3_H
#define __LINUX_IRQCHIP_ARM_GIC_V3_H
/*
* Distributor registers. We assume we're running non-secure, with ARE
* being set. Secure-only and non-ARE registers are not described.
*/
#define GICD_CTLR 0x0000
#define GICD_TYPER 0x0004
#define GICD_IIDR 0x0008
#define GICD_STATUSR 0x0010
#define GICD_SETSPI_NSR 0x0040
#define GICD_CLRSPI_NSR 0x0048
#define GICD_SETSPI_SR 0x0050
#define GICD_CLRSPI_SR 0x0058
#define GICD_SEIR 0x0068
#define GICD_ISENABLER 0x0100
#define GICD_ICENABLER 0x0180
#define GICD_ISPENDR 0x0200
#define GICD_ICPENDR 0x0280
#define GICD_ISACTIVER 0x0300
#define GICD_ICACTIVER 0x0380
#define GICD_IPRIORITYR 0x0400
#define GICD_ICFGR 0x0C00
#define GICD_IROUTER 0x6000
#define GICD_PIDR2 0xFFE8
#define GICD_CTLR_RWP (1U << 31)
#define GICD_CTLR_ARE_NS (1U << 4)
#define GICD_CTLR_ENABLE_G1A (1U << 1)
#define GICD_CTLR_ENABLE_G1 (1U << 0)
#define GICD_IROUTER_SPI_MODE_ONE (0U << 31)
#define GICD_IROUTER_SPI_MODE_ANY (1U << 31)
#define GIC_PIDR2_ARCH_MASK 0xf0
#define GIC_PIDR2_ARCH_GICv3 0x30
#define GIC_PIDR2_ARCH_GICv4 0x40
/*
* Re-Distributor registers, offsets from RD_base
*/
#define GICR_CTLR GICD_CTLR
#define GICR_IIDR 0x0004
#define GICR_TYPER 0x0008
#define GICR_STATUSR GICD_STATUSR
#define GICR_WAKER 0x0014
#define GICR_SETLPIR 0x0040
#define GICR_CLRLPIR 0x0048
#define GICR_SEIR GICD_SEIR
#define GICR_PROPBASER 0x0070
#define GICR_PENDBASER 0x0078
#define GICR_INVLPIR 0x00A0
#define GICR_INVALLR 0x00B0
#define GICR_SYNCR 0x00C0
#define GICR_MOVLPIR 0x0100
#define GICR_MOVALLR 0x0110
#define GICR_PIDR2 GICD_PIDR2
#define GICR_WAKER_ProcessorSleep (1U << 1)
#define GICR_WAKER_ChildrenAsleep (1U << 2)
/*
* Re-Distributor registers, offsets from SGI_base
*/
#define GICR_ISENABLER0 GICD_ISENABLER
#define GICR_ICENABLER0 GICD_ICENABLER
#define GICR_ISPENDR0 GICD_ISPENDR
#define GICR_ICPENDR0 GICD_ICPENDR
#define GICR_ISACTIVER0 GICD_ISACTIVER
#define GICR_ICACTIVER0 GICD_ICACTIVER
#define GICR_IPRIORITYR0 GICD_IPRIORITYR
#define GICR_ICFGR0 GICD_ICFGR
#define GICR_TYPER_VLPIS (1U << 1)
#define GICR_TYPER_LAST (1U << 4)
/*
* CPU interface registers
*/
#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1)
#define ICC_CTLR_EL1_EOImode_drop (1U << 1)
#define ICC_SRE_EL1_SRE (1U << 0)
/*
* Hypervisor interface registers (SRE only)
*/
#define ICH_LR_VIRTUAL_ID_MASK ((1UL << 32) - 1)
#define ICH_LR_EOI (1UL << 41)
#define ICH_LR_GROUP (1UL << 60)
#define ICH_LR_STATE (3UL << 62)
#define ICH_LR_PENDING_BIT (1UL << 62)
#define ICH_LR_ACTIVE_BIT (1UL << 63)
#define ICH_MISR_EOI (1 << 0)
#define ICH_MISR_U (1 << 1)
#define ICH_HCR_EN (1 << 0)
#define ICH_HCR_UIE (1 << 1)
#define ICH_VMCR_CTLR_SHIFT 0
#define ICH_VMCR_CTLR_MASK (0x21f << ICH_VMCR_CTLR_SHIFT)
#define ICH_VMCR_BPR1_SHIFT 18
#define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT)
#define ICH_VMCR_BPR0_SHIFT 21
#define ICH_VMCR_BPR0_MASK (7 << ICH_VMCR_BPR0_SHIFT)
#define ICH_VMCR_PMR_SHIFT 24
#define ICH_VMCR_PMR_MASK (0xffUL << ICH_VMCR_PMR_SHIFT)
#define ICC_EOIR1_EL1 S3_0_C12_C12_1
#define ICC_IAR1_EL1 S3_0_C12_C12_0
#define ICC_SGI1R_EL1 S3_0_C12_C11_5
#define ICC_PMR_EL1 S3_0_C4_C6_0
#define ICC_CTLR_EL1 S3_0_C12_C12_4
#define ICC_SRE_EL1 S3_0_C12_C12_5
#define ICC_GRPEN1_EL1 S3_0_C12_C12_7
#define ICC_IAR1_EL1_SPURIOUS 0x3ff
#define ICC_SRE_EL2 S3_4_C12_C9_5
#define ICC_SRE_EL2_SRE (1 << 0)
#define ICC_SRE_EL2_ENABLE (1 << 3)
/*
* System register definitions
*/
#define ICH_VSEIR_EL2 S3_4_C12_C9_4
#define ICH_HCR_EL2 S3_4_C12_C11_0
#define ICH_VTR_EL2 S3_4_C12_C11_1
#define ICH_MISR_EL2 S3_4_C12_C11_2
#define ICH_EISR_EL2 S3_4_C12_C11_3
#define ICH_ELSR_EL2 S3_4_C12_C11_5
#define ICH_VMCR_EL2 S3_4_C12_C11_7
#define __LR0_EL2(x) S3_4_C12_C12_ ## x
#define __LR8_EL2(x) S3_4_C12_C13_ ## x
#define ICH_LR0_EL2 __LR0_EL2(0)
#define ICH_LR1_EL2 __LR0_EL2(1)
#define ICH_LR2_EL2 __LR0_EL2(2)
#define ICH_LR3_EL2 __LR0_EL2(3)
#define ICH_LR4_EL2 __LR0_EL2(4)
#define ICH_LR5_EL2 __LR0_EL2(5)
#define ICH_LR6_EL2 __LR0_EL2(6)
#define ICH_LR7_EL2 __LR0_EL2(7)
#define ICH_LR8_EL2 __LR8_EL2(0)
#define ICH_LR9_EL2 __LR8_EL2(1)
#define ICH_LR10_EL2 __LR8_EL2(2)
#define ICH_LR11_EL2 __LR8_EL2(3)
#define ICH_LR12_EL2 __LR8_EL2(4)
#define ICH_LR13_EL2 __LR8_EL2(5)
#define ICH_LR14_EL2 __LR8_EL2(6)
#define ICH_LR15_EL2 __LR8_EL2(7)
#define __AP0Rx_EL2(x) S3_4_C12_C8_ ## x
#define ICH_AP0R0_EL2 __AP0Rx_EL2(0)
#define ICH_AP0R1_EL2 __AP0Rx_EL2(1)
#define ICH_AP0R2_EL2 __AP0Rx_EL2(2)
#define ICH_AP0R3_EL2 __AP0Rx_EL2(3)
#define __AP1Rx_EL2(x) S3_4_C12_C9_ ## x
#define ICH_AP1R0_EL2 __AP1Rx_EL2(0)
#define ICH_AP1R1_EL2 __AP1Rx_EL2(1)
#define ICH_AP1R2_EL2 __AP1Rx_EL2(2)
#define ICH_AP1R3_EL2 __AP1Rx_EL2(3)
#ifndef __ASSEMBLY__
#include <linux/stringify.h>
static
inline
void
gic_write_eoir
(
u64
irq
)
{
asm
volatile
(
"msr "
__stringify
(
ICC_EOIR1_EL1
)
", %0"
:
:
"r"
(
irq
));
isb
();
}
#endif
#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