xref: /onnv-gate/usr/src/uts/sun4u/starfire/ml/idn_asm.s (revision 2973:55b674bffad9)
10Sstevel@tonic-gate/*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*2973Sgovinda * Common Development and Distribution License (the "License").
6*2973Sgovinda * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate/*
22*2973Sgovinda * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate/*
290Sstevel@tonic-gate * This file contains the low-level DMV interrupt
300Sstevel@tonic-gate * handler for IDN cross-domain interrupts.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate#if defined(lint)
340Sstevel@tonic-gate#include <sys/types.h>
350Sstevel@tonic-gate#endif /* lint */
360Sstevel@tonic-gate
370Sstevel@tonic-gate#include <sys/asm_linkage.h>
380Sstevel@tonic-gate#include <sys/machasi.h>
390Sstevel@tonic-gate#include <sys/privregs.h>
400Sstevel@tonic-gate#include <sys/intreg.h>
410Sstevel@tonic-gate#include <sys/machthread.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate#include <sys/idn.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate#if !defined(lint)
460Sstevel@tonic-gate#include "idn_offsets.h"
470Sstevel@tonic-gate#endif /* !lint */
480Sstevel@tonic-gate
490Sstevel@tonic-gate#define	IDN_MONDO
500Sstevel@tonic-gate
510Sstevel@tonic-gate/*
520Sstevel@tonic-gate * The IDN_DMV_CPU_SHIFT is based on the sizeof (idn_dmv_cpu_t)
530Sstevel@tonic-gate * which must be a power of 2 to optimize calculating our
540Sstevel@tonic-gate * entry into idn_dmv_cpu[].
550Sstevel@tonic-gate */
560Sstevel@tonic-gate#define	IDN_DMV_CPU_SHIFT	4
570Sstevel@tonic-gate
580Sstevel@tonic-gate/*
590Sstevel@tonic-gate *--------------------------------------------------------
600Sstevel@tonic-gate */
610Sstevel@tonic-gate#if defined(lint)
620Sstevel@tonic-gate
630Sstevel@tonic-gate/*
640Sstevel@tonic-gate * Would be nice to use init_mondo, but unforunately
650Sstevel@tonic-gate * it assumes the first arg is 32-bits.
660Sstevel@tonic-gate */
670Sstevel@tonic-gate/*ARGSUSED*/
680Sstevel@tonic-gatevoid
690Sstevel@tonic-gateidnxf_init_mondo(uint64_t arg0, uint64_t arg1, uint64_t arg2)
700Sstevel@tonic-gate{}
710Sstevel@tonic-gate
720Sstevel@tonic-gate#else /* lint */
730Sstevel@tonic-gate
740Sstevel@tonic-gate	.global _idn_dispatch_status_busy
750Sstevel@tonic-gate_idn_dispatch_status_busy:
760Sstevel@tonic-gate	.asciz	"ASI_INTR_DISPATCH_STATUS error: busy"
770Sstevel@tonic-gate	.align	4
780Sstevel@tonic-gate
790Sstevel@tonic-gate	ENTRY_NP(idnxf_init_mondo)
800Sstevel@tonic-gate#ifdef DEBUG
810Sstevel@tonic-gate	!
820Sstevel@tonic-gate	! IDSR should not be busy at the moment - borrowed from init_mondo
830Sstevel@tonic-gate	!
840Sstevel@tonic-gate	ldxa	[%g0]ASI_INTR_DISPATCH_STATUS, %g1
850Sstevel@tonic-gate	btst	IDSR_BUSY, %g1
860Sstevel@tonic-gate	bz,pt	%xcc, 1f
870Sstevel@tonic-gate	mov	ASI_INTR_DISPATCH, %asi
880Sstevel@tonic-gate	sethi	%hi(_idn_dispatch_status_busy), %o0
890Sstevel@tonic-gate	call	panic
900Sstevel@tonic-gate	or	%o0, %lo(_idn_dispatch_status_busy), %o0
910Sstevel@tonic-gate#endif /* DEBUG */
920Sstevel@tonic-gate
930Sstevel@tonic-gate	mov	ASI_INTR_DISPATCH, %asi
940Sstevel@tonic-gate1:
950Sstevel@tonic-gate	stxa	%o0, [IDDR_0]%asi	! dmv_word0
960Sstevel@tonic-gate	stxa	%o1, [IDDR_1]%asi	! dmv_word1
970Sstevel@tonic-gate	stxa	%o2, [IDDR_2]%asi	! dmv_word2
980Sstevel@tonic-gate
990Sstevel@tonic-gate	retl
1000Sstevel@tonic-gate	membar	#Sync
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate	SET_SIZE(idnxf_init_mondo)
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate#endif /* lint */
1050Sstevel@tonic-gate/*
1060Sstevel@tonic-gate *--------------------------------------------------------
1070Sstevel@tonic-gate */
1080Sstevel@tonic-gate#if defined(lint)
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate/*
1110Sstevel@tonic-gate * Unfortunately, send_mondo is rather picky about getting
1120Sstevel@tonic-gate * a result from the cpu it sends an interrupt to.  If it
1130Sstevel@tonic-gate * doesn't get a result within a specific timeframe it
1140Sstevel@tonic-gate * will panic!  For IDN that's not cool since a cpu hungup
1150Sstevel@tonic-gate * in one could ultimately result in the demise of a cpu
1160Sstevel@tonic-gate * in another domain.  Instead of getting our panties in
1170Sstevel@tonic-gate * a bind, we simply bail out.
1180Sstevel@tonic-gate */
1190Sstevel@tonic-gate/*ARGSUSED*/
1200Sstevel@tonic-gateint
1210Sstevel@tonic-gateidnxf_send_mondo(int upaid)
1220Sstevel@tonic-gate{ return (0); }
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate#else /* lint */
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate	.seg	".data"
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate	.global _idn_send_mondo_failure
1290Sstevel@tonic-gate_idn_send_mondo_failure:
1300Sstevel@tonic-gate	.word	0
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate	.seg	".text"
1330Sstevel@tonic-gate	ENTRY(idnxf_send_mondo)
1340Sstevel@tonic-gate	!
1350Sstevel@tonic-gate	! NOTE:
1360Sstevel@tonic-gate	!	This is stolen from send_mondo.  The changes
1370Sstevel@tonic-gate	!	are those ifdef'd with IDN_MONDO
1380Sstevel@tonic-gate	!
1390Sstevel@tonic-gate	! construct the interrupt dispatch command register in %g1
1400Sstevel@tonic-gate	! also, get the dispatch out as SOON as possible
1410Sstevel@tonic-gate	! (initial analysis puts the minimum dispatch time at around
1420Sstevel@tonic-gate	!  30-60 cycles.  hence, we try to get the dispatch out quickly
1430Sstevel@tonic-gate	!  and then start the rapid check loop).
1440Sstevel@tonic-gate	!
1450Sstevel@tonic-gate	rd	%tick, %o4			! baseline tick
1460Sstevel@tonic-gate	sll	%o0, IDCR_PID_SHIFT, %g1	! IDCR<18:14> = upa port id
1470Sstevel@tonic-gate	or	%g1, IDCR_OFFSET, %g1		! IDCR<13:0> = 0x70
1480Sstevel@tonic-gate	stxa	%g0, [%g1]ASI_INTR_DISPATCH	! interrupt vector dispatch
1490Sstevel@tonic-gate#if defined(SF_ERRATA_54)
1500Sstevel@tonic-gate	membar	#Sync				! store must occur before load
1510Sstevel@tonic-gate	mov	0x20, %g3			! UDBH Control Register Read
1520Sstevel@tonic-gate	ldxa	[%g3]ASI_SDB_INTR_R, %g0
1530Sstevel@tonic-gate#endif
1540Sstevel@tonic-gate	membar	#Sync
1550Sstevel@tonic-gate	clr	%o2				! clear NACK counter
1560Sstevel@tonic-gate	clr	%o3				! clear BUSY counter
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate	!
1590Sstevel@tonic-gate	! how long, in ticks, are we willing to wait completely
1600Sstevel@tonic-gate	!
1610Sstevel@tonic-gate	sethi	%hi(xc_tick_limit), %g2
1620Sstevel@tonic-gate	ldx	[%g2 + %lo(xc_tick_limit)], %g2
1630Sstevel@tonic-gate	add	%g2, %o4, %o5			! compute the limit value
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate	!
1660Sstevel@tonic-gate	! check the dispatch status
1670Sstevel@tonic-gate	!
1680Sstevel@tonic-gate.check_dispatch:
1690Sstevel@tonic-gate	ldxa	[%g0]ASI_INTR_DISPATCH_STATUS, %o1
1700Sstevel@tonic-gate	brz,pn	%o1, .dispatch_complete
1710Sstevel@tonic-gate	  rd	%tick, %g5
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate	!
1740Sstevel@tonic-gate	! see if we've gone beyond the limit
1750Sstevel@tonic-gate	! (can tick ever overflow?)
1760Sstevel@tonic-gate	!
1770Sstevel@tonic-gate.timeout_primed:
1780Sstevel@tonic-gate	sub	%o5, %g5, %g2			! limit - tick < 0 if timeout
1790Sstevel@tonic-gate	brgez,pt %g2, .check_busy
1800Sstevel@tonic-gate	  inc	%o3				! bump the BUSY counter
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate#ifdef IDN_MONDO
1830Sstevel@tonic-gate	!
1840Sstevel@tonic-gate	! Within the context of IDN we don't want
1850Sstevel@tonic-gate	! to panic just because we can't send_mondo.
1860Sstevel@tonic-gate	! Clear the dispatch register and increment
1870Sstevel@tonic-gate	! our count of failures.
1880Sstevel@tonic-gate	!
1890Sstevel@tonic-gate	stxa	%g0, [%g1]ASI_INTR_DISPATCH
1900Sstevel@tonic-gate	sethi	%hi(_idn_send_mondo_failure), %o0
1910Sstevel@tonic-gate	ld	[%o0 + %lo(_idn_send_mondo_failure)], %o1
1920Sstevel@tonic-gate	inc	%o1
1930Sstevel@tonic-gate	st	%o1, [%o0 + %lo(_idn_send_mondo_failure)]
1940Sstevel@tonic-gate	retl
1950Sstevel@tonic-gate	  mov	-1, %o0				! return (-1)
1960Sstevel@tonic-gate#else /* IDN_MONDO */
1970Sstevel@tonic-gate	!
1980Sstevel@tonic-gate	! time to die, see if we are already panicing
1990Sstevel@tonic-gate	!
2000Sstevel@tonic-gate	mov	%o0, %o1			! save target
2010Sstevel@tonic-gate	sethi	%hi(_send_mondo_nack), %o0
2020Sstevel@tonic-gate	or	%o0, %lo(_send_mondo_nack), %o0
2030Sstevel@tonic-gate	sethi	%hi(panicstr), %g2
2040Sstevel@tonic-gate	ldn	[%g2 + %lo(panicstr)], %g2
2050Sstevel@tonic-gate	brnz	%g2, .dispatch_complete		! skip if already in panic
2060Sstevel@tonic-gate	  nop
2070Sstevel@tonic-gate	call	panic
2080Sstevel@tonic-gate	  nop
2090Sstevel@tonic-gate#endif /* IDN_MONDO */
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate.check_busy:
2120Sstevel@tonic-gate	btst	IDSR_BUSY, %o1			! was it BUSY?
2130Sstevel@tonic-gate	bnz,pt	%xcc, .check_dispatch
2140Sstevel@tonic-gate	  nop
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate	!
2170Sstevel@tonic-gate	! we weren't busy, we must have been NACK'd
2180Sstevel@tonic-gate	! wait a while and send again
2190Sstevel@tonic-gate	! (this might need jitter)
2200Sstevel@tonic-gate	!
2210Sstevel@tonic-gate	sethi	%hi(sys_clock_mhz), %g2
2220Sstevel@tonic-gate	lduw	[%g2 + %lo(sys_clock_mhz)], %g2
2230Sstevel@tonic-gate	rd	%tick, %g4
2240Sstevel@tonic-gate	add	%g2, %g4, %g2
2250Sstevel@tonic-gate.delay:
2260Sstevel@tonic-gate	cmp	%g2, %g4
2270Sstevel@tonic-gate	bgu,pt	%xcc, .delay
2280Sstevel@tonic-gate	rd	%tick, %g4
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate	stxa	%g0, [%g1]ASI_INTR_DISPATCH	! interrupt vector dispatch
2310Sstevel@tonic-gate#if defined(SF_ERRATA_54)
2320Sstevel@tonic-gate	membar	#Sync				! store must occur before load
2330Sstevel@tonic-gate	ldxa	[%g3]ASI_SDB_INTR_R, %g0
2340Sstevel@tonic-gate#endif
2350Sstevel@tonic-gate	membar	#Sync
2360Sstevel@tonic-gate	clr	%o3				! reset BUSY counter
2370Sstevel@tonic-gate	ba	.check_dispatch
2380Sstevel@tonic-gate	  inc	%o2				! bump the NACK counter
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate.dispatch_complete:
2410Sstevel@tonic-gate#ifndef IDN_MONDO
2420Sstevel@tonic-gate#ifdef SEND_MONDO_STATS
2430Sstevel@tonic-gate	!
2440Sstevel@tonic-gate	! Increment the appropriate entry in a send_mondo timeout array
2450Sstevel@tonic-gate	! x_entry[CPU][MSB]++;
2460Sstevel@tonic-gate	sub	%g5, %o4, %g5			! how long did we wait?
2470Sstevel@tonic-gate	clr	%o1				! o1 is now bit counter
2480Sstevel@tonic-gate1:	orcc	%g5, %g0, %g0			! any bits left?
2490Sstevel@tonic-gate	srlx	%g5, 1, %g5			! bits to the right
2500Sstevel@tonic-gate	bne,a,pt %xcc, 1b
2510Sstevel@tonic-gate	  add	%o1, 4, %o1			! pointer increment
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate	!
2540Sstevel@tonic-gate	! now compute the base of the x_early entry for our cpu
2550Sstevel@tonic-gate	!
2560Sstevel@tonic-gate	CPU_INDEX(%o0, %g5)
2570Sstevel@tonic-gate	sll	%o0, 8, %o0			! 64 * 4
2580Sstevel@tonic-gate	add	%o0, %o1, %o1			! %o0 = &[CPU][delay]
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate	!
2610Sstevel@tonic-gate	! and increment the appropriate value
2620Sstevel@tonic-gate	!
2630Sstevel@tonic-gate	sethi	%hi(x_early), %o0
2640Sstevel@tonic-gate	or	%o0, %lo(x_early), %o0
2650Sstevel@tonic-gate	ld	[%o0 + %o1], %g5
2660Sstevel@tonic-gate	inc	%g5
2670Sstevel@tonic-gate	st	%g5, [%o0 + %o1]
2680Sstevel@tonic-gate#endif	/* SEND_MONDO_STATS */
2690Sstevel@tonic-gate#endif /* !IDN_MONDO */
2700Sstevel@tonic-gate	retl
2710Sstevel@tonic-gate#ifdef IDN_MONDO
2720Sstevel@tonic-gate	  mov	%g0, %o0			! return (0)
2730Sstevel@tonic-gate#else /* IDN_MONDO */
2740Sstevel@tonic-gate	  nop
2750Sstevel@tonic-gate#endif /* IDN_MONDO */
2760Sstevel@tonic-gate	SET_SIZE(idnxf_send_mondo)
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate#endif /* lint */
2790Sstevel@tonic-gate/*
2800Sstevel@tonic-gate *--------------------------------------------------------
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate#if defined(lint)
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate/*ARGSUSED*/
2850Sstevel@tonic-gatevoid
2860Sstevel@tonic-gateidn_dmv_handler(void *arg)
2870Sstevel@tonic-gate{}
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate#else /* lint */
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate	ENTRY_NP(idn_dmv_handler)
2920Sstevel@tonic-gate	!
2930Sstevel@tonic-gate	! On entry:
2940Sstevel@tonic-gate	!	g1 = idn_dmv_data
2950Sstevel@tonic-gate	!	g2 = word 0
2960Sstevel@tonic-gate	!
2970Sstevel@tonic-gate	ldx	[%g1 + IDN_DMV_QBASE], %g4	! g4 = idn_dmv_qbase
2980Sstevel@tonic-gate	add	%g1, IDN_DMV_CPU, %g3		! g3 = &idn_dmv_cpu[0]
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate	CPU_INDEX(%g6, %g5)		! g6 = cpuid
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate	!
3030Sstevel@tonic-gate	! g5 = cur = idn_dmv_cpu[cpuid]
3040Sstevel@tonic-gate	!
3050Sstevel@tonic-gate	sll	%g6, IDN_DMV_CPU_SHIFT, %g6	! g6 = cpuid * 8
3060Sstevel@tonic-gate	add	%g3, IDN_DMV_CURRENT, %g3
3070Sstevel@tonic-gate	ld	[%g6 + %g3], %g5
3080Sstevel@tonic-gate	!
3090Sstevel@tonic-gate	! g5 = idn_dmv_cpu[cpuid].idn_dmv_current
3100Sstevel@tonic-gate	!      offset from idn_dmv_qbase
3110Sstevel@tonic-gate	!
3120Sstevel@tonic-gate	or	%g5, %g0, %g5		! get to 64-bits
3130Sstevel@tonic-gate	add	%g5, %g4, %g5		! g5 = idn_dmv_current
3140Sstevel@tonic-gate					!      actual address
3150Sstevel@tonic-gate	ldstub	[%g5 + IV_INUSE], %g7	! cur->iv_inuse = 0xff
3160Sstevel@tonic-gate	brz,pt	%g7, 1f			! did we get it?
3170Sstevel@tonic-gate	sub	%g3, IDN_DMV_CURRENT, %g4
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate	!
3200Sstevel@tonic-gate	! Queue is FULL.  Drop interrupt.
3210Sstevel@tonic-gate	!
3220Sstevel@tonic-gate	add	%g4, IDN_DMV_LOSTINTR, %g3
3230Sstevel@tonic-gate	ld	[%g6 + %g3], %g2
3240Sstevel@tonic-gate	!
3250Sstevel@tonic-gate	! g2 = idn_dmv_cpu[cpuid].idn_iv_lostintr++
3260Sstevel@tonic-gate	!
3270Sstevel@tonic-gate	inc	%g2
3280Sstevel@tonic-gate	set	dmv_finish_intr, %g4
3290Sstevel@tonic-gate	st	%g2, [%g3 + %g6]
3300Sstevel@tonic-gate	jmp	%g4
3310Sstevel@tonic-gate	mov	-1, %g1
3320Sstevel@tonic-gate	!
3330Sstevel@tonic-gate	! not reached
3340Sstevel@tonic-gate	!
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate1:
3370Sstevel@tonic-gate	add	%g4, IDN_DMV_ACTIVE, %g7
3380Sstevel@tonic-gate	!
3390Sstevel@tonic-gate	! Move current pointer to next one.
3400Sstevel@tonic-gate	! idn_dmv_current[cpuid] = cur->iv_next
3410Sstevel@tonic-gate	!
3420Sstevel@tonic-gate	ld	[%g5 + IV_NEXT], %g4
3430Sstevel@tonic-gate	st	%g4, [%g3 + %g6]
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate	!
3460Sstevel@tonic-gate	! Start filling in structure with data.
3470Sstevel@tonic-gate	!
3480Sstevel@tonic-gate	stx	%g2, [%g5 + IV_HEAD]
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate	mov	IRDR_1, %g2
3510Sstevel@tonic-gate	mov	IRDR_2, %g4
3520Sstevel@tonic-gate	ldxa	[%g2]ASI_INTR_RECEIVE, %g2	! g2 = xargs[0,1]
3530Sstevel@tonic-gate	ldxa	[%g4]ASI_INTR_RECEIVE, %g4	! g4 = xargs[2,3]
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate	stx	%g2, [%g5 + IV_XARGS0]
3560Sstevel@tonic-gate	stx	%g4, [%g5 + IV_XARGS2]
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate	membar	#StoreLoad|#StoreStore
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate	clrb	[%g5 + IV_READY]	! cur->iv_ready = 0 (unlocked)
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate	!
3630Sstevel@tonic-gate	! See if we're already active, i.e. have things
3640Sstevel@tonic-gate	! queued.  If so, don't bother generating a soft
3650Sstevel@tonic-gate	! interrupt.  IDN interrupts could exhaust the
366*2973Sgovinda	! intr_vec structs for the given cpu and that code
367*2973Sgovinda	! doesn't know how to survive with intr_vec structs!
3680Sstevel@tonic-gate	!
3690Sstevel@tonic-gate	ldstub	[%g6 + %g7], %g7	! idn_dmv_active = 0xff
3700Sstevel@tonic-gate	brz,a,pt %g7, 2f
371*2973Sgovinda	ldx	[%g1 + IDN_SOFT_INUM], %g7	! g7 = idn_soft_inum
3720Sstevel@tonic-gate	mov	-1, %g7
3730Sstevel@tonic-gate2:
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate	!
3760Sstevel@tonic-gate	! Setup to cause an IDN soft interrupt to occur,
3770Sstevel@tonic-gate	! (if necessary).
3780Sstevel@tonic-gate	!
3790Sstevel@tonic-gate	set	dmv_finish_intr, %g3
3800Sstevel@tonic-gate	jmp	%g3
3810Sstevel@tonic-gate	mov	%g7, %g1
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate	SET_SIZE(idn_dmv_handler)
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate#endif /* lint */
386