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