wrsm_trap.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* TL1 trap handler for DMV interrupts generated by WCIs
* Note: You must build sun4u/genassym before assembling this file.
*
* This handler places incoming interrupts onto the appropriate receive
* queue for waiting handlers based on the interrupt mondo. It also
* directly handles "small put interrupts"; it writes <64 chunks of data
* passed by the interrupt into the memory segment, again based on the
* interrupt mondo.
*/
#if !defined(lint)
#include <sys/asm_linkage.h>
#include <sys/asi.h>
#include <sys/machasi.h>
#include <sys/privregs.h>
#include <sys/machthread.h>
#include <sys/fsr.h>
#include <sys/machparam.h>
#include <sys/wrsm_config.h>
#include <sys/wrsm_intr.h>
#include <sys/wrsm_intr_impl.h>
#include <wrsm_offsets.h>
#endif /* lint */
/*
* The definitions of the interrupt recieve and send registers
* (IRDR_x and IDDR_x) are different for Cheetah than for spitfire
* so the values in intreg.h won't work.
*/
#define IRDR_0 0x40
#define IRDR_1 0x48
#define IRDR_2 0x50
#define IRDR_3 0x58
#define IRDR_4 0x60
#define IRDR_5 0x68
#define IRDR_6 0x80
#define IRDR_7 0x88
#define CMMU_MONDO_SHIFT 32
#define CMMU_MONDO_MASK 0xffff
#define RING_EMPTY 1
#define RING_FULL 2
#define PFN_INVALID -1
#if defined(lint)
/* ARGSUSED */
void
wrsm_tl_handler(unsigned long dmv_arg, unsigned long irdr_0)
{}
#endif /* lint */
#if !defined(lint)
.seg ".data"
.global wrsm_null_intr_count
.align 8
wrsm_null_intr_count:
.word 0, 0
#ifdef DEBUG
.global wrsm_dropped_intr
.align 8
wrsm_dropped_intr:
.word 0, 0
.global wrsm_trap_softint_count
.align 8
wrsm_trap_softint_count:
.word 0, 0
.global wrsm_trap_ring_info
.align 8
wrsm_trap_ring_info:
.word 0, 0
.global wrsm_trap_arg1
.align 8
wrsm_trap_arg1:
.word 0, 0xbadd
.global wrsm_trap_arg2
.align 8
wrsm_trap_arg2:
.word 0, 0xcafe
.global wrsm_trap_highwater
.align 8
wrsm_trap_highwater:
.word 0, 0
#endif /* DEBUG */
#ifdef WRSM_STORE_TRAP_DATA
.global wrsm_trap_data
.align 8
wrsm_trap_data:
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
#endif /* WRSM_STORE_TRAP_DATA */
!
! %g1 The argument passed to dmv_add_intr()
! %g2 Word 0 of the incoming mondo vector(IRDR_0)
! The argument in %g1 is the pointer to the base
! of the recvq_table
!
.seg ".text"
ENTRY(wrsm_tl1_handler)
#ifdef DEBUG
set wrsm_trap_arg1, %g3
stx %g1, [%g3]
set wrsm_trap_arg2, %g3
stx %g2, [%g3]
#endif
/*
* The 16-bit index into the recvq_table is in bits 47 through
* 32 of IRDR_0
*/
srlx %g2, CMMU_MONDO_SHIFT, %g3
set CMMU_MONDO_MASK, %g5
andcc %g3, %g5, %g3 ! %g3 now holds the 16-bit index
bne 0f
nop
! If the mondo is 0, bump a counter and resume without
! triggering a softint
set wrsm_null_intr_count, %g4
ldx [%g4], %g5
inc %g5
stx %g5, [%g4]
set dmv_finish_intr, %g5
jmp %g5
sub %g0, 1, %g1 ! no softint
0:
mov %g3, %g4
srlx %g3, WRSM_INTR_TABLE_SHIFT, %g3
and %g3, WRSM_INTR_TABLE_MASK, %g3
srlx %g4, WRSM_INTR_INDEX_SHIFT, %g4
and %g4, WRSM_INTR_INDEX_MASK, %g4
! %g3 has the table number and %g4 has the table index
sllx %g3, 3, %g3 ! g3 = g3 * sizeof(void *)
add %g3, %g1, %g3 ! g3 = &recvq_tables[table]
ldx [%g3], %g5 ! g5 = recvq_tables[table]
sllx %g4, 3, %g4 ! g4 = g4 * sizeof(void *)
add %g4, %g5, %g4
ldx [%g4], %g6
! %g6 has the pointer to the correct recvq struct
! We no longer need %g3, %g4, or %g5
/*
* If the recvq exportseg field is set, this must be a small put
* interrupt; parse and handle message here. Otherwise it is
* a standard packet to be put onto a recvq.
*/
ldx [%g6 + EXPORTSEG], %g3 ! get exportseg pointer
cmp %g0, %g3 ! is it NULL?
be,a,pn %xcc, 1f ! yes; handle normal packet
add %g6, PACKET_RING_INFO, %g3 ! execute on branch only
/*
* %g3 has exportseg pointer
*/
ldx [%g3 + PFN_LIST], %g4 ! get pfn_list pointer
cmp %g0, %g4 ! is it NULL?
be,a,pn %xcc, 5f ! yes; toss this packet
sub %g0, 1, %g1 ! dmv_finish_intr: no softint
/*
* no longer need %g1, %g3 or %g6
* still don't need need %g5
*
* %g4 has pfn_list pointer
*
* %g2 has word 0 of the incoming mondo vector (IRDR_0), which
* contains the first 8 bytes of small put message.
*
* Parse message and find the length to write, and offset into
* message putdata field holding first byte. Both of these values
* are in IRDR_0 (bytes 0-7).
*/
srlx %g2, 24, %g1 ! byte 4 holds # bytes to write
and %g1, 0xff, %g1 ! just want byte 4
srlx %g2, 16, %g2 ! byte 5 holds putdata offset
and %g2, 0xff, %g2 ! just want byte 5
/*
* If no bytes to write, finished small put interrupt handling.
* Skip to cleanup.
*/
cmp %g0, %g1 ! any bytes to write?
be,a,pn %xcc, 5f ! none, branch to cleanup
sub %g0, 1, %g1 ! dmv_finish_intr: no softint
/*
* %g1 holds the number of bytes left to write
* %g2 holds the message putdata offset to write
* %g4 has pfn_list pointer
*
* still don't need %g3, %g5 or %g6
*
* Calculate the physical address to start at. The segment offset
* is translated into the page backing the segment offset. The
* exact physical address is this page plus the offset into this
* page.
*/
mov IRDR_1, %g3
ldxa [%g3]ASI_INTR_RECEIVE, %g3 ! bytes 8-15
srlx %g3, MMU_PAGESHIFT, %g7 ! calculate pfn_list index
sllx %g7, 3, %g7 ! calculate pfn_list offset
add %g4, %g7, %g4 ! add to pfn_list start address
ldx [%g4], %g5 ! get the pfn
cmp %g5, PFN_INVALID ! is pfn invalid?
be,a,pn %xcc, 5f ! yes; toss this packet
sub %g0, 1, %g1 ! dmv_finish_intr: no softint
sllx %g5, MMU_PAGESHIFT, %g5 ! turn into a physical address
/* calculate offset into the page */
sllx %g3, (64 - MMU_PAGESHIFT), %g3 ! clean out upper bits
srlx %g3, (64 - MMU_PAGESHIFT), %g3 ! shift back to get page offset
add %g5, %g3, %g5 ! add; now have start address
6:
/*
* While (len > 0) {}
*
* Loop through the data in putdata, writing it to physical memory
* using the largest possible sized atomic write in each case: 8,
* 4, 2 or 1 byte chunks. The alignment of the write location and
* number of bytes to write determines the largest usable write to
* use.
*
* The data in the putdata buffer is guaranteed be aligned so that
* each Mondo register falls onto an aligned 8 bytes in the
* segment.
*
* %g1 holds the number of bytes left to write
* %g2 holds the message putdata offset to write
* %g4 holds the address of the current pfn_list entry
* %g5 holds the physical address to write to
* still don't need %g3 or %g6
*/
/*
* The maximum amount of bytes that can be transfered via a DMV is
* is 48 bytes. The data payload can span two Dcache lines. Invalidate
* two D$ lines starting at %g5. We do not have to mask %g5 as the
* lower 5 bits of the physical address are ignored.
*/
sethi %hi(dcache_line_mask), %g6
ld [%g6 + %lo(dcache_line_mask)], %g6
and %g5, %g6, %g3
sethi %hi(dcache_linesize), %g6
ld [%g6 + %lo(dcache_linesize)], %g6
stxa %g0, [%g3]ASI_DC_INVAL
membar #Sync
stxa %g0, [%g3 + %g6]ASI_DC_INVAL
membar #Sync
/*
* Read in appropriate message data based on the offset into the
* message putdata field. Offset 0 of the putdata starts at byte
* 16 in the message buffer, or IRDR_2.
*/
subcc %g2, 8, %g0
blu,a,pt %xcc, calc_valid_bytes
mov IRDR_2, %g3
subcc %g2, 16, %g0
blu,a,pt %xcc, calc_valid_bytes
mov IRDR_3, %g3
subcc %g2, 24, %g0
blu,a,pt %xcc, calc_valid_bytes
mov IRDR_4, %g3
subcc %g2, 32, %g0
blu,a,pt %xcc, calc_valid_bytes
mov IRDR_5, %g3
subcc %g2, 40, %g0
blu,a,pt %xcc, calc_valid_bytes
mov IRDR_6, %g3
/*
* must be the last register (bytes 40 - 47 of putdata)
*/
mov IRDR_7, %g3
calc_valid_bytes:
/*
* %g3 now IRDR_X register that needs to be read
*
* Read the IRDR_X register into %g3
* Calculate the number of valid bytes in register.
* First, subtract off bytes at the start of the register
* that shouldn't be written (this only happens for IRDR_2).
*/
ldxa [%g3]ASI_INTR_RECEIVE, %g3
and %g2, 7, %g6 ! byte offset into this register
set 8, %g7 ! calc number of valid bytes:
sub %g7, %g6, %g6 ! (8 - byte offset)
/*
* %g3 holds the data to write, with the valid bytes in the
* least significant bytes of the register
*
* %g6 holds the number valid bytes
*
* The number of bytes from this register to be written must be no
* more than the lesser of # valid bytes (%g6) and bytes left (%g1).
*/
cmp %g6, %g1
bleu,a,pn %xcc, calc_offset_bytes ! %g6 holds correct value
nop
/*
* Adjust for the number of bytes in %g1. Shift register to the
* right to get the valid bytes in the lower part of the register.
*/
sub %g6, %g1, %g7 ! get rid of how many bytes?
sllx %g7, 3, %g7 ! calculate number of bits to shift
srlx %g3, %g7, %g3 ! shift data
mov %g1, %g6
calc_offset_bytes:
/*
* %g3 holds the data to write, with the valid bytes in the
* least significant bytes of the register
*
* %g6 holds the number of valid bytes
*
* The maximum number of bytes to write is the lesser of the
* number of valid bytes (%g6) and the number of bytes that
* can be written atomicly at this offset.
*/
and %g5, 1, %g7 ! offset is 1 byte aligned
cmp %g7, 1
be,a,pn %xcc, calc_least_bytes ! can only write 1 byte
nop
and %g5, 0x2, %g7 ! offset is 2 byte aligned
cmp %g7, 0x2
be,a,pn %xcc, calc_least_bytes ! can only write 2 bytes
nop
and %g5, 0x4, %g7 ! offset 4 byte aligned
cmp %g7, 0x4
be,a,pn %xcc, calc_least_bytes ! can only write 4 bytes
nop
set 8, %g7 ! offset is 8 byte aligned
calc_least_bytes:
/*
* %g6 holds the number of valid bytes
* %g7 holds the max atomic write bytes
*
* save the lesser of %g6 and %g7 in %g7
*/
cmp %g7, %g6
bleu,a,pn %xcc, calc_write_bytes ! %g7 holds correct value
nop
mov %g6, %g7
calc_write_bytes:
/*
* %g3 holds the data to write, with the valid bytes in the
* least significant bytes of the register
*
* %g6 holds the number of valid bytes
*
* %g7 holds max number of bytes to write
*/
cmp %g7, 1 ! can only write 1 byte
be,a %xcc, write_one
sub %g6, 1, %g6 ! calculate # of excess bytes
cmp %g7, 3
bleu,a,pn %xcc, write_two ! can only write 2 bytes
sub %g6, 2, %g6 ! calculate # of excess bytes
cmp %g7, 7
bleu,a,pn %xcc, write_four ! can only write 4 bytes
sub %g6, 4, %g6 ! calculate # of excess bytes
ba,a write_eight ! can write all 8 bytes
nop
write_one: /* write 1 byte */
/*
* %g6 hold number of excess bytes (shift right to get rid of them)
*/
sllx %g6, 3, %g6 ! how many bits is that?
srlx %g3, %g6, %g3
rdpr %pstate, %g6
andn %g6, PSTATE_IE | PSTATE_AM, %g7
wrpr %g7, 0, %pstate
stba %g3, [%g5]ASI_MEM ! store 1 byte
wrpr %g0, %g6, %pstate ! restore earlier pstate register value
sub %g1, 1, %g1 ! decrement bytes left to write
add %g2, 1, %g2 ! increment putdata offset
add %g5, 1, %g5 ! increment address to write to
ba check_complete
nop
write_two: /* write 2 bytes */
/*
* %g6 hold number of excess bytes (shift right to get rid of them)
*/
sllx %g6, 3, %g6 ! how many bits is that?
srlx %g3, %g6, %g3
rdpr %pstate, %g6
andn %g6, PSTATE_IE | PSTATE_AM, %g7
wrpr %g7, 0, %pstate
stha %g3, [%g5]ASI_MEM ! store 2 bytes
wrpr %g0, %g6, %pstate ! restore earlier pstate register value
sub %g1, 2, %g1 ! decrement bytes left to write
add %g2, 2, %g2 ! increment putdata offset
add %g5, 2, %g5 ! increment address to write to
ba check_complete
nop
write_four: /* write 4 bytes */
/*
* %g6 hold number of excess bytes (shift right to get rid of them)
*/
sllx %g6, 3, %g6 ! how many bits is that?
srlx %g3, %g6, %g3
rdpr %pstate, %g6
andn %g6, PSTATE_IE | PSTATE_AM, %g7
wrpr %g7, 0, %pstate
sta %g3, [%g5]ASI_MEM ! store 4 bytes
wrpr %g0, %g6, %pstate ! restore earlier pstate register value
sub %g1, 4, %g1 ! decrement bytes left to write
add %g2, 4, %g2 ! increment putdata offset
add %g5, 4, %g5 ! increment address to write to
ba check_complete
nop
write_eight: /* write 8 bytes */
rdpr %pstate, %g6
andn %g6, PSTATE_IE | PSTATE_AM, %g7
wrpr %g7, 0, %pstate
stxa %g3, [%g5]ASI_MEM ! store 8 bytes
wrpr %g0, %g6, %pstate ! restore earlier pstate register value
sub %g1, 8, %g1 ! decrement bytes left to write
add %g2, 8, %g2 ! increment putdata offset
add %g5, 8, %g5 ! increment address to write to
ba check_complete
nop
check_complete:
/*
* If no bytes left to write, finished small put interrupt handling.
* Skip to cleanup.
*/
cmp %g0, %g1 ! any bytes left?
be,a,pn %xcc, smallput_done ! none left, branch to cleanup
nop
/*
* Determine whether there are any bytes left on the current page.
* If not, get the next page from the pfn_list, and loop.
*/
sllx %g5, (64 - MMU_PAGESHIFT), %g7 ! clean out upper bits
bnz %xcc, 6b ! more bytes left on this page, loop
nop
add %g4, 8, %g4 ! move to next entry in pfn_list
ldx [%g4], %g5 ! get the pfn
cmp %g5, PFN_INVALID ! is pfn invalid?
be,a,pn %xcc, smallput_done ! yes; toss rest of packet
nop
sllx %g5, MMU_PAGESHIFT, %g5 ! turn it into a physical address
ba 6b ! loop
nop
smallput_done:
membar #Sync ! flush write cache
ba 5f ! branch to cleanup
sub %g0, 1, %g1 ! dmv_finish_intr: no softint
/*
* Handle recvq messages
*/
1:
ldx [%g3], %g4 ! get packet_ring_info
set 1, %g5 ! turn on lock bit
sllx %g5, 48, %g5
or %g4, %g5, %g5
casxa [%g3]ASI_N, %g4, %g5
cmp %g4, %g5
bne,pn %xcc, 1b
nop
! %g5 has the current packet info
! The bits of packet info have the following structure
! 48-63 lock
! 32-47 head
! 16-31 tail
! 0 -15 size
sllx %g5, 16, %g4
srlx %g4, 48, %g4 ! %g4 has the head pointer
ldx [%g6 + PACKET_RING], %g3
mulx %g4, WRSM_INTR_PACKET_SIZE, %g7
add %g3, %g7, %g3
! %g2 still has IRDR_0
! %g3 is a pointer to the next available packet ring
! %g4 still has packet_ring_head which we will need later
! %g5 has the packet_info data
! %g6 has pointer to the recvq struct
!
! Now store the payload data into the packet
stx %g2, [%g3]
mov IRDR_1, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 8]
mov IRDR_2, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 16]
mov IRDR_3, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 24]
mov IRDR_4, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 32]
mov IRDR_5, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 40]
mov IRDR_6, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 48]
mov IRDR_7, %g7
ldxa [%g7]ASI_INTR_RECEIVE, %g7
stx %g7, [%g3 + 56]
! %g2 and %g3 are now available
sllx %g5, 32, %g3
srlx %g3, 48, %g3 ! %g3 has the tail pointer
sllx %g5, 48, %g1
srlx %g1, 48, %g1 ! %g1 has the ring size
! g2, g5 and g7 available
/*
* NOTE: num_items does not include the interrupt serviced
* g4 (head) was not yet incremented
*/
lduw [%g6 + HIGH_WATER_MARK], %g2 ! load the HWM in g2 (uint32)
subcc %g4, %g3, %g5 ! g5 = head - tail (num_items)
bl,a 6f ! if (head < tail)
add %g1, %g5, %g5 ! g5 = size + (head - tail)
6:
inc %g5 ! account for this interrupt
cmp %g5, %g2 ! num_items ? high_water_mark
bl 8f ! num_items < high_water_mark
nop
/* num_items >= high_water_mark */
ldx [%g6 + HIGH_WATER_COUNT], %g2
inc %g2
stx %g2, [%g6 + HIGH_WATER_COUNT]
set WRSM_MAX_WCIS, %g2
9: brz,pn %g2, 8f ! while (i > 0) {
dec %g2 ! %g2 = i-- : index into wci array
ldx [%g6 + SRAM_PADDR], %g5 ! beginning of wci sram
sllx %g2, 3, %g7 ! g7 = g2 * sizeof(void *)
add %g5, %g7, %g5 ! address of i-th wci
ldx [%g5], %g5 ! load the address of i-th sram
brz,a %g5, 9b ! if (%g5 == NULL) break ;
nop
lduw [%g6 + CMMU_INDEX], %g7 ! offset to correct cmmu (uint32)
sllx %g7, 6, %g7 ! %g7 = %g7 * sizeof(CMMU entry)
add %g5, %g7, %g5 ! get the address
set WRSM_CMMU_0_DISABLE, %g7 ! bit 2 and 26 (error + valid)
! (set handles 32 bits)
stxa %g7, [%g5]ASI_IO ! write to the cmmu.
ba 9b ! }
nop
8:
mov %g0, %g7
cmp %g3, %g4 ! compare head and tail
move %xcc, RING_EMPTY, %g7
! Increment the packet_ring_head
mov %g4, %g2 ! save head in case ring full
inc %g4
cmp %g4, %g1 ! %g1 = ring size, %g4 = head
movge %icc, %g0, %g4 ! if head >= size then head = 0
cmp %g3, %g4 ! if head==tail then the ring is full
bne %xcc, 1f
nop
mov %g2, %g4 ! restore original head
#ifdef DEBUG
set wrsm_dropped_intr, %g2
ldx [%g2], %g5
inc %g5
stx %g5, [%g2]
#endif /* DEBUG */
mov RING_FULL, %g7
1:
! Rebuild packet_ring_info in %g5
mov %g1, %g5 ! size
sllx %g3, 16, %g3
or %g5, %g3, %g5 ! tail
sllx %g4, 32, %g4
or %g5, %g4, %g5 ! head
stx %g5, [%g6 + PACKET_RING_INFO] ! release lock
#ifdef DEBUG
set wrsm_trap_ring_info, %g2
stx %g5, [%g2]
#endif
ldx [%g6 + DRAINER], %g3 ! g3 = recvq->drainer
cmp %g7, RING_EMPTY ! if ring is non-empty
bne,pn %xcc, 5f ! exit without a softint
sub %g0, 1, %g1
/*
* If recvq->drainer_next != NULL then this recvq is
* already on a service list, so don't queue it again
*/
ldx [%g6 + DRAINER_NEXT], %g4
brnz,pn %g4, 4f
nop
2:
! Insert the recvq into the drainer's pending service
! list (PSL)
add %g3, DRAINER_PSL, %g2 ! g2 = &drainer->psl
ldx [%g2], %g4 ! g4 = drainer->psl
3:
mov %g6, %g5 ! g5 = revcq
stx %g4, [%g6 + DRAINER_NEXT] ! recvq->dranr_next=dranr->psl
mov %g4, %g1 ! %g1 has old value of psl
! casx does the following as an atomic:
! if (g4 == *g2) { /* If g4 equals what's at g2... */
! swap *g2, g5;
! } else { /* Else... */
! g5 = *g2; /* Place what's currently in g2 into g5 */
! }
! Regardless of the outcome, g5 will contain what was at g2 when
! the operation began. The only way to see if the store took place
! is to see if the data at g2 hasn't changed. In other words, the
! store took place iff g4==g5 after the casx instruction.
casxa [%g2]ASI_N, %g4, %g5 ! drainer->psl = recvq
cmp %g4, %g5 ! if psl hasn't changed...
be %xcc, 4f ! then break out of loop
nop
mov %g5, %g4 ! else g4 = new drainer->psl
ba 3b ! loop
nop
4:
! if drainer->psl was PSL_IDLE before the insert, then we
! generate a softint, otherwise we don't
cmp %g1, WRSM_INTR_PSL_IDLE
bne,pn %xcc, 5f
sub %g0, 1, %g1
#ifdef DEBUG
! Keep track of the number of softints triggered
set wrsm_trap_softint_count, %g5
ldx [%g5], %g2
inc %g2
stx %g2, [%g5]
#endif
! Get the softint inum from the drainer structure
ld [%g3 + DRAINER_INUM], %g1
5:
set dmv_finish_intr, %g5
jmp %g5
nop
#ifdef WRSM_STORE_TRAP_DATA
30:
set wrsm_trap_data, %g7
stx %g3, [%g7+0]
stx %g4, [%g7+8]
stx %g5, [%g7+16]
stx %g6, [%g7+24]
! If no secondary interrupt, return -1
set -1, %g1
sra %g1, 0, %g1
! Return
set dmv_finish_intr, %g5
jmp %g5
nop
#endif
SET_SIZE(wrsm_tl1_handler)
#endif /* !lint */