mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-16 10:20:30 +00:00
Convert the interrupt queue from an array to a linked list. Implement
intr_dequeue in asm so that it can easily be modified to do light weight context switching.
This commit is contained in:
parent
12b51ad055
commit
4d574756ac
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=97265
@ -29,11 +29,12 @@
|
||||
#ifndef _MACHINE_INTR_MACHDEP_H_
|
||||
#define _MACHINE_INTR_MACHDEP_H_
|
||||
|
||||
#define NPIL (1 << 4)
|
||||
#define NIV (1 << 11)
|
||||
#define IRSR_BUSY (1 << 5)
|
||||
|
||||
#define IQ_SIZE (NPIL * 2)
|
||||
#define IQ_MASK (IQ_SIZE - 1)
|
||||
#define PIL_MAX (1 << 4)
|
||||
#define IV_MAX (1 << 11)
|
||||
|
||||
#define IR_FREE (PIL_MAX * 2)
|
||||
|
||||
#define IH_SHIFT PTR_SHIFT
|
||||
#define IQE_SHIFT 5
|
||||
@ -47,27 +48,19 @@
|
||||
#define PIL_FAST 13 /* fast interrupts */
|
||||
#define PIL_TICK 14
|
||||
|
||||
struct trapframe;
|
||||
|
||||
typedef void ih_func_t(struct trapframe *);
|
||||
typedef void iv_func_t(void *);
|
||||
|
||||
struct iqe {
|
||||
u_int iqe_tag;
|
||||
u_int iqe_pri;
|
||||
u_long iqe_vec;
|
||||
iv_func_t *iqe_func;
|
||||
void *iqe_arg;
|
||||
};
|
||||
|
||||
struct intr_queue {
|
||||
struct iqe iq_queue[IQ_SIZE]; /* must be first */
|
||||
u_long iq_head;
|
||||
u_long iq_tail;
|
||||
};
|
||||
|
||||
struct ithd;
|
||||
|
||||
struct intr_request {
|
||||
struct intr_request *ir_next;
|
||||
iv_func_t *ir_func;
|
||||
void *ir_arg;
|
||||
u_int ir_vec;
|
||||
u_int ir_pri;
|
||||
};
|
||||
|
||||
struct intr_vector {
|
||||
iv_func_t *iv_func;
|
||||
void *iv_arg;
|
||||
|
@ -45,7 +45,10 @@ struct vmspace;
|
||||
* point at the globaldata structure.
|
||||
*/
|
||||
#define PCPU_MD_FIELDS \
|
||||
struct intr_queue pc_iq; /* interrupt queue */ \
|
||||
struct intr_request pc_irpool[IR_FREE]; \
|
||||
struct intr_request *pc_irhead; \
|
||||
struct intr_request **pc_irtail; \
|
||||
struct intr_request *pc_irfree; \
|
||||
struct vmspace *pc_vmspace; \
|
||||
vm_offset_t pc_addr; \
|
||||
u_int pc_mid; \
|
||||
|
@ -358,10 +358,10 @@ ENTRY(rsf_fatal)
|
||||
sir
|
||||
END(rsf_fatal)
|
||||
|
||||
.comm intrnames, NIV * 8
|
||||
.comm intrnames, IV_MAX * 8
|
||||
.comm eintrnames, 0
|
||||
|
||||
.comm intrcnt, NIV * 8
|
||||
.comm intrcnt, IV_MAX * 8
|
||||
.comm eintrcnt, 0
|
||||
|
||||
/*
|
||||
@ -538,8 +538,12 @@ END(tl0_sfsr_trap)
|
||||
INTR_LEVEL(0)
|
||||
.endm
|
||||
|
||||
.macro tl0_intr_vector
|
||||
b,a %xcc, intr_enqueue
|
||||
.macro intr_vector
|
||||
ldxa [%g0] ASI_INTR_RECEIVE, %g1
|
||||
andcc %g1, IRSR_BUSY, %g0
|
||||
bnz,a,pt %xcc, intr_enqueue
|
||||
nop
|
||||
sir
|
||||
.align 32
|
||||
.endm
|
||||
|
||||
@ -1136,109 +1140,209 @@ END(tl1_sfsr_trap)
|
||||
INTR_LEVEL(1)
|
||||
.endm
|
||||
|
||||
.macro tl1_intr_vector
|
||||
b,a intr_enqueue
|
||||
.align 32
|
||||
.endm
|
||||
ENTRY(intr_dequeue)
|
||||
save %sp, -CCFSZ, %sp
|
||||
|
||||
1: ldx [PCPU(IRHEAD)], %l0
|
||||
brnz,a,pt %l0, 2f
|
||||
nop
|
||||
|
||||
ret
|
||||
restore
|
||||
|
||||
2: wrpr %g0, PSTATE_NORMAL, %pstate
|
||||
|
||||
ldx [%l0 + IR_NEXT], %l1
|
||||
brnz,pt %l1, 3f
|
||||
stx %l1, [PCPU(IRHEAD)]
|
||||
PCPU_ADDR(IRHEAD, %l1)
|
||||
stx %l1, [PCPU(IRTAIL)]
|
||||
|
||||
3: ldx [%l0 + IR_FUNC], %o0
|
||||
ldx [%l0 + IR_ARG], %o1
|
||||
ldx [%l0 + IR_VEC], %o2
|
||||
|
||||
ldx [PCPU(IRFREE)], %l1
|
||||
stx %l1, [%l0 + IR_NEXT]
|
||||
stx %l0, [PCPU(IRFREE)]
|
||||
|
||||
wrpr %g0, PSTATE_KERNEL, %pstate
|
||||
|
||||
call %o0
|
||||
mov %o1, %o0
|
||||
ba,a %xcc, 1b
|
||||
nop
|
||||
END(intr_dequeue)
|
||||
|
||||
/*
|
||||
* Handle a vectored interrupt.
|
||||
*
|
||||
* This is either a data bearing mondo vector interrupt, or a cross trap
|
||||
* request from another cpu. In either case the hardware supplies an
|
||||
* interrupt packet, in the form of 3 data words which are read from internal
|
||||
* registers. A data bearing mondo vector packet consists of an interrupt
|
||||
* number in the first data word, and zero in 2nd and 3rd. We use the
|
||||
* interrupt number to find the function, argument and priority from the
|
||||
* intr_vector table, allocate and fill in an intr_request from the per-cpu
|
||||
* free list, link it onto the per-cpu active list and finally post a softint
|
||||
* at the desired priority. Cross trap requests come in 2 forms, direct
|
||||
* and queued. Direct requests are distinguished by the first data word
|
||||
* being zero. The 2nd data word carries a function to call and the 3rd
|
||||
* an argument to pass. The function is jumped to directly. It executes
|
||||
* in nucleus context on interrupt globals and with all interrupts disabled,
|
||||
* therefore it must be fast, and the things that it can do are limited.
|
||||
* Queued cross trap requests are handled much like mondo vectors, except
|
||||
* that the function, argument and priority are contained in the interrupt
|
||||
* packet itself. They are distinguished by the upper 4 bits of the data
|
||||
* word being non-zero, which specifies the priority of the softint to
|
||||
* deliver.
|
||||
*
|
||||
* Register usage:
|
||||
* %g1 - pointer to intr_request
|
||||
* %g2 - pointer to intr_vector, temp once required data is loaded
|
||||
* %g3 - interrupt number for mondo vectors, unused otherwise
|
||||
* %g4 - function, from the interrupt packet for cross traps, or
|
||||
* loaded from the interrupt registers for mondo vecors
|
||||
* %g5 - argument, as above for %g4
|
||||
* %g6 - softint priority
|
||||
*/
|
||||
ENTRY(intr_enqueue)
|
||||
/*
|
||||
* Load the interrupt packet from the hardware.
|
||||
*/
|
||||
wr %g0, ASI_SDB_INTR_R, %asi
|
||||
ldxa [%g0] ASI_INTR_RECEIVE, %g2
|
||||
ldxa [%g0 + AA_SDB_INTR_D0] %asi, %g3
|
||||
ldxa [%g0 + AA_SDB_INTR_D1] %asi, %g4
|
||||
ldxa [%g0 + AA_SDB_INTR_D2] %asi, %g5
|
||||
stxa %g0, [%g0] ASI_INTR_RECEIVE
|
||||
membar #Sync
|
||||
|
||||
/*
|
||||
* If the second data word is present it points to code to execute
|
||||
* directly. Jump to it.
|
||||
*/
|
||||
brz,a,pt %g4, 1f
|
||||
nop
|
||||
jmpl %g4, %g0
|
||||
nop
|
||||
|
||||
/*
|
||||
* Find the head of the queue and advance it.
|
||||
*/
|
||||
1: ldx [PCPU(IQ) + IQ_HEAD], %g1
|
||||
add %g1, 1, %g6
|
||||
and %g6, IQ_MASK, %g6
|
||||
stx %g6, [PCPU(IQ) + IQ_HEAD]
|
||||
|
||||
/*
|
||||
* Find the iqe.
|
||||
*/
|
||||
sllx %g1, IQE_SHIFT, %g1
|
||||
add %g1, PCPU_REG, %g1
|
||||
add %g1, PC_IQ, %g1
|
||||
|
||||
/*
|
||||
* Store the tag and first data word in the iqe. These are always
|
||||
* valid.
|
||||
*/
|
||||
stw %g2, [%g1 + IQE_TAG]
|
||||
stx %g3, [%g1 + IQE_VEC]
|
||||
|
||||
#ifdef INVARIANTS
|
||||
/*
|
||||
* If the new head is the same as the tail, the next interrupt will
|
||||
* overwrite unserviced packets. This is bad.
|
||||
*/
|
||||
ldx [PCPU(IQ) + IQ_TAIL], %g2
|
||||
cmp %g2, %g6
|
||||
be %xcc, 2f
|
||||
nop
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: data=%#lx %#lx %#lx"
|
||||
, %g1, %g2, %g6, 7, 8, 9)
|
||||
stx %g3, [%g1 + KTR_PARM1]
|
||||
stx %g4, [%g1 + KTR_PARM2]
|
||||
stx %g5, [%g1 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load the function, argument and priority and store them in the iqe.
|
||||
* If the first data word is zero this is a direct cross trap request.
|
||||
* The 2nd word points to code to execute and the 3rd is an argument
|
||||
* to pass. Jump to it.
|
||||
*/
|
||||
sllx %g3, IV_SHIFT, %g3
|
||||
SET(intr_vectors, %g6, %g2)
|
||||
add %g2, %g3, %g2
|
||||
brnz,a,pt %g3, 1f
|
||||
nop
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: direct ipi func=%#lx arg=%#lx"
|
||||
, %g1, %g2, %g6, 7, 8, 9)
|
||||
stx %g4, [%g1 + KTR_PARM1]
|
||||
stx %g5, [%g1 + KTR_PARM2]
|
||||
9:
|
||||
#endif
|
||||
|
||||
jmpl %g4, %g0
|
||||
nop
|
||||
/* NOTREACHED */
|
||||
|
||||
/*
|
||||
* If the high 4 bits of the 1st data word are non-zero, this is a
|
||||
* queued cross trap request to be delivered as a softint. The high
|
||||
* 4 bits of the 1st data word specify a priority, and the 2nd and
|
||||
* 3rd a function and argument.
|
||||
*/
|
||||
1: srlx %g3, 60, %g6
|
||||
brnz,a,pn %g6, 2f
|
||||
clr %g3
|
||||
|
||||
/*
|
||||
* Find the function, argument and desired priority from the
|
||||
* intr_vector table.
|
||||
*/
|
||||
SET(intr_vectors, %g4, %g2)
|
||||
sllx %g3, IV_SHIFT, %g4
|
||||
add %g2, %g4, %g2
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: mondo vector func=%#lx arg=%#lx pri=%#lx"
|
||||
, %g4, %g5, %g6, 7, 8, 9)
|
||||
ldx [%g2 + IV_FUNC], %g5
|
||||
stx %g5, [%g4 + KTR_PARM1]
|
||||
ldx [%g2 + IV_ARG], %g5
|
||||
stx %g5, [%g4 + KTR_PARM2]
|
||||
ldx [%g2 + IV_PRI], %g5
|
||||
stx %g5, [%g4 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
ldx [%g2 + IV_FUNC], %g4
|
||||
ldx [%g2 + IV_ARG], %g5
|
||||
lduw [%g2 + IV_PRI], %g6
|
||||
stx %g4, [%g1 + IQE_FUNC]
|
||||
stx %g5, [%g1 + IQE_ARG]
|
||||
stw %g6, [%g1 + IQE_PRI]
|
||||
|
||||
ba,a %xcc, 3f
|
||||
nop
|
||||
|
||||
/*
|
||||
* Get a intr_request from the free list. There should always be one
|
||||
* unless we are getting an interrupt storm from stray interrupts, in
|
||||
* which case the we will deference a NULL pointer and panic.
|
||||
*/
|
||||
2:
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: head=%d tail=%d pri=%p tag=%#x vec=%#x"
|
||||
, %g2, %g3, %g4, 7, 8, 9)
|
||||
ldx [PCPU(IQ) + IQ_HEAD], %g3
|
||||
stx %g3, [%g2 + KTR_PARM1]
|
||||
ldx [PCPU(IQ) + IQ_TAIL], %g3
|
||||
stx %g3, [%g2 + KTR_PARM2]
|
||||
lduw [%g1 + IQE_PRI], %g3
|
||||
stx %g3, [%g2 + KTR_PARM3]
|
||||
lduw [%g1 + IQE_TAG], %g3
|
||||
stx %g3, [%g2 + KTR_PARM4]
|
||||
ldx [%g1 + IQE_VEC], %g3
|
||||
stx %g3, [%g2 + KTR_PARM5]
|
||||
CATR(KTR_INTR, "intr_enqueue: queued ipi func=%#lx arg=%#lx pri=%#lx"
|
||||
, %g1, %g2, %g3, 7, 8, 9)
|
||||
stx %g4, [%g1 + KTR_PARM1]
|
||||
stx %g5, [%g1 + KTR_PARM2]
|
||||
stx %g6, [%g1 + KTR_PARM3]
|
||||
9:
|
||||
clr %g3
|
||||
#endif
|
||||
|
||||
3:
|
||||
ldx [PCPU(IRFREE)], %g1
|
||||
ldx [%g1 + IR_NEXT], %g2
|
||||
stx %g2, [PCPU(IRFREE)]
|
||||
|
||||
/*
|
||||
* Store the vector number, function, argument and priority.
|
||||
*/
|
||||
stw %g3, [%g1 + IR_VEC]
|
||||
stx %g4, [%g1 + IR_FUNC]
|
||||
stx %g5, [%g1 + IR_ARG]
|
||||
stw %g6, [%g1 + IR_PRI]
|
||||
|
||||
/*
|
||||
* Link it onto the end of the active list.
|
||||
*/
|
||||
stx %g0, [%g1 + IR_NEXT]
|
||||
ldx [PCPU(IRTAIL)], %g4
|
||||
stx %g1, [%g4]
|
||||
add %g1, IR_NEXT, %g1
|
||||
stx %g1, [PCPU(IRTAIL)]
|
||||
|
||||
/*
|
||||
* Trigger a softint at the level indicated by the priority.
|
||||
*/
|
||||
mov 1, %g1
|
||||
sllx %g1, %g6, %g1
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: softint pil=%#lx pri=%#lx mask=%#lx"
|
||||
, %g2, %g3, %g4, 7, 8, 9)
|
||||
rdpr %pil, %g3
|
||||
stx %g3, [%g2 + KTR_PARM1]
|
||||
stx %g6, [%g2 + KTR_PARM2]
|
||||
stx %g1, [%g2 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
wr %g1, 0, %asr20
|
||||
|
||||
retry
|
||||
|
||||
#ifdef INVARIANTS
|
||||
/*
|
||||
* The interrupt queue is about to overflow. We are in big trouble.
|
||||
* Done, retry the instruction.
|
||||
*/
|
||||
2: sir
|
||||
#endif
|
||||
retry
|
||||
END(intr_enqueue)
|
||||
|
||||
.macro tl1_immu_miss
|
||||
@ -1759,7 +1863,7 @@ tl0_intr_level:
|
||||
tl0_intr_level ! 0x41-0x4f
|
||||
tl0_reserved 16 ! 0x50-0x5f
|
||||
tl0_intr_vector:
|
||||
tl0_intr_vector ! 0x60
|
||||
intr_vector ! 0x60
|
||||
tl0_watch_phys:
|
||||
tl0_gen T_PA_WATCHPOINT ! 0x61
|
||||
tl0_watch_virt:
|
||||
@ -1859,7 +1963,7 @@ tl1_intr_level:
|
||||
tl1_intr_level ! 0x241-0x24f
|
||||
tl1_reserved 16 ! 0x250-0x25f
|
||||
tl1_intr_vector:
|
||||
tl1_intr_vector ! 0x260
|
||||
intr_vector ! 0x260
|
||||
tl1_watch_phys:
|
||||
tl1_gen T_PA_WATCHPOINT ! 0x261
|
||||
tl1_watch_virt:
|
||||
@ -2432,8 +2536,7 @@ ENTRY(tl1_trap)
|
||||
, %g1, %g2, %g3, 7, 8, 9)
|
||||
ldx [PCPU(CURTHREAD)], %g2
|
||||
stx %g2, [%g1 + KTR_PARM1]
|
||||
andn %o0, T_KERNEL, %g2
|
||||
stx %g2, [%g1 + KTR_PARM2]
|
||||
stx %o0, [%g1 + KTR_PARM2]
|
||||
stx %l3, [%g1 + KTR_PARM3]
|
||||
stx %l1, [%g1 + KTR_PARM4]
|
||||
stx %i6, [%g1 + KTR_PARM5]
|
||||
|
@ -358,10 +358,10 @@ ENTRY(rsf_fatal)
|
||||
sir
|
||||
END(rsf_fatal)
|
||||
|
||||
.comm intrnames, NIV * 8
|
||||
.comm intrnames, IV_MAX * 8
|
||||
.comm eintrnames, 0
|
||||
|
||||
.comm intrcnt, NIV * 8
|
||||
.comm intrcnt, IV_MAX * 8
|
||||
.comm eintrcnt, 0
|
||||
|
||||
/*
|
||||
@ -538,8 +538,12 @@ END(tl0_sfsr_trap)
|
||||
INTR_LEVEL(0)
|
||||
.endm
|
||||
|
||||
.macro tl0_intr_vector
|
||||
b,a %xcc, intr_enqueue
|
||||
.macro intr_vector
|
||||
ldxa [%g0] ASI_INTR_RECEIVE, %g1
|
||||
andcc %g1, IRSR_BUSY, %g0
|
||||
bnz,a,pt %xcc, intr_enqueue
|
||||
nop
|
||||
sir
|
||||
.align 32
|
||||
.endm
|
||||
|
||||
@ -1136,109 +1140,209 @@ END(tl1_sfsr_trap)
|
||||
INTR_LEVEL(1)
|
||||
.endm
|
||||
|
||||
.macro tl1_intr_vector
|
||||
b,a intr_enqueue
|
||||
.align 32
|
||||
.endm
|
||||
ENTRY(intr_dequeue)
|
||||
save %sp, -CCFSZ, %sp
|
||||
|
||||
1: ldx [PCPU(IRHEAD)], %l0
|
||||
brnz,a,pt %l0, 2f
|
||||
nop
|
||||
|
||||
ret
|
||||
restore
|
||||
|
||||
2: wrpr %g0, PSTATE_NORMAL, %pstate
|
||||
|
||||
ldx [%l0 + IR_NEXT], %l1
|
||||
brnz,pt %l1, 3f
|
||||
stx %l1, [PCPU(IRHEAD)]
|
||||
PCPU_ADDR(IRHEAD, %l1)
|
||||
stx %l1, [PCPU(IRTAIL)]
|
||||
|
||||
3: ldx [%l0 + IR_FUNC], %o0
|
||||
ldx [%l0 + IR_ARG], %o1
|
||||
ldx [%l0 + IR_VEC], %o2
|
||||
|
||||
ldx [PCPU(IRFREE)], %l1
|
||||
stx %l1, [%l0 + IR_NEXT]
|
||||
stx %l0, [PCPU(IRFREE)]
|
||||
|
||||
wrpr %g0, PSTATE_KERNEL, %pstate
|
||||
|
||||
call %o0
|
||||
mov %o1, %o0
|
||||
ba,a %xcc, 1b
|
||||
nop
|
||||
END(intr_dequeue)
|
||||
|
||||
/*
|
||||
* Handle a vectored interrupt.
|
||||
*
|
||||
* This is either a data bearing mondo vector interrupt, or a cross trap
|
||||
* request from another cpu. In either case the hardware supplies an
|
||||
* interrupt packet, in the form of 3 data words which are read from internal
|
||||
* registers. A data bearing mondo vector packet consists of an interrupt
|
||||
* number in the first data word, and zero in 2nd and 3rd. We use the
|
||||
* interrupt number to find the function, argument and priority from the
|
||||
* intr_vector table, allocate and fill in an intr_request from the per-cpu
|
||||
* free list, link it onto the per-cpu active list and finally post a softint
|
||||
* at the desired priority. Cross trap requests come in 2 forms, direct
|
||||
* and queued. Direct requests are distinguished by the first data word
|
||||
* being zero. The 2nd data word carries a function to call and the 3rd
|
||||
* an argument to pass. The function is jumped to directly. It executes
|
||||
* in nucleus context on interrupt globals and with all interrupts disabled,
|
||||
* therefore it must be fast, and the things that it can do are limited.
|
||||
* Queued cross trap requests are handled much like mondo vectors, except
|
||||
* that the function, argument and priority are contained in the interrupt
|
||||
* packet itself. They are distinguished by the upper 4 bits of the data
|
||||
* word being non-zero, which specifies the priority of the softint to
|
||||
* deliver.
|
||||
*
|
||||
* Register usage:
|
||||
* %g1 - pointer to intr_request
|
||||
* %g2 - pointer to intr_vector, temp once required data is loaded
|
||||
* %g3 - interrupt number for mondo vectors, unused otherwise
|
||||
* %g4 - function, from the interrupt packet for cross traps, or
|
||||
* loaded from the interrupt registers for mondo vecors
|
||||
* %g5 - argument, as above for %g4
|
||||
* %g6 - softint priority
|
||||
*/
|
||||
ENTRY(intr_enqueue)
|
||||
/*
|
||||
* Load the interrupt packet from the hardware.
|
||||
*/
|
||||
wr %g0, ASI_SDB_INTR_R, %asi
|
||||
ldxa [%g0] ASI_INTR_RECEIVE, %g2
|
||||
ldxa [%g0 + AA_SDB_INTR_D0] %asi, %g3
|
||||
ldxa [%g0 + AA_SDB_INTR_D1] %asi, %g4
|
||||
ldxa [%g0 + AA_SDB_INTR_D2] %asi, %g5
|
||||
stxa %g0, [%g0] ASI_INTR_RECEIVE
|
||||
membar #Sync
|
||||
|
||||
/*
|
||||
* If the second data word is present it points to code to execute
|
||||
* directly. Jump to it.
|
||||
*/
|
||||
brz,a,pt %g4, 1f
|
||||
nop
|
||||
jmpl %g4, %g0
|
||||
nop
|
||||
|
||||
/*
|
||||
* Find the head of the queue and advance it.
|
||||
*/
|
||||
1: ldx [PCPU(IQ) + IQ_HEAD], %g1
|
||||
add %g1, 1, %g6
|
||||
and %g6, IQ_MASK, %g6
|
||||
stx %g6, [PCPU(IQ) + IQ_HEAD]
|
||||
|
||||
/*
|
||||
* Find the iqe.
|
||||
*/
|
||||
sllx %g1, IQE_SHIFT, %g1
|
||||
add %g1, PCPU_REG, %g1
|
||||
add %g1, PC_IQ, %g1
|
||||
|
||||
/*
|
||||
* Store the tag and first data word in the iqe. These are always
|
||||
* valid.
|
||||
*/
|
||||
stw %g2, [%g1 + IQE_TAG]
|
||||
stx %g3, [%g1 + IQE_VEC]
|
||||
|
||||
#ifdef INVARIANTS
|
||||
/*
|
||||
* If the new head is the same as the tail, the next interrupt will
|
||||
* overwrite unserviced packets. This is bad.
|
||||
*/
|
||||
ldx [PCPU(IQ) + IQ_TAIL], %g2
|
||||
cmp %g2, %g6
|
||||
be %xcc, 2f
|
||||
nop
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: data=%#lx %#lx %#lx"
|
||||
, %g1, %g2, %g6, 7, 8, 9)
|
||||
stx %g3, [%g1 + KTR_PARM1]
|
||||
stx %g4, [%g1 + KTR_PARM2]
|
||||
stx %g5, [%g1 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load the function, argument and priority and store them in the iqe.
|
||||
* If the first data word is zero this is a direct cross trap request.
|
||||
* The 2nd word points to code to execute and the 3rd is an argument
|
||||
* to pass. Jump to it.
|
||||
*/
|
||||
sllx %g3, IV_SHIFT, %g3
|
||||
SET(intr_vectors, %g6, %g2)
|
||||
add %g2, %g3, %g2
|
||||
brnz,a,pt %g3, 1f
|
||||
nop
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: direct ipi func=%#lx arg=%#lx"
|
||||
, %g1, %g2, %g6, 7, 8, 9)
|
||||
stx %g4, [%g1 + KTR_PARM1]
|
||||
stx %g5, [%g1 + KTR_PARM2]
|
||||
9:
|
||||
#endif
|
||||
|
||||
jmpl %g4, %g0
|
||||
nop
|
||||
/* NOTREACHED */
|
||||
|
||||
/*
|
||||
* If the high 4 bits of the 1st data word are non-zero, this is a
|
||||
* queued cross trap request to be delivered as a softint. The high
|
||||
* 4 bits of the 1st data word specify a priority, and the 2nd and
|
||||
* 3rd a function and argument.
|
||||
*/
|
||||
1: srlx %g3, 60, %g6
|
||||
brnz,a,pn %g6, 2f
|
||||
clr %g3
|
||||
|
||||
/*
|
||||
* Find the function, argument and desired priority from the
|
||||
* intr_vector table.
|
||||
*/
|
||||
SET(intr_vectors, %g4, %g2)
|
||||
sllx %g3, IV_SHIFT, %g4
|
||||
add %g2, %g4, %g2
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: mondo vector func=%#lx arg=%#lx pri=%#lx"
|
||||
, %g4, %g5, %g6, 7, 8, 9)
|
||||
ldx [%g2 + IV_FUNC], %g5
|
||||
stx %g5, [%g4 + KTR_PARM1]
|
||||
ldx [%g2 + IV_ARG], %g5
|
||||
stx %g5, [%g4 + KTR_PARM2]
|
||||
ldx [%g2 + IV_PRI], %g5
|
||||
stx %g5, [%g4 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
ldx [%g2 + IV_FUNC], %g4
|
||||
ldx [%g2 + IV_ARG], %g5
|
||||
lduw [%g2 + IV_PRI], %g6
|
||||
stx %g4, [%g1 + IQE_FUNC]
|
||||
stx %g5, [%g1 + IQE_ARG]
|
||||
stw %g6, [%g1 + IQE_PRI]
|
||||
|
||||
ba,a %xcc, 3f
|
||||
nop
|
||||
|
||||
/*
|
||||
* Get a intr_request from the free list. There should always be one
|
||||
* unless we are getting an interrupt storm from stray interrupts, in
|
||||
* which case the we will deference a NULL pointer and panic.
|
||||
*/
|
||||
2:
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: head=%d tail=%d pri=%p tag=%#x vec=%#x"
|
||||
, %g2, %g3, %g4, 7, 8, 9)
|
||||
ldx [PCPU(IQ) + IQ_HEAD], %g3
|
||||
stx %g3, [%g2 + KTR_PARM1]
|
||||
ldx [PCPU(IQ) + IQ_TAIL], %g3
|
||||
stx %g3, [%g2 + KTR_PARM2]
|
||||
lduw [%g1 + IQE_PRI], %g3
|
||||
stx %g3, [%g2 + KTR_PARM3]
|
||||
lduw [%g1 + IQE_TAG], %g3
|
||||
stx %g3, [%g2 + KTR_PARM4]
|
||||
ldx [%g1 + IQE_VEC], %g3
|
||||
stx %g3, [%g2 + KTR_PARM5]
|
||||
CATR(KTR_INTR, "intr_enqueue: queued ipi func=%#lx arg=%#lx pri=%#lx"
|
||||
, %g1, %g2, %g3, 7, 8, 9)
|
||||
stx %g4, [%g1 + KTR_PARM1]
|
||||
stx %g5, [%g1 + KTR_PARM2]
|
||||
stx %g6, [%g1 + KTR_PARM3]
|
||||
9:
|
||||
clr %g3
|
||||
#endif
|
||||
|
||||
3:
|
||||
ldx [PCPU(IRFREE)], %g1
|
||||
ldx [%g1 + IR_NEXT], %g2
|
||||
stx %g2, [PCPU(IRFREE)]
|
||||
|
||||
/*
|
||||
* Store the vector number, function, argument and priority.
|
||||
*/
|
||||
stw %g3, [%g1 + IR_VEC]
|
||||
stx %g4, [%g1 + IR_FUNC]
|
||||
stx %g5, [%g1 + IR_ARG]
|
||||
stw %g6, [%g1 + IR_PRI]
|
||||
|
||||
/*
|
||||
* Link it onto the end of the active list.
|
||||
*/
|
||||
stx %g0, [%g1 + IR_NEXT]
|
||||
ldx [PCPU(IRTAIL)], %g4
|
||||
stx %g1, [%g4]
|
||||
add %g1, IR_NEXT, %g1
|
||||
stx %g1, [PCPU(IRTAIL)]
|
||||
|
||||
/*
|
||||
* Trigger a softint at the level indicated by the priority.
|
||||
*/
|
||||
mov 1, %g1
|
||||
sllx %g1, %g6, %g1
|
||||
|
||||
#if KTR_COMPILE & KTR_INTR
|
||||
CATR(KTR_INTR, "intr_enqueue: softint pil=%#lx pri=%#lx mask=%#lx"
|
||||
, %g2, %g3, %g4, 7, 8, 9)
|
||||
rdpr %pil, %g3
|
||||
stx %g3, [%g2 + KTR_PARM1]
|
||||
stx %g6, [%g2 + KTR_PARM2]
|
||||
stx %g1, [%g2 + KTR_PARM3]
|
||||
9:
|
||||
#endif
|
||||
|
||||
wr %g1, 0, %asr20
|
||||
|
||||
retry
|
||||
|
||||
#ifdef INVARIANTS
|
||||
/*
|
||||
* The interrupt queue is about to overflow. We are in big trouble.
|
||||
* Done, retry the instruction.
|
||||
*/
|
||||
2: sir
|
||||
#endif
|
||||
retry
|
||||
END(intr_enqueue)
|
||||
|
||||
.macro tl1_immu_miss
|
||||
@ -1759,7 +1863,7 @@ tl0_intr_level:
|
||||
tl0_intr_level ! 0x41-0x4f
|
||||
tl0_reserved 16 ! 0x50-0x5f
|
||||
tl0_intr_vector:
|
||||
tl0_intr_vector ! 0x60
|
||||
intr_vector ! 0x60
|
||||
tl0_watch_phys:
|
||||
tl0_gen T_PA_WATCHPOINT ! 0x61
|
||||
tl0_watch_virt:
|
||||
@ -1859,7 +1963,7 @@ tl1_intr_level:
|
||||
tl1_intr_level ! 0x241-0x24f
|
||||
tl1_reserved 16 ! 0x250-0x25f
|
||||
tl1_intr_vector:
|
||||
tl1_intr_vector ! 0x260
|
||||
intr_vector ! 0x260
|
||||
tl1_watch_phys:
|
||||
tl1_gen T_PA_WATCHPOINT ! 0x261
|
||||
tl1_watch_virt:
|
||||
@ -2432,8 +2536,7 @@ ENTRY(tl1_trap)
|
||||
, %g1, %g2, %g3, 7, 8, 9)
|
||||
ldx [PCPU(CURTHREAD)], %g2
|
||||
stx %g2, [%g1 + KTR_PARM1]
|
||||
andn %o0, T_KERNEL, %g2
|
||||
stx %g2, [%g1 + KTR_PARM2]
|
||||
stx %o0, [%g1 + KTR_PARM2]
|
||||
stx %l3, [%g1 + KTR_PARM3]
|
||||
stx %l1, [%g1 + KTR_PARM4]
|
||||
stx %i6, [%g1 + KTR_PARM5]
|
||||
|
@ -177,7 +177,9 @@ ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread));
|
||||
ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb));
|
||||
ASSYM(PC_CPUID, offsetof(struct pcpu, pc_cpuid));
|
||||
ASSYM(PC_CPUMASK, offsetof(struct pcpu, pc_cpumask));
|
||||
ASSYM(PC_IQ, offsetof(struct pcpu, pc_iq));
|
||||
ASSYM(PC_IRHEAD, offsetof(struct pcpu, pc_irhead));
|
||||
ASSYM(PC_IRTAIL, offsetof(struct pcpu, pc_irtail));
|
||||
ASSYM(PC_IRFREE, offsetof(struct pcpu, pc_irfree));
|
||||
ASSYM(PC_MID, offsetof(struct pcpu, pc_mid));
|
||||
ASSYM(PC_TLB_CTX, offsetof(struct pcpu, pc_tlb_ctx));
|
||||
ASSYM(PC_TLB_CTX_MAX, offsetof(struct pcpu, pc_tlb_ctx_max));
|
||||
@ -187,16 +189,13 @@ ASSYM(PC_SIZEOF, sizeof(struct pcpu));
|
||||
|
||||
ASSYM(IH_SHIFT, IH_SHIFT);
|
||||
|
||||
ASSYM(IQ_MASK, IQ_MASK);
|
||||
ASSYM(IQ_HEAD, offsetof(struct intr_queue, iq_head));
|
||||
ASSYM(IQ_TAIL, offsetof(struct intr_queue, iq_tail));
|
||||
ASSYM(IRSR_BUSY, IRSR_BUSY);
|
||||
|
||||
ASSYM(IQE_SHIFT, IQE_SHIFT);
|
||||
ASSYM(IQE_TAG, offsetof(struct iqe, iqe_tag));
|
||||
ASSYM(IQE_PRI, offsetof(struct iqe, iqe_pri));
|
||||
ASSYM(IQE_VEC, offsetof(struct iqe, iqe_vec));
|
||||
ASSYM(IQE_FUNC, offsetof(struct iqe, iqe_func));
|
||||
ASSYM(IQE_ARG, offsetof(struct iqe, iqe_arg));
|
||||
ASSYM(IR_NEXT, offsetof(struct intr_request, ir_next));
|
||||
ASSYM(IR_FUNC, offsetof(struct intr_request, ir_func));
|
||||
ASSYM(IR_ARG, offsetof(struct intr_request, ir_arg));
|
||||
ASSYM(IR_PRI, offsetof(struct intr_request, ir_pri));
|
||||
ASSYM(IR_VEC, offsetof(struct intr_request, ir_vec));
|
||||
|
||||
ASSYM(ITA_MASK, offsetof(struct ipi_tlb_args, ita_mask));
|
||||
ASSYM(ITA_TLB, offsetof(struct ipi_tlb_args, ita_tlb));
|
||||
@ -210,7 +209,7 @@ ASSYM(IV_FUNC, offsetof(struct intr_vector, iv_func));
|
||||
ASSYM(IV_ARG, offsetof(struct intr_vector, iv_arg));
|
||||
ASSYM(IV_PRI, offsetof(struct intr_vector, iv_pri));
|
||||
|
||||
ASSYM(NIV, NIV);
|
||||
ASSYM(IV_MAX, IV_MAX);
|
||||
|
||||
ASSYM(KEF_ASTPENDING, KEF_ASTPENDING);
|
||||
ASSYM(KEF_NEEDRESCHED, KEF_NEEDRESCHED);
|
||||
|
@ -80,12 +80,11 @@
|
||||
#define MAX_STRAY_LOG 5
|
||||
|
||||
CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
|
||||
CTASSERT((1 << IQE_SHIFT) == sizeof(struct iqe));
|
||||
|
||||
ih_func_t *intr_handlers[NPIL];
|
||||
struct intr_vector intr_vectors[NIV];
|
||||
ih_func_t *intr_handlers[PIL_MAX];
|
||||
struct intr_vector intr_vectors[IV_MAX];
|
||||
|
||||
u_long intr_stray_count[NIV];
|
||||
u_long intr_stray_count[IV_MAX];
|
||||
|
||||
/* protect the intr_vectors table */
|
||||
static struct mtx intr_table_lock;
|
||||
@ -93,32 +92,6 @@ static struct mtx intr_table_lock;
|
||||
static void intr_stray_level(struct trapframe *tf);
|
||||
static void intr_stray_vector(void *cookie);
|
||||
|
||||
void
|
||||
intr_dequeue(struct trapframe *tf)
|
||||
{
|
||||
struct intr_queue *iq;
|
||||
struct iqe *iqe;
|
||||
u_long head;
|
||||
u_long next;
|
||||
u_long tail;
|
||||
|
||||
iq = PCPU_PTR(iq);
|
||||
for (head = iq->iq_head;; head = next) {
|
||||
for (tail = iq->iq_tail; tail != head;) {
|
||||
iqe = &iq->iq_queue[tail];
|
||||
atomic_add_long(&intrcnt[iqe->iqe_vec], 1);
|
||||
KASSERT(iqe->iqe_func != NULL,
|
||||
("intr_dequeue: iqe->iqe_func NULL"));
|
||||
iqe->iqe_func(iqe->iqe_arg);
|
||||
tail = (tail + 1) & IQ_MASK;
|
||||
}
|
||||
iq->iq_tail = tail;
|
||||
next = iq->iq_head;
|
||||
if (head == next)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
|
||||
{
|
||||
@ -162,9 +135,9 @@ intr_init1()
|
||||
int i;
|
||||
|
||||
/* Mark all interrupts as being stray. */
|
||||
for (i = 0; i < NPIL; i++)
|
||||
for (i = 0; i < PIL_MAX; i++)
|
||||
intr_handlers[i] = intr_stray_level;
|
||||
for (i = 0; i < NIV; i++) {
|
||||
for (i = 0; i < IV_MAX; i++) {
|
||||
intr_vectors[i].iv_func = intr_stray_vector;
|
||||
intr_vectors[i].iv_arg = &intr_vectors[i];
|
||||
intr_vectors[i].iv_pri = PIL_LOW;
|
||||
|
@ -183,6 +183,15 @@ cpu_startup(void *arg)
|
||||
void
|
||||
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
|
||||
{
|
||||
struct intr_request *ir;
|
||||
int i;
|
||||
|
||||
pcpu->pc_irtail = &pcpu->pc_irhead;
|
||||
for (i = 0; i < IR_FREE; i++) {
|
||||
ir = &pcpu->pc_irpool[i];
|
||||
ir->ir_next = pcpu->pc_irfree;
|
||||
pcpu->pc_irfree = ir;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -217,7 +217,7 @@ nexus_probe(device_t dev)
|
||||
sc->sc_mem_rman.rm_descr = "UPA Device Memory";
|
||||
if (rman_init(&sc->sc_intr_rman) != 0 ||
|
||||
rman_init(&sc->sc_mem_rman) != 0 ||
|
||||
rman_manage_region(&sc->sc_intr_rman, 0, NIV - 1) != 0 ||
|
||||
rman_manage_region(&sc->sc_intr_rman, 0, IV_MAX - 1) != 0 ||
|
||||
rman_manage_region(&sc->sc_mem_rman, UPA_MEMSTART, UPA_MEMEND) != 0)
|
||||
panic("nexus_probe: failed to set up rmans");
|
||||
for (child = OF_child(root); child != 0; child = OF_peer(child)) {
|
||||
|
Loading…
Reference in New Issue
Block a user