PERFORCE change 93959 for review
Kip Macy
kmacy at FreeBSD.org
Sat Mar 25 04:20:14 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=93959
Change 93959 by kmacy at kmacy_storage:sun4vtmp on 2006/03/25 04:19:49
pull in initial {dev,cpu}_mondo implementation
Affected files ...
.. //depot/projects/kmacy_sun4v/src/sys/sparc64/sparc64/genassym.c#15 edit
.. //depot/projects/kmacy_sun4v/src/sys/sun4v/sun4v/exception.S#39 edit
.. //depot/projects/kmacy_sun4v/src/sys/sun4v/sun4v/interrupt.S#4 edit
Differences ...
==== //depot/projects/kmacy_sun4v/src/sys/sparc64/sparc64/genassym.c#15 (text+ko) ====
@@ -205,9 +205,9 @@
ASSYM(PC_SIZEOF, sizeof(struct pcpu));
#ifdef SUN4V
-ASSYM(PC_CPU_Q_BASE, offsetof(struct pcpu, pc_cpu_q_ra));
+ASSYM(PC_CPU_Q_RA, offsetof(struct pcpu, pc_cpu_q_ra));
ASSYM(PC_CPU_Q_SIZE, offsetof(struct pcpu, pc_cpu_q_size));
-ASSYM(PC_DEV_Q_BASE, offsetof(struct pcpu, pc_dev_q_ra));
+ASSYM(PC_DEV_Q_RA, offsetof(struct pcpu, pc_dev_q_ra));
ASSYM(PC_DEV_Q_SIZE, offsetof(struct pcpu, pc_dev_q_size));
ASSYM(PC_RQ_BASE, offsetof(struct pcpu, pc_rq_ra));
@@ -222,6 +222,7 @@
ASSYM(PC_CURPCB_RA, offsetof(struct pcpu, pc_curpcb_ra));
ASSYM(PCB_RA, offsetof(struct pcb, pcb_ra));
+ASSYM(INTR_REPORT_SIZE, INTR_REPORT_SIZE);
#else
ASSYM(PC_TLB_CTX, offsetof(struct pcpu, pc_tlb_ctx));
ASSYM(PC_TLB_CTX_MAX, offsetof(struct pcpu, pc_tlb_ctx_max));
==== //depot/projects/kmacy_sun4v/src/sys/sun4v/sun4v/exception.S#39 (text+ko) ====
@@ -324,14 +324,11 @@
.endm
.macro cpu_mondo
- MAGIC_TRAP_ON
ba,a,pt %xcc, cpu_mondo
.align 32
.endm
.macro dev_mondo
- MAGIC_TRAP_ON
- MAGIC_EXIT
ba,a,pt %xcc, dev_mondo
.align 32
.endm
==== //depot/projects/kmacy_sun4v/src/sys/sun4v/sun4v/interrupt.S#4 (text+ko) ====
@@ -27,6 +27,8 @@
#include <machine/asm.h>
__FBSDID("$FreeBSD: src/sys/sparc64/sparc64/interrupt.S,v 1.8 2005/04/16 15:05:56 marius Exp $");
+#include "opt_simulator.h"
+#include <machine/hypervisorvar.h>
#include <machine/asi.h>
#include <machine/asmacros.h>
#include <machine/ktr.h>
@@ -79,3 +81,267 @@
ba,a %xcc, 1b
nop
END(intr_fast)
+
+/*
+ * Running tally of invalid CPU mondo interrupts
+ */
+#if defined(lint)
+uint64_t cpu_mondo_invalid;
+#else /* lint */
+ .data
+ .globl cpu_mondo_invalid
+ .align 8
+cpu_mondo_invalid:
+ .skip 8
+
+ .text
+#endif /* lint */
+
+#if defined(lint)
+void
+cpu_mondo(void)
+{}
+#else /* lint */
+
+/*
+ * (TT 0x7c, TL>0) CPU Mondo Queue Handler
+ * Globals are the Interrupt Globals.
+ *
+ * Interrupts in sun4v are delivered to privileged code in the form
+ * of interrupt reports. Each interrupt report is 64-bytes long,
+ * consisting of 8 64-bit words. Each interrupt report is appended
+ * onto the appropriate interrupt queue of which there are currently two,
+ * one for CPU mondos (formerly referred to as cross trap function
+ * requests) and one for device mondos. Each queue has its own
+ * trap vector.
+ *
+ * New reports are appended onto the tail of the queue, and privileged
+ * code reads the report from the queue's head. The head pointer is stored
+ * in a register and is equal to the current offset from the base address
+ * of its associated queue.
+ *
+ * The structure of the cpu mondo report follows sun4u conventions:
+ *
+ * word 0: address of cross-trap handler
+ * word 1: first argument to handler
+ * word 2: second argument to handler
+ * word 3-7: unused
+ *
+ * Privileged code is responsible for incrementing the head pointer
+ * to remove each entry. The pointers are updated using modulo
+ * arithmetic such that the queue is empty when head == tail and is full
+ * when the addition of an entry would make head == tail.
+ *
+ * This trap handler is called when the cpu mondo queue becomes non-empty
+ * and will continue to be called while interrupts enabled until the
+ * queue becomes empty.
+ *
+ */
+ENTRY(cpu_mondo)
+ MAGIC_TRAP_ON
+ !
+ ! Register Usage:-
+ ! %g5 PC for fasttrap TL>0 handler
+ ! %g1 arg 1
+ ! %g2 arg 2
+ ! %g3 queue base VA
+ ! %g4 queue size mask
+ ! %g6 head ptr
+ mov CPU_MONDO_QUEUE_HEAD, %g1
+ ldxa [%g1]ASI_QUEUE, %g6 ! %g6 = head ptr
+ mov CPU_MONDO_QUEUE_TAIL, %g2
+ ldxa [%g2]ASI_QUEUE, %g4 ! %g4 = tail ptr
+ cmp %g6, %g4
+ be,pn %xcc, 0f ! head == tail
+ nop
+
+ /*
+ * Get the address of the current CPU and index into
+ * the pcpu structure for the Q values.
+ */
+ GET_PCPU_SCRATCH
+ ldx [PCPU(CPU_Q_RA)], %g3 ! %g3 = queue base PA
+ ldx [PCPU(CPU_Q_SIZE)], %g4 ! %g4 = queue size
+ sub %g4, 1, %g4 ! %g4 = queue size mask
+
+ ! Load interrupt receive data registers 1 and 2 to fetch
+ ! the arguments for the fast trap handler.
+ !
+ ! Since the data words in the interrupt report are not defined yet
+ ! we assume that the consective words contain valid data and preserve
+ ! sun4u's xcall mondo arguments.
+ ! Register usage:
+ ! %g5 PC for fasttrap TL>0 handler
+ ! %g1 arg 1
+ ! %g2 arg 2
+
+ ldxa [%g3 + %g6]ASI_REAL, %g5 ! get PC from q base + head
+ add %g6, 0x8, %g6 ! inc head 8 bytes
+ ldxa [%g3 + %g6]ASI_REAL, %g1 ! read data word 1
+ add %g6, 0x8, %g6 ! inc head 8 bytes
+ ldxa [%g3 + %g6]ASI_REAL, %g2 ! read data word 2
+ add %g6, (INTR_REPORT_SIZE - 16) , %g6
+ ! inc head to next record
+
+ and %g6, %g4, %g6 ! and size mask for wrap around
+ mov CPU_MONDO_QUEUE_HEAD, %g3
+ stxa %g6, [%g3]ASI_QUEUE ! store head pointer
+ membar #Sync
+
+ /*
+ * For now catch invalid PC being passed via cpu_mondo queue
+ */
+ set KERNBASE, %g4
+ cmp %g5, %g4
+ bl,a,pn %xcc, 1f ! branch if bad %pc
+ nop
+
+ jmp %g5 ! jump to traphandler
+ nop
+1:
+ ! invalid trap handler, discard it for now
+ set cpu_mondo_invalid, %g4
+ ldx [%g4], %g5
+ inc %g5
+ stx %g5, [%g4]
+0:
+ retry
+ /* NOTREACHED */
+END(cpu_mondo)
+
+#endif /* lint */
+
+
+#if defined(lint)
+void
+dev_mondo(void)
+{}
+#else /* lint */
+
+/*
+ * (TT 0x7d, TL>0) Dev Mondo Queue Handler
+ * Globals are the Interrupt Globals.
+ *
+ * Device interrupt reports take the following form:
+ * Bits: 63 11 10 6 5 0
+ * word 0: | zero | | bus port | | device ID |
+ * word 1-7: unused
+ *
+ */
+ENTRY(dev_mondo)
+ /*
+ * Register Usage:-
+ * %g5 inum
+ * %g1 ptr to intrerrupt vector entry for inum
+ * %g3 queue base PA
+ * %g4 queue size mask
+ * %g6 head ptr
+ */
+ mov DEV_MONDO_QUEUE_HEAD, %g1
+ ldxa [%g1]ASI_QUEUE, %g6 ! %g6 = head ptr
+ mov DEV_MONDO_QUEUE_TAIL, %g2
+ ldxa [%g2]ASI_QUEUE, %g4 ! %g4 = tail ptr
+ cmp %g6, %g4
+ be,pn %xcc, 0f ! head == tail
+ nop
+
+ /*
+ * Get CPU address and index to Q base
+ */
+ GET_PCPU_SCRATCH
+ ldx [PCPU(DEV_Q_RA)], %g3 ! %g3 = queue base PA
+
+ /*
+ * Register usage:
+ * %g5 - inum
+ */
+ ldxa [%g3 + %g6]ASI_REAL, %g5 ! %g5 = inum from q base + head
+
+ /*
+ * We verify that inum is valid ( < IV_MAX). If it is greater
+ * than IV_MAX, we let the software interrupt handler take care
+ * of it.
+ */
+ set IV_MAX, %g4
+ cmp %g5, %g4
+ bgeu,a,pn %xcc, 1f
+ ldx [PCPU(DEV_Q_SIZE)], %g4 ! queue size (delay slot)
+
+ /*
+ * Find the function, argument and desired priority from the
+ * intr_vectors table
+ */
+ set intr_vectors, %g1
+ sll %g5, IV_SHIFT, %g2
+ add %g1, %g2, %g1 ! %g1 = &intr_vectors[inum]
+
+ /*
+ * Get an 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 dereference a NULL pointer and panic.
+ */
+ ldx [PCPU(IRFREE)], %g2 ! %g2 = ptr to tail element
+
+ /*
+ * Sun4v-fixme: It might be better to have the software interrupt
+ * handler deal with this scenario rather than just panic.
+ */
+ !brz,a,pt %g2, 1f
+ !ldx [PCPU(DEV_Q_SIZE)], %g4 ! queue size (delay slot)
+
+ ldx [%g2 + IR_NEXT], %g3 ! %g3 = next element in list
+ stx %g3, [PCPU(IRFREE)] ! %g3 is now the tail
+
+ /*
+ * Store the vector number, function, argument, and priority.
+ */
+ stw %g5, [%g2 + IR_VEC]
+ ldx [%g1 + IV_FUNC], %g3 ! %g3 = function ptr
+ stx %g3, [%g2 + IR_FUNC]
+ ldx [%g1 + IV_ARG], %g3 ! %g3 = argument ptr
+ stx %g3, [%g2 + IR_ARG]
+ lduw [%g1 + IV_PRI], %g1 ! %g1 = priority
+ stw %g1, [%g2 + IR_PRI]
+
+ /*
+ * Link it onto the end of the active list
+ */
+ stx %g0, [%g2 + IR_NEXT]
+ ldx [PCPU(IRTAIL)], %g3 ! %g3 = ptr to tail
+ stx %g2, [%g3]
+ add %g2, IR_NEXT, %g2
+ stx %g2, [PCPU(IRTAIL)]
+
+ /*
+ * Unlike Solaris, FreeBSD throws away the rest of the
+ * 64-byte packet. We may want to revisit this philosophy
+ * at some point since information in the packet is defined by
+ * the device and MAY be meaningful.
+ *
+ * For now, we retain FreeBSD's sun4u semantics.
+ */
+ ldx [PCPU(DEV_Q_SIZE)], %g4 ! queue size
+
+1: sub %g4, 1, %g4 ! %g4 = queue size mask
+ add %g6, INTR_REPORT_SIZE, %g6 ! inc head to next record
+ and %g6, %g4, %g6 ! and mask for wrap around
+ mov DEV_MONDO_QUEUE_HEAD, %g3
+ stxa %g6, [%g3]ASI_QUEUE ! increment head offset
+ membar #Sync
+
+ /*
+ * Trigger a softint at the level indicated by the priority
+ */
+ mov 1, %g6
+ sllx %g6, %g1, %g6
+ wr %g6, 0, %set_softint
+
+ /*
+ * Done, retry the instruction
+ */
+0: retry
+
+ /* NOTREACHED */
+END(dev_mondo)
+#endif /* lint */
+
More information about the p4-projects
mailing list