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
69c010b2
Commit
69c010b2
authored
Sep 19, 2008
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sparc32: Use PROM device probing for sun4m irq registers.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
2e57572a
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
74 additions
and
129 deletions
+74
-129
arch/sparc/kernel/entry.S
arch/sparc/kernel/entry.S
+20
-20
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_irq.c
+54
-109
No files found.
arch/sparc/kernel/entry.S
View file @
69c010b2
...
...
@@ -272,17 +272,18 @@ smp4m_ticker:
*/
maybe_smp4m_msg
:
GET_PROCESSOR4M_ID
(
o3
)
set
sun4m_interrupts
,
%
l5
ld
[%
l5
],
%
o5
sethi
%
hi
(
sun4m_irq_percpu
),
%
l5
sll
%
o3
,
2
,
%
o3
or
%
l5
,
%
lo
(
sun4m_irq_percpu
),
%
o5
sethi
%
hi
(
0x40000000
),
%
o2
sll
%
o3
,
12
,
%
o3
ld
[%
o5
+
%
o3
],
%
o1
andcc
%
o1
,
%
o2
,
%
g0
ld
[%
o1
+
0x00
],
%
o3
!
sun4m_irq_percpu
[
cpu
]->
pending
andcc
%
o3
,
%
o2
,
%
g0
be
,
a
smp4m_ticker
cmp
%
l7
,
14
st
%
o2
,
[%
o
5
+
0x4
]
st
%
o2
,
[%
o
1
+
0x04
]
!
sun4m_irq_percpu
[
cpu
]->
clear
=
0x40000000
WRITE_PAUSE
ld
[%
o
5
],
%
g0
ld
[%
o
1
+
0x00
],
%
g0
!
sun4m_irq_percpu
[
cpu
]->
pending
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
...
...
@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
SAVE_ALL
sethi
%
hi
(
0x80000000
),
%
o2
GET_PROCESSOR4M_ID
(
o0
)
set
sun4m_interrupts
,
%
l5
ld
[%
l5
]
,
%
o5
sll
%
o0
,
1
2
,
%
o0
add
%
o5
,
%
o0
,
%
o5
ld
[%
o5
],
%
o3
set
hi
%
hi
(
sun4m_irq_percpu
)
,
%
l5
or
%
l5
,
%
lo
(
sun4m_irq_percpu
)
,
%
o5
sll
%
o0
,
2
,
%
o0
ld
[%
o5
+
%
o0
]
,
%
o5
ld
[%
o5
+
0x00
],
%
o3
!
sun4m_irq_percpu
[
cpu
]->
pending
andcc
%
o3
,
%
o2
,
%
g0
be
1
f
!
Must
be
an
NMI
async
memory
error
st
%
o2
,
[%
o5
+
4
]
st
%
o2
,
[%
o5
+
0x04
]
!
sun4m_irq_percpu
[
cpu
]->
clear
=
0x80000000
WRITE_PAUSE
ld
[%
o5
],
%
g0
ld
[%
o5
+
0x00
],
%
g0
!
sun4m_irq_percpu
[
cpu
]->
pending
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
...
...
@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
1
:
/
*
NMI
async
memory
error
handling
.
*/
sethi
%
hi
(
0x80000000
),
%
l4
sethi
%
hi
(
0x4000
),
%
o3
sub
%
o5
,
%
o0
,
%
o5
add
%
o5
,
%
o3
,
%
l5
st
%
l4
,
[%
l5
+
0xc
]
sethi
%
hi
(
sun4m_irq_global
),
%
o5
ld
[%
o5
+
%
lo
(
sun4m_irq_global
)],
%
l5
st
%
l4
,
[%
l5
+
0x0c
]
!
sun4m_irq_global
->
mask_set
=
0x80000000
WRITE_PAUSE
ld
[%
l5
],
%
g0
ld
[%
l5
+
0x00
],
%
g0
!
sun4m_irq_global
->
pending
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
...
...
@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
WRITE_PAUSE
call
sun4m_nmi
nop
st
%
l4
,
[%
l5
+
0x
8
]
st
%
l4
,
[%
l5
+
0x
08
]
!
sun4m_irq_global
->
mask_clear
=
0x80000000
WRITE_PAUSE
ld
[%
l5
],
%
g0
ld
[%
l5
+
0x00
],
%
g0
!
sun4m_irq_global
->
pending
WRITE_PAUSE
RESTORE_ALL
...
...
arch/sparc/kernel/sun4m_irq.c
View file @
69c010b2
...
...
@@ -41,53 +41,25 @@
#include "irq.h"
/* On the sun4m, just like the timers, we have both per-cpu and master
* interrupt registers.
*/
/* These registers are used for sending/receiving irqs from/to
* different cpu's.
*/
struct
sun4m_intreg_percpu
{
unsigned
int
tbt
;
/* Interrupts still pending for this cpu. */
/* These next two registers are WRITE-ONLY and are only
* "on bit" sensitive, "off bits" written have NO affect.
*/
unsigned
int
clear
;
/* Clear this cpus irqs here. */
unsigned
int
set
;
/* Set this cpus irqs here. */
unsigned
char
space
[
PAGE_SIZE
-
12
];
struct
sun4m_irq_percpu
{
u32
pending
;
u32
clear
;
u32
set
;
};
/*
* djhr
* Actually the clear and set fields in this struct are misleading..
* according to the SLAVIO manual (and the same applies for the SEC)
* the clear field clears bits in the mask which will ENABLE that IRQ
* the set field sets bits in the mask to DISABLE the IRQ.
*
* Also the undirected_xx address in the SLAVIO is defined as
* RESERVED and write only..
*
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
* sun4m machines, for MP the layout makes more sense.
*/
struct
sun4m_intregs
{
struct
sun4m_intreg_percpu
cpu_intregs
[
SUN4M_NCPUS
];
unsigned
int
tbt
;
/* IRQ's that are still pending. */
unsigned
int
irqs
;
/* Master IRQ bits. */
/* Again, like the above, two these registers are WRITE-ONLY. */
unsigned
int
clear
;
/* Clear master IRQ's by setting bits here. */
unsigned
int
set
;
/* Set master IRQ's by setting bits here. */
/* This register is both READ and WRITE. */
unsigned
int
undirected_target
;
/* Which cpu gets undirected irqs. */
struct
sun4m_irq_global
{
u32
pending
;
u32
mask
;
u32
mask_clear
;
u32
mask_set
;
u32
interrupt_target
;
};
static
unsigned
long
dummy
;
/* Code in entry.S needs to get at these register mappings. */
struct
sun4m_irq_percpu
__iomem
*
sun4m_irq_percpu
[
SUN4M_NCPUS
];
struct
sun4m_irq_global
__iomem
*
sun4m_irq_global
;
st
ruct
sun4m_intregs
*
sun4m_interrupts
;
st
atic
unsigned
long
dummy
;
unsigned
long
*
irq_rcvreg
=
&
dummy
;
/* Dave Redman (djhr@tadpole.co.uk)
...
...
@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
mask
=
sun4m_get_irqmask
(
irq_nr
);
local_irq_save
(
flags
);
if
(
irq_nr
>
15
)
s
un4m_interrupts
->
set
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_global
->
mask_set
)
;
else
s
un4m_interrupts
->
cpu_intregs
[
cpu
].
set
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
set
)
;
local_irq_restore
(
flags
);
}
...
...
@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
mask
=
sun4m_get_irqmask
(
irq_nr
);
local_irq_save
(
flags
);
if
(
irq_nr
>
15
)
s
un4m_interrupts
->
clear
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_global
->
mask_clear
)
;
else
s
un4m_interrupts
->
cpu_intregs
[
cpu
].
clear
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
clear
)
;
local_irq_restore
(
flags
);
}
else
{
local_irq_save
(
flags
);
s
un4m_interrupts
->
clear
=
SUN4M_INT_FLOPPY
;
s
bus_writel
(
SUN4M_INT_FLOPPY
,
&
sun4m_irq_global
->
mask_clear
)
;
local_irq_restore
(
flags
);
}
}
...
...
@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
*/
static
void
sun4m_disable_pil_irq
(
unsigned
int
pil
)
{
s
un4m_interrupts
->
set
=
cpu_pil_to_imask
[
pil
]
;
s
bus_writel
(
cpu_pil_to_imask
[
pil
],
&
sun4m_irq_global
->
mask_set
)
;
}
static
void
sun4m_enable_pil_irq
(
unsigned
int
pil
)
{
s
un4m_interrupts
->
clear
=
cpu_pil_to_imask
[
pil
]
;
s
bus_writel
(
cpu_pil_to_imask
[
pil
],
&
sun4m_irq_global
->
mask_clear
)
;
}
#ifdef CONFIG_SMP
static
void
sun4m_send_ipi
(
int
cpu
,
int
level
)
{
unsigned
long
mask
;
mask
=
sun4m_get_irqmask
(
level
);
sun4m_interrupts
->
cpu_intregs
[
cpu
].
set
=
mask
;
unsigned
long
mask
=
sun4m_get_irqmask
(
level
);
sbus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
set
);
}
static
void
sun4m_clear_ipi
(
int
cpu
,
int
level
)
{
unsigned
long
mask
;
mask
=
sun4m_get_irqmask
(
level
);
sun4m_interrupts
->
cpu_intregs
[
cpu
].
clear
=
mask
;
unsigned
long
mask
=
sun4m_get_irqmask
(
level
);
sbus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
clear
);
}
static
void
sun4m_set_udt
(
int
cpu
)
{
s
un4m_interrupts
->
undirected_target
=
cpu
;
s
bus_writel
(
cpu
,
&
sun4m_irq_global
->
interrupt_target
)
;
}
#endif
...
...
@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
for
(
i
=
0
;
i
<
num_cpu_timers
;
i
++
)
sbus_writel
(
0
,
&
timers_percpu
[
i
]
->
l14_limit
);
if
(
num_cpu_timers
==
4
)
sbus_writel
(
SUN4M_INT_E14
,
&
sun4m_i
nterrupts
->
set
);
sbus_writel
(
SUN4M_INT_E14
,
&
sun4m_i
rq_global
->
mask_
set
);
#ifdef CONFIG_SMP
{
...
...
@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
void
__init
sun4m_init_IRQ
(
void
)
{
int
ie_node
,
i
;
struct
linux_prom_registers
int_regs
[
PROMREG_MAX
];
int
num_regs
;
struct
resource
r
;
int
mid
;
local_irq_disable
();
if
((
ie_node
=
prom_searchsiblings
(
prom_getchild
(
prom_root_node
),
"obio"
))
==
0
||
(
ie_node
=
prom_getchild
(
ie_node
))
==
0
||
(
ie_node
=
prom_searchsiblings
(
ie_node
,
"interrupt"
))
==
0
)
{
prom_printf
(
"Cannot find /obio/interrupt node
\n
"
);
prom_halt
();
struct
device_node
*
dp
=
of_find_node_by_name
(
NULL
,
"interrupt"
);
int
len
,
i
,
mid
,
num_cpu_iregs
;
const
u32
*
addr
;
if
(
!
dp
)
{
printk
(
KERN_ERR
"sun4m_init_IRQ: No 'interrupt' node.
\n
"
);
return
;
}
num_regs
=
prom_getproperty
(
ie_node
,
"reg"
,
(
char
*
)
int_regs
,
sizeof
(
int_regs
));
num_regs
=
(
num_regs
/
sizeof
(
struct
linux_prom_registers
));
/* Apply the obio ranges to these registers. */
prom_apply_obio_ranges
(
int_regs
,
num_regs
);
int_regs
[
4
].
phys_addr
=
int_regs
[
num_regs
-
1
].
phys_addr
;
int_regs
[
4
].
reg_size
=
int_regs
[
num_regs
-
1
].
reg_size
;
int_regs
[
4
].
which_io
=
int_regs
[
num_regs
-
1
].
which_io
;
for
(
ie_node
=
1
;
ie_node
<
4
;
ie_node
++
)
{
int_regs
[
ie_node
].
phys_addr
=
int_regs
[
ie_node
-
1
].
phys_addr
+
PAGE_SIZE
;
int_regs
[
ie_node
].
reg_size
=
int_regs
[
ie_node
-
1
].
reg_size
;
int_regs
[
ie_node
].
which_io
=
int_regs
[
ie_node
-
1
].
which_io
;
addr
=
of_get_property
(
dp
,
"address"
,
&
len
);
if
(
!
addr
)
{
printk
(
KERN_ERR
"sun4m_init_IRQ: No 'address' prop.
\n
"
);
return
;
}
memset
((
char
*
)
&
r
,
0
,
sizeof
(
struct
resource
));
/* Map the interrupt registers for all possible cpus. */
r
.
flags
=
int_regs
[
0
].
which_io
;
r
.
start
=
int_regs
[
0
].
phys_addr
;
sun4m_interrupts
=
(
struct
sun4m_intregs
*
)
of_ioremap
(
&
r
,
0
,
PAGE_SIZE
*
SUN4M_NCPUS
,
"interrupts_percpu"
);
num_cpu_iregs
=
(
len
/
sizeof
(
u32
))
-
1
;
for
(
i
=
0
;
i
<
num_cpu_iregs
;
i
++
)
{
sun4m_irq_percpu
[
i
]
=
(
void
__iomem
*
)
(
unsigned
long
)
addr
[
i
];
}
sun4m_irq_global
=
(
void
__iomem
*
)
(
unsigned
long
)
addr
[
num_cpu_iregs
];
/* Map the system interrupt control registers. */
r
.
flags
=
int_regs
[
4
].
which_io
;
r
.
start
=
int_regs
[
4
].
phys_addr
;
of_ioremap
(
&
r
,
0
,
int_regs
[
4
].
reg_size
,
"interrupts_system"
);
local_irq_disable
();
s
un4m_interrupts
->
set
=
~
SUN4M_INT_MASKALL
;
s
bus_writel
(
~
SUN4M_INT_MASKALL
,
&
sun4m_irq_global
->
mask_set
)
;
for
(
i
=
0
;
!
cpu_find_by_instance
(
i
,
NULL
,
&
mid
);
i
++
)
sun4m_interrupts
->
cpu_intregs
[
mid
].
clear
=
~
0x17fff
;
if
(
!
cpu_find_by_instance
(
1
,
NULL
,
NULL
))
{
/* system wide interrupts go to cpu 0, this should always
* be safe because it is guaranteed to be fitted or OBP doesn't
* come up
*
* Not sure, but writing here on SLAVIO systems may puke
* so I don't do it unless there is more than 1 cpu.
*/
irq_rcvreg
=
(
unsigned
long
*
)
&
sun4m_interrupts
->
undirected_target
;
sun4m_interrupts
->
undirected_target
=
0
;
sbus_writel
(
~
0x17fff
,
&
sun4m_irq_percpu
[
mid
]
->
clear
);
if
(
num_cpu_iregs
==
4
)
{
irq_rcvreg
=
(
unsigned
long
*
)
&
sun4m_irq_global
->
interrupt_target
;
sbus_writel
(
0
,
&
sun4m_irq_global
->
interrupt_target
);
}
BTFIXUPSET_CALL
(
enable_irq
,
sun4m_enable_irq
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
disable_irq
,
sun4m_disable_irq
,
BTFIXUPCALL_NORM
);
...
...
@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL
(
clear_cpu_int
,
sun4m_clear_ipi
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
set_irq_udt
,
sun4m_set_udt
,
BTFIXUPCALL_NORM
);
#endif
/* Cannot enable interrupts until OBP ticker is disabled. */
}
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