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:
...
@@ -272,17 +272,18 @@ smp4m_ticker:
*/
*/
maybe_smp4m_msg
:
maybe_smp4m_msg
:
GET_PROCESSOR4M_ID
(
o3
)
GET_PROCESSOR4M_ID
(
o3
)
set
sun4m_interrupts
,
%
l5
sethi
%
hi
(
sun4m_irq_percpu
),
%
l5
ld
[%
l5
],
%
o5
sll
%
o3
,
2
,
%
o3
or
%
l5
,
%
lo
(
sun4m_irq_percpu
),
%
o5
sethi
%
hi
(
0x40000000
),
%
o2
sethi
%
hi
(
0x40000000
),
%
o2
sll
%
o3
,
12
,
%
o3
ld
[%
o5
+
%
o3
],
%
o1
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
be
,
a
smp4m_ticker
cmp
%
l7
,
14
cmp
%
l7
,
14
st
%
o2
,
[%
o
5
+
0x4
]
st
%
o2
,
[%
o
1
+
0x04
]
!
sun4m_irq_percpu
[
cpu
]->
clear
=
0x40000000
WRITE_PAUSE
WRITE_PAUSE
ld
[%
o
5
],
%
g0
ld
[%
o
1
+
0x00
],
%
g0
!
sun4m_irq_percpu
[
cpu
]->
pending
WRITE_PAUSE
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
wr
%
l4
,
0x0
,
%
psr
...
@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
...
@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
SAVE_ALL
SAVE_ALL
sethi
%
hi
(
0x80000000
),
%
o2
sethi
%
hi
(
0x80000000
),
%
o2
GET_PROCESSOR4M_ID
(
o0
)
GET_PROCESSOR4M_ID
(
o0
)
set
sun4m_interrupts
,
%
l5
set
hi
%
hi
(
sun4m_irq_percpu
)
,
%
l5
ld
[%
l5
]
,
%
o5
or
%
l5
,
%
lo
(
sun4m_irq_percpu
)
,
%
o5
sll
%
o0
,
1
2
,
%
o0
sll
%
o0
,
2
,
%
o0
add
%
o5
,
%
o0
,
%
o5
ld
[%
o5
+
%
o0
]
,
%
o5
ld
[%
o5
],
%
o3
ld
[%
o5
+
0x00
],
%
o3
!
sun4m_irq_percpu
[
cpu
]->
pending
andcc
%
o3
,
%
o2
,
%
g0
andcc
%
o3
,
%
o2
,
%
g0
be
1
f
!
Must
be
an
NMI
async
memory
error
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
WRITE_PAUSE
ld
[%
o5
],
%
g0
ld
[%
o5
+
0x00
],
%
g0
!
sun4m_irq_percpu
[
cpu
]->
pending
WRITE_PAUSE
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
wr
%
l4
,
0x0
,
%
psr
...
@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
...
@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
1
:
1
:
/
*
NMI
async
memory
error
handling
.
*/
/
*
NMI
async
memory
error
handling
.
*/
sethi
%
hi
(
0x80000000
),
%
l4
sethi
%
hi
(
0x80000000
),
%
l4
sethi
%
hi
(
0x4000
),
%
o3
sethi
%
hi
(
sun4m_irq_global
),
%
o5
sub
%
o5
,
%
o0
,
%
o5
ld
[%
o5
+
%
lo
(
sun4m_irq_global
)],
%
l5
add
%
o5
,
%
o3
,
%
l5
st
%
l4
,
[%
l5
+
0x0c
]
!
sun4m_irq_global
->
mask_set
=
0x80000000
st
%
l4
,
[%
l5
+
0xc
]
WRITE_PAUSE
WRITE_PAUSE
ld
[%
l5
],
%
g0
ld
[%
l5
+
0x00
],
%
g0
!
sun4m_irq_global
->
pending
WRITE_PAUSE
WRITE_PAUSE
or
%
l0
,
PSR_PIL
,
%
l4
or
%
l0
,
PSR_PIL
,
%
l4
wr
%
l4
,
0x0
,
%
psr
wr
%
l4
,
0x0
,
%
psr
...
@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
...
@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
WRITE_PAUSE
WRITE_PAUSE
call
sun4m_nmi
call
sun4m_nmi
nop
nop
st
%
l4
,
[%
l5
+
0x
8
]
st
%
l4
,
[%
l5
+
0x
08
]
!
sun4m_irq_global
->
mask_clear
=
0x80000000
WRITE_PAUSE
WRITE_PAUSE
ld
[%
l5
],
%
g0
ld
[%
l5
+
0x00
],
%
g0
!
sun4m_irq_global
->
pending
WRITE_PAUSE
WRITE_PAUSE
RESTORE_ALL
RESTORE_ALL
...
...
arch/sparc/kernel/sun4m_irq.c
View file @
69c010b2
...
@@ -41,53 +41,25 @@
...
@@ -41,53 +41,25 @@
#include "irq.h"
#include "irq.h"
/* On the sun4m, just like the timers, we have both per-cpu and master
struct
sun4m_irq_percpu
{
* interrupt registers.
u32
pending
;
*/
u32
clear
;
u32
set
;
/* 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_global
{
* djhr
u32
pending
;
* Actually the clear and set fields in this struct are misleading..
u32
mask
;
* according to the SLAVIO manual (and the same applies for the SEC)
u32
mask_clear
;
* the clear field clears bits in the mask which will ENABLE that IRQ
u32
mask_set
;
* the set field sets bits in the mask to DISABLE the IRQ.
u32
interrupt_target
;
*
* 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. */
};
};
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
;
unsigned
long
*
irq_rcvreg
=
&
dummy
;
/* Dave Redman (djhr@tadpole.co.uk)
/* Dave Redman (djhr@tadpole.co.uk)
...
@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
...
@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
mask
=
sun4m_get_irqmask
(
irq_nr
);
mask
=
sun4m_get_irqmask
(
irq_nr
);
local_irq_save
(
flags
);
local_irq_save
(
flags
);
if
(
irq_nr
>
15
)
if
(
irq_nr
>
15
)
s
un4m_interrupts
->
set
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_global
->
mask_set
)
;
else
else
s
un4m_interrupts
->
cpu_intregs
[
cpu
].
set
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
set
)
;
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
}
}
...
@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
...
@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
mask
=
sun4m_get_irqmask
(
irq_nr
);
mask
=
sun4m_get_irqmask
(
irq_nr
);
local_irq_save
(
flags
);
local_irq_save
(
flags
);
if
(
irq_nr
>
15
)
if
(
irq_nr
>
15
)
s
un4m_interrupts
->
clear
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_global
->
mask_clear
)
;
else
else
s
un4m_interrupts
->
cpu_intregs
[
cpu
].
clear
=
mask
;
s
bus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
clear
)
;
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
}
else
{
}
else
{
local_irq_save
(
flags
);
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
);
local_irq_restore
(
flags
);
}
}
}
}
...
@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
...
@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
*/
*/
static
void
sun4m_disable_pil_irq
(
unsigned
int
pil
)
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
)
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
#ifdef CONFIG_SMP
static
void
sun4m_send_ipi
(
int
cpu
,
int
level
)
static
void
sun4m_send_ipi
(
int
cpu
,
int
level
)
{
{
unsigned
long
mask
;
unsigned
long
mask
=
sun4m_get_irqmask
(
level
);
sbus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
set
);
mask
=
sun4m_get_irqmask
(
level
);
sun4m_interrupts
->
cpu_intregs
[
cpu
].
set
=
mask
;
}
}
static
void
sun4m_clear_ipi
(
int
cpu
,
int
level
)
static
void
sun4m_clear_ipi
(
int
cpu
,
int
level
)
{
{
unsigned
long
mask
;
unsigned
long
mask
=
sun4m_get_irqmask
(
level
);
sbus_writel
(
mask
,
&
sun4m_irq_percpu
[
cpu
]
->
clear
);
mask
=
sun4m_get_irqmask
(
level
);
sun4m_interrupts
->
cpu_intregs
[
cpu
].
clear
=
mask
;
}
}
static
void
sun4m_set_udt
(
int
cpu
)
static
void
sun4m_set_udt
(
int
cpu
)
{
{
s
un4m_interrupts
->
undirected_target
=
cpu
;
s
bus_writel
(
cpu
,
&
sun4m_irq_global
->
interrupt_target
)
;
}
}
#endif
#endif
...
@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
...
@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
for
(
i
=
0
;
i
<
num_cpu_timers
;
i
++
)
for
(
i
=
0
;
i
<
num_cpu_timers
;
i
++
)
sbus_writel
(
0
,
&
timers_percpu
[
i
]
->
l14_limit
);
sbus_writel
(
0
,
&
timers_percpu
[
i
]
->
l14_limit
);
if
(
num_cpu_timers
==
4
)
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
#ifdef CONFIG_SMP
{
{
...
@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
...
@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
void
__init
sun4m_init_IRQ
(
void
)
void
__init
sun4m_init_IRQ
(
void
)
{
{
int
ie_node
,
i
;
struct
device_node
*
dp
=
of_find_node_by_name
(
NULL
,
"interrupt"
);
struct
linux_prom_registers
int_regs
[
PROMREG_MAX
];
int
len
,
i
,
mid
,
num_cpu_iregs
;
int
num_regs
;
const
u32
*
addr
;
struct
resource
r
;
int
mid
;
if
(
!
dp
)
{
printk
(
KERN_ERR
"sun4m_init_IRQ: No 'interrupt' node.
\n
"
);
local_irq_disable
();
return
;
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
();
}
}
num_regs
=
prom_getproperty
(
ie_node
,
"reg"
,
(
char
*
)
int_regs
,
sizeof
(
int_regs
));
addr
=
of_get_property
(
dp
,
"address"
,
&
len
);
num_regs
=
(
num_regs
/
sizeof
(
struct
linux_prom_registers
));
if
(
!
addr
)
{
printk
(
KERN_ERR
"sun4m_init_IRQ: No 'address' prop.
\n
"
);
/* Apply the obio ranges to these registers. */
return
;
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
;
}
}
memset
((
char
*
)
&
r
,
0
,
sizeof
(
struct
resource
));
num_cpu_iregs
=
(
len
/
sizeof
(
u32
))
-
1
;
/* Map the interrupt registers for all possible cpus. */
for
(
i
=
0
;
i
<
num_cpu_iregs
;
i
++
)
{
r
.
flags
=
int_regs
[
0
].
which_io
;
sun4m_irq_percpu
[
i
]
=
(
void
__iomem
*
)
r
.
start
=
int_regs
[
0
].
phys_addr
;
(
unsigned
long
)
addr
[
i
];
sun4m_interrupts
=
(
struct
sun4m_intregs
*
)
of_ioremap
(
&
r
,
0
,
}
PAGE_SIZE
*
SUN4M_NCPUS
,
"interrupts_percpu"
);
sun4m_irq_global
=
(
void
__iomem
*
)
(
unsigned
long
)
addr
[
num_cpu_iregs
];
/* Map the system interrupt control registers. */
local_irq_disable
();
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"
);
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
++
)
for
(
i
=
0
;
!
cpu_find_by_instance
(
i
,
NULL
,
&
mid
);
i
++
)
sun4m_interrupts
->
cpu_intregs
[
mid
].
clear
=
~
0x17fff
;
sbus_writel
(
~
0x17fff
,
&
sun4m_irq_percpu
[
mid
]
->
clear
);
if
(
!
cpu_find_by_instance
(
1
,
NULL
,
NULL
))
{
if
(
num_cpu_iregs
==
4
)
{
/* system wide interrupts go to cpu 0, this should always
irq_rcvreg
=
(
unsigned
long
*
)
&
sun4m_irq_global
->
interrupt_target
;
* be safe because it is guaranteed to be fitted or OBP doesn't
sbus_writel
(
0
,
&
sun4m_irq_global
->
interrupt_target
);
* 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
;
}
}
BTFIXUPSET_CALL
(
enable_irq
,
sun4m_enable_irq
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
enable_irq
,
sun4m_enable_irq
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
disable_irq
,
sun4m_disable_irq
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
disable_irq
,
sun4m_disable_irq
,
BTFIXUPCALL_NORM
);
...
@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
...
@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL
(
clear_cpu_int
,
sun4m_clear_ipi
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
clear_cpu_int
,
sun4m_clear_ipi
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
set_irq_udt
,
sun4m_set_udt
,
BTFIXUPCALL_NORM
);
BTFIXUPSET_CALL
(
set_irq_udt
,
sun4m_set_udt
,
BTFIXUPCALL_NORM
);
#endif
#endif
/* Cannot enable interrupts until OBP ticker is disabled. */
/* 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