diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/cpc/common/cputrack.c | 10 | ||||
-rw-r--r-- | usr/src/cmd/cpc/cputrack/Makefile.com | 9 | ||||
-rw-r--r-- | usr/src/cmd/cpc/cputrack/i386/Makefile | 11 | ||||
-rw-r--r-- | usr/src/lib/libcpc/common/libcpc.c | 5 | ||||
-rw-r--r-- | usr/src/uts/common/os/kcpc.c | 42 | ||||
-rw-r--r-- | usr/src/uts/common/sys/cpc_impl.h | 12 | ||||
-rw-r--r-- | usr/src/uts/common/sys/kcpc.h | 8 | ||||
-rw-r--r-- | usr/src/uts/sun4v/Makefile.workarounds | 9 | ||||
-rw-r--r-- | usr/src/uts/sun4v/cpu/niagara2.c | 22 | ||||
-rw-r--r-- | usr/src/uts/sun4v/cpu/niagara2_asm.s | 55 | ||||
-rw-r--r-- | usr/src/uts/sun4v/generic/Makefile | 5 | ||||
-rw-r--r-- | usr/src/uts/sun4v/niagara2/Makefile | 5 | ||||
-rw-r--r-- | usr/src/uts/sun4v/os/mach_startup.c | 23 | ||||
-rw-r--r-- | usr/src/uts/sun4v/pcbe/niagara2_pcbe.c | 278 | ||||
-rw-r--r-- | usr/src/uts/sun4v/sys/niagara2regs.h | 28 |
15 files changed, 388 insertions, 134 deletions
diff --git a/usr/src/cmd/cpc/common/cputrack.c b/usr/src/cmd/cpc/common/cputrack.c index 37aaf9f600..9b334d0aeb 100644 --- a/usr/src/cmd/cpc/common/cputrack.c +++ b/usr/src/cmd/cpc/common/cputrack.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -80,7 +80,9 @@ cputrack_pctx_errfn(const char *fn, const char *fmt, va_list ap) } static int cputrack(int argc, char *argv[], int optind); +#if defined(__i386) static void p4_ht_error(void); +#endif #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" @@ -343,9 +345,11 @@ pinit_lwp(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) errstr = strerror(errno); if (errno == EAGAIN) (void) cpc_unbind(cpc, set); +#if defined(__i386) if (errno == EACCES) p4_ht_error(); else +#endif (void) fprintf(stderr, gettext( "%6d: init_lwp: can't bind perf counters " "to lwp%d - %s\n"), (int)pid, (int)lwpid, @@ -690,6 +694,8 @@ cputrack(int argc, char *argv[], int optind) return (err != 0 ? 1 : 0); } +#if defined(__i386) + #define OFFLINE_CMD "/usr/sbin/psradm -f " #define BUFSIZE 5 /* enough for "n " where n is a cpuid */ @@ -811,3 +817,5 @@ p4_ht_error(void) exit(1); } + +#endif /* defined(__i386) */ diff --git a/usr/src/cmd/cpc/cputrack/Makefile.com b/usr/src/cmd/cpc/cputrack/Makefile.com index a6b61171f1..d67fb933dd 100644 --- a/usr/src/cmd/cpc/cputrack/Makefile.com +++ b/usr/src/cmd/cpc/cputrack/Makefile.com @@ -2,9 +2,8 @@ # 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. +# Common Development and Distribution License (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. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -31,7 +30,7 @@ include ../../../Makefile.cmd PROG = cputrack OBJS = $(PROG).o caps.o time.o setgrp.o strtoset.o SRCS = $(OBJS:%.o=../../common/%.c) -LDLIBS += -lcpc -lpctx -lkstat +LDLIBS += -lcpc -lpctx CFLAGS += $(CCVERBOSE) $(CTF_FLAGS) CFLAGS64 += $(CCVERBOSE) $(CTF_FLAGS) diff --git a/usr/src/cmd/cpc/cputrack/i386/Makefile b/usr/src/cmd/cpc/cputrack/i386/Makefile index c2eedd1f9c..139c8bd92a 100644 --- a/usr/src/cmd/cpc/cputrack/i386/Makefile +++ b/usr/src/cmd/cpc/cputrack/i386/Makefile @@ -2,9 +2,8 @@ # 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. +# Common Development and Distribution License (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. @@ -20,11 +19,13 @@ # CDDL HEADER END # # -# Copyright (c) 1999 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" include ../Makefile.com +LDLIBS += -lkstat + install: all $(ROOTPROG32) diff --git a/usr/src/lib/libcpc/common/libcpc.c b/usr/src/lib/libcpc/common/libcpc.c index bb18b2f090..058e163ccd 100644 --- a/usr/src/lib/libcpc/common/libcpc.c +++ b/usr/src/lib/libcpc/common/libcpc.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -953,7 +953,8 @@ static const char *errstr[] = { "Invalid flags in a request\n", /* CPC_REQ_INVALID_FLAGS */ "Requests conflict with each other\n", /* CPC_CONFLICTING_REQS */ "Attribute requires the cpc_cpu privilege\n", /* CPC_ATTR_REQUIRES_PRIVILEGE */ -"Couldn't bind LWP to requested processor\n" /* CPC_PBIND_FAILED */ +"Couldn't bind LWP to requested processor\n", /* CPC_PBIND_FAILED */ +"Hypervisor event access denied\n" /* CPC_HV_NO_ACCESS */ }; /*VARARGS3*/ diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c index 4ed3b8b354..19867ff840 100644 --- a/usr/src/uts/common/os/kcpc.c +++ b/usr/src/uts/common/os/kcpc.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -302,9 +302,13 @@ kcpc_configure_reqs(kcpc_ctx_t *ctx, kcpc_set_t *set, int *subcode) &(rp->kr_config), (void *)ctx)) != 0) { kcpc_free_configs(set); *subcode = ret; - if (ret == CPC_ATTR_REQUIRES_PRIVILEGE) + switch (ret) { + case CPC_ATTR_REQUIRES_PRIVILEGE: + case CPC_HV_NO_ACCESS: return (EACCES); - return (EINVAL); + default: + return (EINVAL); + } } ctx->kc_pics[n].kp_req = rp; @@ -364,6 +368,13 @@ kcpc_sample(kcpc_set_t *set, uint64_t *buf, hrtime_t *hrtime, uint64_t *tick) } kpreempt_enable(); + + /* + * The config may have been invalidated by + * the pcbe_sample op. + */ + if (ctx->kc_flags & KCPC_CTX_INVALID) + return (EAGAIN); } if (copyout(set->ks_data, buf, @@ -746,8 +757,7 @@ kcpc_ctx_clone(kcpc_ctx_t *ctx, kcpc_ctx_t *cctx) } } if (kcpc_configure_reqs(cctx, cks, &code) != 0) - panic("kcpc_ctx_clone: configure of context %p with " - "set %p failed with subcode %d", cctx, cks, code); + kcpc_invalidate_config(cctx); } @@ -890,7 +900,7 @@ kcpc_hw_overflow_intr(caddr_t arg1, caddr_t arg2) if (pcbe_ops == NULL || (bitmap = pcbe_ops->pcbe_overflow_bitmap()) == 0) return (DDI_INTR_UNCLAIMED); -#ifdef N2_ERRATUM_134 +#ifdef N2_1x_CPC_WORKAROUNDS /* * Check if any of the supported counters overflowed. If * not, it's a spurious overflow trap (Niagara2 1.x silicon @@ -1116,7 +1126,11 @@ kcpc_lwp_create(kthread_t *t, kthread_t *ct) kcpc_ctx_clone(ctx, cctx); rw_exit(&kcpc_cpuctx_lock); - cctx->kc_flags = ctx->kc_flags; + /* + * Copy the parent context's kc_flags field, but don't overwrite + * the child's in case it was modified during kcpc_ctx_clone. + */ + cctx->kc_flags |= ctx->kc_flags; cctx->kc_thread = ct; cctx->kc_cpuid = -1; ct->t_cpc_set = cctx->kc_set; @@ -1298,6 +1312,20 @@ kcpc_invalidate_all(void) } /* + * Interface for PCBEs to signal that an existing configuration has suddenly + * become invalid. + */ +void +kcpc_invalidate_config(void *token) +{ + kcpc_ctx_t *ctx = token; + + ASSERT(ctx != NULL); + + atomic_or_uint(&ctx->kc_flags, KCPC_CTX_INVALID); +} + +/* * Called from lwp_exit() and thread_exit() */ void diff --git a/usr/src/uts/common/sys/cpc_impl.h b/usr/src/uts/common/sys/cpc_impl.h index 8869dea4a3..f7bc7a5838 100644 --- a/usr/src/uts/common/sys/cpc_impl.h +++ b/usr/src/uts/common/sys/cpc_impl.h @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,8 +57,10 @@ typedef struct { #define CPC_OVF_NOTIFY_EMT 0x1 #define CPC_COUNT_USER 0x2 #define CPC_COUNT_SYSTEM 0x4 +#define CPC_COUNT_HV 0x8 -#define KCPC_REQ_ALL_FLAGS 0x7 +#define KCPC_REQ_ALL_FLAGS (CPC_OVF_NOTIFY_EMT | CPC_COUNT_USER | \ + CPC_COUNT_SYSTEM | CPC_COUNT_HV) #define KCPC_REQ_VALID_FLAGS(flags) \ (((flags) | KCPC_REQ_ALL_FLAGS) == KCPC_REQ_ALL_FLAGS) @@ -216,6 +217,7 @@ extern int kcpc_pcbe_tryload(const char *, uint_t, uint_t, uint_t); #define CPC_CONFLICTING_REQS 8 /* Reqs in the set conflict */ #define CPC_ATTR_REQUIRES_PRIVILEGE 9 /* Insufficient privs for atr */ #define CPC_PBIND_FAILED 10 /* Couldn't bind to processor */ +#define CPC_HV_NO_ACCESS 11 /* No perm for HV events */ #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/kcpc.h b/usr/src/uts/common/sys/kcpc.h index ffcd542fef..50bce17513 100644 --- a/usr/src/uts/common/sys/kcpc.h +++ b/usr/src/uts/common/sys/kcpc.h @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +128,7 @@ extern void kcpc_free_set(kcpc_set_t *set); extern void *kcpc_next_config(void *token, void *current, uint64_t **data); +extern void kcpc_invalidate_config(void *token); /* * Called by a PCBE to determine if nonprivileged access to counters should be diff --git a/usr/src/uts/sun4v/Makefile.workarounds b/usr/src/uts/sun4v/Makefile.workarounds index 632b91da9f..ec7246444e 100644 --- a/usr/src/uts/sun4v/Makefile.workarounds +++ b/usr/src/uts/sun4v/Makefile.workarounds @@ -21,7 +21,7 @@ # # uts/sun4v/Makefile.workarounds # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -35,8 +35,5 @@ WORKAROUND_DEFS = WORKAROUND_DEFS += -DQCN_POLLING # XXXQ WORKAROUND_DEFS += -DDO_CORELEVEL_LOADBAL -# The following is required to support Niagara2 1.0 -WORKAROUND_DEFS += -DN2_ERRATUM_49 # %stick_compare{6:0} ignored -WORKAROUND_DEFS += -DN2_IDLE_WORKAROUND -WORKAROUND_DEFS += -DN2_ERRATUM_112 # multiple traps for 1 event -WORKAROUND_DEFS += -DN2_ERRATUM_134 # PMU doesn't set OV bit +# The following is required to support Niagara2 1.x +WORKAROUND_DEFS += -DN2_1x_CPC_WORKAROUNDS # Errata 94, 112, 132, & 134 diff --git a/usr/src/uts/sun4v/cpu/niagara2.c b/usr/src/uts/sun4v/cpu/niagara2.c index 1503304a30..2735b47016 100644 --- a/usr/src/uts/sun4v/cpu/niagara2.c +++ b/usr/src/uts/sun4v/cpu/niagara2.c @@ -72,6 +72,19 @@ static hsvc_info_t niagara2_hsvc = { NIAGARA2_HSVC_MINOR, cpu_module_name }; +#ifdef N2_1x_CPC_WORKAROUNDS +static uint64_t cpu_ver; /* Niagara2 CPU version reg */ +uint64_t ni2_1x_perf_workarounds = 0; + +/* Niagara2 CPU version register */ +#define VER_MASK_MAJOR_SHIFT 28 +#define VER_MASK_MAJOR_MASK 0xf + +extern uint64_t va_to_pa(void *); +extern uint64_t ni2_getver(); /* HV code to get %hver */ +extern uint64_t niagara2_getver(uint64_t ni2_getver_ra, uint64_t *cpu_version); +#endif + void cpu_setup(void) { @@ -79,6 +92,15 @@ cpu_setup(void) extern int cpc_has_overflow_intr; int status; +#ifdef N2_1x_CPC_WORKAROUNDS + /* + * Get CPU version for Niagara2 part. + */ + if (niagara2_getver(va_to_pa((void *)ni2_getver), &cpu_ver) == H_EOK && + ((cpu_ver >> VER_MASK_MAJOR_SHIFT) & VER_MASK_MAJOR_MASK) <= 1) + ni2_1x_perf_workarounds = 1; +#endif + /* * Negotiate the API version for Niagara2 specific hypervisor * services. diff --git a/usr/src/uts/sun4v/cpu/niagara2_asm.s b/usr/src/uts/sun4v/cpu/niagara2_asm.s index 09dc06cd4b..467e7d9a0b 100644 --- a/usr/src/uts/sun4v/cpu/niagara2_asm.s +++ b/usr/src/uts/sun4v/cpu/niagara2_asm.s @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -142,3 +142,56 @@ cpu_inv_tsb(caddr_t tsb_base, uint_t tsb_bytes) SET_SIZE(cpu_inv_tsb) #endif /* lint */ + +#ifdef N2_1x_CPC_WORKAROUNDS +/* + * This workaround will be removed prior to the FCS release. + */ + +#if defined(lint) + +/*ARGSUSED*/ +uint64_t +niagara2_getver(uint64_t ni_getver_ra, uint64_t *cpu_version) +{ return (0); } + +#else /* lint */ + +/* +* The following hypervisor calls are used to get the CPU version register +*/ +#define HV_DIAG_RA2PA 0x200 +#define HV_DIAG_HEXEC 0x201 + + /* + * niagara2_getver(uint64_t ni_getver_ra, uint64_t *cpu_version) + */ + ENTRY(niagara2_getver) + mov %o1, %o4 ! save cpu_version pointer + mov HV_DIAG_RA2PA, %o5 ! get PA of ni_getver routine + ta FAST_TRAP + brnz,pn %o0, 2f ! return error in not successful + nop + + mov %o1, %o0 ! move ni_getver PA to %o0 + mov HV_DIAG_HEXEC, %o5 + ta FAST_TRAP + brnz,pn %o0, 2f + nop + stx %o1, [%o4] ! copy version +2: + retl + nop + SET_SIZE(niagara2_getver) + /* + * Hypervisor code sequence to get chip version via HV_DIAG_HEXEC. + * Returns E_HOK in %o0 and %hver register value in %o1. + */ + .global ni2_getver + .align 16 +ni2_getver: + mov H_EOK, %o0 + rdhpr %hver, %o1 + done +#endif /* lint */ +#endif diff --git a/usr/src/uts/sun4v/generic/Makefile b/usr/src/uts/sun4v/generic/Makefile index 0acc03e527..99650fa269 100644 --- a/usr/src/uts/sun4v/generic/Makefile +++ b/usr/src/uts/sun4v/generic/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -72,6 +72,9 @@ INSTALL_TARGET = def $(BINARY) $(ROOTMODULE) $(ROOTSOFTLINKS) # CFLAGS += $(CCVERBOSE) +# The following is required to support Niagara2 1.0 +WORKAROUND_DEFS += -DN2_ERRATUM_49 # %stick_compare{6:0} ignored + # # cpu-module-specific flags # diff --git a/usr/src/uts/sun4v/niagara2/Makefile b/usr/src/uts/sun4v/niagara2/Makefile index f2b343e8ad..80d5f729a1 100644 --- a/usr/src/uts/sun4v/niagara2/Makefile +++ b/usr/src/uts/sun4v/niagara2/Makefile @@ -20,7 +20,7 @@ # # # uts/sun4v/niagara2/Makefile -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -68,6 +68,9 @@ INSTALL_TARGET = def $(BINARY) $(ROOTMODULE) # CFLAGS += $(CCVERBOSE) -DNIAGARA2_IMPL +# The following is required to support Niagara2 1.0 +WORKAROUND_DEFS += -DN2_ERRATUM_49 # %stick_compare{6:0} ignored + # # cpu-module-specific flags # diff --git a/usr/src/uts/sun4v/os/mach_startup.c b/usr/src/uts/sun4v/os/mach_startup.c index e9916773f4..100bfd90da 100644 --- a/usr/src/uts/sun4v/os/mach_startup.c +++ b/usr/src/uts/sun4v/os/mach_startup.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -77,14 +77,6 @@ phys_install_has_changed(void) } -#ifdef N2_IDLE_WORKAROUND -/* - * Tuneable to control enabling of IDLE loop workaround on Niagara2 1.x parts. - * This workaround will be removed before the RR. - */ -int n2_idle_workaround; -#endif - /* * Halt the present CPU until awoken via an interrupt */ @@ -138,19 +130,6 @@ cpu_halt(void) return; } -#ifdef N2_IDLE_WORKAROUND - /* - * The following workaround for Niagara2, when enabled, forces the - * IDLE CPU to wait in a tight loop until something becomes runnable - * locally, minimizing the overall CPU usage on an IDLE CPU. - */ - if (n2_idle_workaround) { - while (cpup->cpu_disp->disp_nrunnable == 0) { - (void) hv_cpu_yield(); - } - } -#endif - /* * We're on our way to being halted. Wait until something becomes * runnable locally or we are awaken (i.e. removed from the halt set). diff --git a/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c b/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c index 1e34194fa0..972d20cd50 100644 --- a/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c +++ b/usr/src/uts/sun4v/pcbe/niagara2_pcbe.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,6 +40,8 @@ #include <sys/sdt.h> #include <sys/niagara2regs.h> #include <sys/hsvc.h> +#include <sys/hypervisor_api.h> +#include <sys/disp.h> static int ni2_pcbe_init(void); static uint_t ni2_pcbe_ncounters(void); @@ -64,6 +66,10 @@ extern uint64_t ultra_getpic(void); extern uint64_t ultra_gettick(void); extern char cpu_module_name[]; +#ifdef N2_1x_CPC_WORKAROUNDS +extern uint64_t ni2_1x_perf_workarounds; +#endif + pcbe_ops_t ni2_pcbe_ops = { PCBE_VER_1, CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, @@ -94,12 +100,21 @@ typedef struct _ni2_event { const uint32_t emask_valid; /* Mask of unreserved MASK bits */ } ni2_event_t; -#define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_NIAGARA2_PCR_PRIVPIC_SHIFT) +#define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_NIAGARA2_PCR_PRIV_SHIFT) #define EV_END {NULL, 0, 0} -static const uint64_t allstopped = ULTRA_PCR_PRIVPIC; +static const uint64_t allstopped = (ULTRA_PCR_PRIVPIC | + CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); + +/* + * We update this array in the program and allstop routine. The array + * is checked in the sample routine to allow us to only perform the + * PCR.ht bit check when counting is in progress. + */ +static boolean_t ni2_cpc_counting[NCPU]; -static ni2_event_t ni2_events[] = { +#ifdef N2_1x_CPC_WORKAROUNDS +static ni2_event_t ni2_1x_events[] = { { "Idle_strands", 0x000, 0x00 }, { "Br_completed", 0x201, 0x7f }, { "Br_taken", 0x202, 0x7f }, @@ -139,7 +154,52 @@ static ni2_event_t ni2_events[] = { { "CRC_MPA_cksum", 0x720, 0x3f }, EV_END }; +#endif +static ni2_event_t ni2_2x_events[] = { + { "Idle_strands", 0x000, 0x00 }, + { "Br_completed", 0x201, 0xff }, + { "Br_taken", 0x202, 0xff }, + { "Instr_FGU_arithmetic", 0x204, 0xff }, + { "Instr_ld", 0x208, 0xff }, + { "Instr_st", 0x210, 0xff }, + { "Instr_sw", 0x220, 0xff }, + { "Instr_other", 0x240, 0xff }, + { "Atomics", 0x280, 0xff }, + { "Instr_cnt", 0x2fd, 0xff }, + { "IC_miss", 0x301, 0x33 }, + { "DC_miss", 0x302, 0x33 }, + { "L2_imiss", 0x310, 0x33 }, + { "L2_dmiss_ld", 0x320, 0x33 }, + { "ITLB_HWTW_ref_L2", 0x404, 0x3c }, + { "DTLB_HWTW_ref_L2", 0x408, 0x3c }, + { "ITLB_HWTW_miss_L2", 0x410, 0x3c }, + { "DTLB_HWTW_miss_L2", 0x420, 0x3c }, + { "Stream_ld_to_PCX", 0x501, 0x3f }, + { "Stream_st_to_PCX", 0x502, 0x3f }, + { "CPU_ld_to_PCX", 0x504, 0x3f }, + { "CPU_ifetch_to_PCX", 0x508, 0x3f }, + { "CPU_st_to_PCX", 0x510, 0x3f }, + { "MMU_ld_to_PCX", 0x520, 0x3f }, + { "DES_3DES_op", 0x601, 0x3f }, + { "AES_op", 0x602, 0x3f }, + { "RC4_op", 0x604, 0x3f }, + { "MD5_SHA-1_SHA-256_op", 0x608, 0x3f }, + { "MA_op", 0x610, 0x3f }, + { "CRC_TCPIP_cksum", 0x620, 0x3f }, + { "DES_3DES_busy_cycle", 0x701, 0x3f }, + { "AES_busy_cycle", 0x702, 0x3f }, + { "RC4_busy_cycle", 0x704, 0x3f }, + { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0x3f }, + { "MA_busy_cycle", 0x710, 0x3f }, + { "CRC_MPA_cksum", 0x720, 0x3f }, + { "ITLB_miss", 0xb04, 0x0c }, + { "DTLB_miss", 0xb08, 0x0c }, + { "TLB_miss", 0xb0c, 0x0c }, + EV_END +}; + +static ni2_event_t *ni2_events = ni2_2x_events; static const char *ni2_impl_name = "UltraSPARC T2"; static char *evlist; static size_t evlist_sz; @@ -177,6 +237,10 @@ ni2_pcbe_init(void) niagara2_hsvc_major, niagara2_hsvc_minor, status); niagara2_hsvc_available = B_FALSE; } +#ifdef N2_1x_CPC_WORKAROUNDS + if (ni2_1x_perf_workarounds) + ni2_events = ni2_1x_events; +#endif /* * Construct event list. * @@ -260,15 +324,11 @@ ni2_pcbe_event_coverage(char *event) return (0x3); } -#ifdef N2_ERRATUM_112 +#ifdef N2_1x_CPC_WORKAROUNDS uint64_t ni2_ov_tstamp[NCPU]; /* last overflow time stamp */ uint64_t ni2_ov_spurious_range = 1000000; /* 1 msec at 1GHz */ #endif -/* - * These processors cannot tell which counter overflowed. The PCBE interface - * requires such processors to act as if _all_ counters had overflowed. - */ static uint64_t ni2_pcbe_overflow_bitmap(void) { @@ -276,10 +336,6 @@ ni2_pcbe_overflow_bitmap(void) uint64_t pic; uint32_t pic0, pic1; boolean_t update_pic = B_FALSE; -#ifdef N2_ERRATUM_112 - uint64_t tstamp; - processorid_t cpun; -#endif ASSERT(getpil() >= DISP_LEVEL); pcr = ultra_getpcr(); @@ -288,51 +344,73 @@ ni2_pcbe_overflow_bitmap(void) CPC_NIAGARA2_PCR_OV0_SHIFT; overflow |= (pcr & CPC_NIAGARA2_PCR_OV1_MASK) >> CPC_NIAGARA2_PCR_OV1_SHIFT; -#ifdef N2_ERRATUM_112 - /* - * Niagara2 1.x silicon can generate a duplicate overflow trap per - * event. If we take an overflow trap with no counters overflowing, - * return a non-zero bitmask with no OV bit set for supported - * counter so that the framework can ignore this trap. - */ - cpun = CPU->cpu_id; - tstamp = ultra_gettick(); - if (overflow) - ni2_ov_tstamp[cpun] = tstamp; - else if (tstamp < (ni2_ov_tstamp[cpun] + ni2_ov_spurious_range)) - overflow |= 1ULL << 63; -#endif + pic = ultra_getpic(); pic0 = (uint32_t)(pic & PIC0_MASK); pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK); -#ifdef N2_ERRATUM_134 - /* - * In Niagara2 1.x silicon, PMU doesn't set OV bit for precise events. - * So, if we take a trap with the counter within the overflow range - * and the OV bit is not set, we assume OV bit should have been set. - */ +#ifdef N2_1x_CPC_WORKAROUNDS + if (ni2_1x_perf_workarounds) { + uint64_t tstamp; + processorid_t cpun; + + /* + * Niagara2 1.x silicon can generate a duplicate overflow + * trap per event. If we take an overflow trap with no + * counters overflowing, return a non-zero bitmask with no + * OV bit set for supported counter so that the framework + * can ignore this trap. + */ + cpun = CPU->cpu_id; + tstamp = ultra_gettick(); + if (overflow) + ni2_ov_tstamp[cpun] = tstamp; + else if (tstamp < (ni2_ov_tstamp[cpun] + ni2_ov_spurious_range)) + overflow |= 1ULL << 63; - if (PIC_IN_OV_RANGE(pic0)) - overflow |= 0x1; - if (PIC_IN_OV_RANGE(pic1)) - overflow |= 0x2; + /* + * In Niagara2 1.x silicon, PMU doesn't set OV bit for + * precise events. So, if we take a trap with the counter + * within the overflow range and the OV bit is not set, we + * assume OV bit should have been set. + */ + if (PIC_IN_OV_RANGE(pic0)) + overflow |= 0x1; + if (PIC_IN_OV_RANGE(pic1)) + overflow |= 0x2; + } #endif - /* - * Reset the pic, if it is within the overflow range. - */ - if ((overflow & 0x1) && (PIC_IN_OV_RANGE(pic0))) { - pic0 = 0; - update_pic = B_TRUE; + + pcr |= (CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); + + if (overflow & 0x1) { + pcr &= ~(CPC_NIAGARA2_PCR_OV0_MASK | + CPC_NIAGARA2_PCR_HOLDOV0); + if (PIC_IN_OV_RANGE(pic0)) { + pic0 = 0; + update_pic = B_TRUE; + } } - if ((overflow & 0x2) && (PIC_IN_OV_RANGE(pic1))) { - pic1 = 0; - update_pic = B_TRUE; + + if (overflow & 0x2) { + pcr &= ~(CPC_NIAGARA2_PCR_OV1_MASK | + CPC_NIAGARA2_PCR_HOLDOV1); + if (PIC_IN_OV_RANGE(pic1)) { + pic1 = 0; + update_pic = B_TRUE; + } } if (update_pic) ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0); + /* + * The HV interface does not need to be used here because we are + * only resetting the OV bits and do not need to set the HT bit. + */ + DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); + ultra_setpcr(pcr); + return (overflow); } @@ -368,7 +446,7 @@ ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, for (i = 0; i < nattrs; i++) { if (strcmp(attrs[i].ka_name, "hpriv") == 0) { if (attrs[i].ka_val != 0) - flags |= CPC_COUNT_HPRIV; + flags |= CPC_COUNT_HV; } else if (strcmp(attrs[i].ka_name, "emask") == 0) { if ((attrs[i].ka_val | evp->emask_valid) != evp->emask_valid) @@ -386,6 +464,36 @@ ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, (other_config->pcbe_flags != flags)) return (CPC_CONFLICTING_REQS); + /* + * If the hpriv attribute is present, make sure we have + * access to hyperprivileged events before continuing with + * this configuration. If we can set the ht bit in the PCR + * successfully, we must have access to hyperprivileged + * events. + * + * If this is a static per-CPU configuration, the CPC + * driver ensures there can not be more than one for this + * CPU. If this is a per-LWP configuration, the driver + * ensures no static per-CPU counting is ongoing and that + * the target LWP is not already being monitored. + */ + if (flags & CPC_COUNT_HV) { + kpreempt_disable(); + + DTRACE_PROBE1(niagara2__setpcr, uint64_t, + allstopped | CPC_NIAGARA2_PCR_HT); + if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, + allstopped | CPC_NIAGARA2_PCR_HT) != H_EOK) { + kpreempt_enable(); + return (CPC_HV_NO_ACCESS); + } + + DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped); + (void) hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped); + + kpreempt_enable(); + } + cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP); cfg->pcbe_picno = picnum; @@ -409,7 +517,7 @@ ni2_pcbe_program(void *token) uint64_t toe; /* enable trap-on-event for pic0 and pic1 */ - toe = (CPC_COUNT_TOE0 | CPC_COUNT_TOE1); + toe = (CPC_NIAGARA2_PCR_TOE0 | CPC_NIAGARA2_PCR_TOE1); if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == NULL) @@ -418,7 +526,7 @@ ni2_pcbe_program(void *token) if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { pic1 = &nullcfg; nullcfg.pcbe_flags = pic0->pcbe_flags; - toe = CPC_COUNT_TOE0; /* enable trap-on-event for pic0 */ + toe = CPC_NIAGARA2_PCR_TOE0; /* enable trap-on-event for pic0 */ } if (pic0->pcbe_picno != 0) { @@ -430,7 +538,7 @@ ni2_pcbe_program(void *token) tmp = pic0; pic0 = pic1; pic1 = tmp; - toe = CPC_COUNT_TOE1; /* enable trap-on-event for pic1 */ + toe = CPC_NIAGARA2_PCR_TOE1; /* enable trap-on-event for pic1 */ } if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) @@ -444,7 +552,8 @@ ni2_pcbe_program(void *token) */ ASSERT(pic0->pcbe_flags == pic1->pcbe_flags); - ultra_setpcr(allstopped); + ni2_pcbe_allstop(); + ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) | (uint64_t)pic0->pcbe_pic); @@ -453,25 +562,34 @@ ni2_pcbe_program(void *token) CPC_NIAGARA2_PCR_PIC1_SHIFT; if (pic0->pcbe_flags & CPC_COUNT_USER) - pcr |= (1ull << CPC_NIAGARA2_PCR_USR_SHIFT); + pcr |= (1ull << CPC_NIAGARA2_PCR_UT_SHIFT); if (pic0->pcbe_flags & CPC_COUNT_SYSTEM) - pcr |= (1ull << CPC_NIAGARA2_PCR_SYS_SHIFT); - if (pic0->pcbe_flags & CPC_COUNT_HPRIV) - pcr |= (1ull << CPC_NIAGARA2_PCR_HPRIV_SHIFT); + pcr |= (1ull << CPC_NIAGARA2_PCR_ST_SHIFT); + if (pic0->pcbe_flags & CPC_COUNT_HV) + pcr |= (1ull << CPC_NIAGARA2_PCR_HT_SHIFT); pcr |= toe; DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); - /* - * PCR is set by HV using API call hv_niagara_setperf(). - * Silently ignore hvpriv events if access is denied. - */ - if (pic0->pcbe_flags & CPC_COUNT_HPRIV) { - if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != 0) - ultra_setpcr(pcr); + if (pic0->pcbe_flags & CPC_COUNT_HV) { + /* + * The ht bit in the PCR is only writable in + * hyperprivileged mode. So if we are counting + * hpriv events, we must use the HV interface + * hv_niagara_setperf to set the PCR. If this + * fails, assume we no longer have access to + * hpriv events. + */ + if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != H_EOK) { + kcpc_invalidate_config(token); + return; + } } else + /* Set the PCR with no hpriv event counting enabled. */ ultra_setpcr(pcr); + ni2_cpc_counting[CPU->cpu_id] = B_TRUE; + /* * On UltraSPARC, only read-to-read counts are accurate. We cannot * expect the value we wrote into the PIC, above, to be there after @@ -488,7 +606,17 @@ ni2_pcbe_program(void *token) static void ni2_pcbe_allstop(void) { - ultra_setpcr(allstopped); + /* + * We use the HV interface here because if we were counting + * hyperprivileged events, we must reset the PCR.ht bit to stop + * the counting. In the event that this HV call fails, we fall + * back on ultra_setpcr which does not have write access to the + * ht bit. + */ + if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped) != H_EOK) + ultra_setpcr(allstopped); + + ni2_cpc_counting[CPU->cpu_id] = B_FALSE; } static void @@ -500,6 +628,7 @@ ni2_pcbe_sample(void *token) uint64_t *pic1_data; uint64_t *dtmp; uint64_t tmp; + uint64_t pcr; ni2_pcbe_config_t *pic0; ni2_pcbe_config_t *pic1; ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; @@ -529,6 +658,29 @@ ni2_pcbe_sample(void *token) if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) panic("%s: bad config on token %p\n", ni2_impl_name, token); + + if (pic0->pcbe_flags & CPC_COUNT_HV) { + /* + * If the hpriv attribute is present, but the HT bit + * is not set in the PCR, access to hyperprivileged + * events must have been revoked. Only perform this + * check if counting is not stopped. + */ +#ifdef N2_1x_CPC_WORKAROUNDS + if (!ni2_1x_perf_workarounds) { +#endif + pcr = ultra_getpcr(); + DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); + if (ni2_cpc_counting[CPU->cpu_id] && + !(pcr & CPC_NIAGARA2_PCR_HT)) { + kcpc_invalidate_config(token); + return; + } +#ifdef N2_1x_CPC_WORKAROUNDS + } +#endif + } + diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic; if (diff < 0) diff += (1ll << 32); diff --git a/usr/src/uts/sun4v/sys/niagara2regs.h b/usr/src/uts/sun4v/sys/niagara2regs.h index 3113597e39..2f2bf3ea65 100644 --- a/usr/src/uts/sun4v/sys/niagara2regs.h +++ b/usr/src/uts/sun4v/sys/niagara2regs.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,26 +53,32 @@ extern "C" { /* * Niagara2 SPARC Performance Control Register */ -#define CPC_NIAGARA2_PCR_PRIVPIC_SHIFT 0 -#define CPC_NIAGARA2_PCR_SYS_SHIFT 1 -#define CPC_NIAGARA2_PCR_USR_SHIFT 2 -#define CPC_NIAGARA2_PCR_HPRIV_SHIFT 3 +#define CPC_NIAGARA2_PCR_PRIV_SHIFT 0 +#define CPC_NIAGARA2_PCR_ST_SHIFT 1 +#define CPC_NIAGARA2_PCR_UT_SHIFT 2 + +#define CPC_NIAGARA2_PCR_HT_SHIFT 3 +#define CPC_NIAGARA2_PCR_HT (1ull << CPC_NIAGARA2_PCR_HT_SHIFT) + #define CPC_NIAGARA2_PCR_TOE0_SHIFT 4 #define CPC_NIAGARA2_PCR_TOE1_SHIFT 5 - -#define CPC_COUNT_HPRIV (1ull << CPC_NIAGARA2_PCR_HPRIV_SHIFT) -#define CPC_COUNT_TOE0 (1ull << CPC_NIAGARA2_PCR_TOE0_SHIFT) -#define CPC_COUNT_TOE1 (1ull << CPC_NIAGARA2_PCR_TOE1_SHIFT) +#define CPC_NIAGARA2_PCR_TOE0 (1ull << CPC_NIAGARA2_PCR_TOE0_SHIFT) +#define CPC_NIAGARA2_PCR_TOE1 (1ull << CPC_NIAGARA2_PCR_TOE1_SHIFT) #define CPC_NIAGARA2_PCR_PIC0_SHIFT 6 #define CPC_NIAGARA2_PCR_PIC1_SHIFT 19 #define CPC_NIAGARA2_PCR_PIC0_MASK UINT64_C(0xfff) #define CPC_NIAGARA2_PCR_PIC1_MASK UINT64_C(0xfff) -#define CPC_NIAGARA2_PCR_OV0_MASK UINT64_C(0x40000) -#define CPC_NIAGARA2_PCR_OV1_MASK UINT64_C(0x80000000) #define CPC_NIAGARA2_PCR_OV0_SHIFT 18 #define CPC_NIAGARA2_PCR_OV1_SHIFT 30 +#define CPC_NIAGARA2_PCR_OV0_MASK UINT64_C(0x40000) +#define CPC_NIAGARA2_PCR_OV1_MASK UINT64_C(0x80000000) + +#define CPC_NIAGARA2_PCR_HOLDOV0_SHIFT 62 +#define CPC_NIAGARA2_PCR_HOLDOV1_SHIFT 63 +#define CPC_NIAGARA2_PCR_HOLDOV0 (1ull << CPC_NIAGARA2_PCR_HOLDOV0_SHIFT) +#define CPC_NIAGARA2_PCR_HOLDOV1 (1ull << CPC_NIAGARA2_PCR_HOLDOV1_SHIFT) /* * Hypervisor FAST_TRAP API function numbers to get/set DRAM |