delay.c revision 340270
1263008Sroyger/*- 2263008Sroyger * Copyright (c) 1990 The Regents of the University of California. 3263008Sroyger * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> 4263008Sroyger * All rights reserved. 5263008Sroyger * 6263008Sroyger * This code is derived from software contributed to Berkeley by 7263008Sroyger * William Jolitz and Don Ahn. 8263008Sroyger * 9263008Sroyger * Redistribution and use in source and binary forms, with or without 10263008Sroyger * modification, are permitted provided that the following conditions 11263008Sroyger * are met: 12263008Sroyger * 1. Redistributions of source code must retain the above copyright 13263008Sroyger * notice, this list of conditions and the following disclaimer. 14263008Sroyger * 2. Redistributions in binary form must reproduce the above copyright 15263008Sroyger * notice, this list of conditions and the following disclaimer in the 16263008Sroyger * documentation and/or other materials provided with the distribution. 17263008Sroyger * 4. Neither the name of the University nor the names of its contributors 18263008Sroyger * may be used to endorse or promote products derived from this software 19263008Sroyger * without specific prior written permission. 20263008Sroyger * 21263008Sroyger * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22263008Sroyger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23263008Sroyger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24263008Sroyger * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25263008Sroyger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26263008Sroyger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27263008Sroyger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28263008Sroyger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29263008Sroyger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30263008Sroyger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31263008Sroyger * SUCH DAMAGE. 32263008Sroyger * 33263008Sroyger * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 34263008Sroyger */ 35263008Sroyger 36263008Sroyger#include <sys/cdefs.h> 37263008Sroyger__FBSDID("$FreeBSD: stable/11/sys/x86/x86/delay.c 340270 2018-11-08 22:42:55Z jhb $"); 38263008Sroyger 39263008Sroyger/* Generic x86 routines to handle delay */ 40263008Sroyger 41263008Sroyger#include <sys/param.h> 42263008Sroyger#include <sys/systm.h> 43263008Sroyger#include <sys/timetc.h> 44263008Sroyger#include <sys/proc.h> 45263008Sroyger#include <sys/kernel.h> 46263008Sroyger#include <sys/sched.h> 47263008Sroyger 48263008Sroyger#include <machine/clock.h> 49263008Sroyger#include <machine/cpu.h> 50263008Sroyger#include <x86/init.h> 51263008Sroyger 52340270Sjhbstatic void 53340270Sjhbdelay_tsc(int n) 54263008Sroyger{ 55340270Sjhb uint64_t end, now; 56263008Sroyger 57340270Sjhb /* 58340270Sjhb * Pin the current thread ensure correct behavior if the TSCs 59340270Sjhb * on different CPUs are not in sync. 60340270Sjhb */ 61340270Sjhb sched_pin(); 62340270Sjhb now = rdtsc(); 63340270Sjhb end = now + tsc_freq * n / 1000000; 64340270Sjhb do { 65340270Sjhb cpu_spinwait(); 66340270Sjhb now = rdtsc(); 67340270Sjhb } while (now < end); 68340270Sjhb sched_unpin(); 69263008Sroyger} 70263008Sroyger 71263008Sroygerstatic int 72263008Sroygerdelay_tc(int n) 73263008Sroyger{ 74263008Sroyger struct timecounter *tc; 75263008Sroyger timecounter_get_t *func; 76263008Sroyger uint64_t end, freq, now; 77263008Sroyger u_int last, mask, u; 78263008Sroyger 79340270Sjhb /* 80340270Sjhb * Only use the TSC if it is P-state invariant. If the TSC is 81340270Sjhb * not P-state invariant and the CPU is not running at the 82340270Sjhb * "full" P-state, then the TSC will increment at some rate 83340270Sjhb * less than tsc_freq and delay_tsc() will wait too long. 84340270Sjhb */ 85340270Sjhb if (tsc_is_invariant && tsc_freq != 0) { 86340270Sjhb delay_tsc(n); 87340270Sjhb return (1); 88340270Sjhb } 89263008Sroyger tc = timecounter; 90340270Sjhb if (tc->tc_quality <= 0) 91340270Sjhb return (0); 92340270Sjhb func = tc->tc_get_timecount; 93340270Sjhb mask = tc->tc_counter_mask; 94340270Sjhb freq = tc->tc_frequency; 95263008Sroyger now = 0; 96263008Sroyger end = freq * n / 1000000; 97263008Sroyger last = func(tc) & mask; 98263008Sroyger do { 99263008Sroyger cpu_spinwait(); 100263008Sroyger u = func(tc) & mask; 101263008Sroyger if (u < last) 102263008Sroyger now += mask - last + u + 1; 103263008Sroyger else 104263008Sroyger now += u - last; 105263008Sroyger last = u; 106263008Sroyger } while (now < end); 107263008Sroyger return (1); 108263008Sroyger} 109263008Sroyger 110263008Sroygervoid 111263008SroygerDELAY(int n) 112263008Sroyger{ 113263008Sroyger 114263008Sroyger if (delay_tc(n)) 115263008Sroyger return; 116263008Sroyger 117263008Sroyger init_ops.early_delay(n); 118263008Sroyger} 119340270Sjhb 120340270Sjhbvoid 121340270Sjhbcpu_lock_delay(void) 122340270Sjhb{ 123340270Sjhb 124340270Sjhb /* 125340270Sjhb * Use TSC to wait for a usec if present, otherwise fall back 126340270Sjhb * to reading from port 0x84. We can't call into timecounters 127340270Sjhb * for this delay since timecounters might use spin locks. 128340270Sjhb * 129340270Sjhb * Note that unlike delay_tc(), this uses the TSC even if it 130340270Sjhb * is not P-state invariant. For this function it is ok to 131340270Sjhb * wait even a few usecs. 132340270Sjhb */ 133340270Sjhb if (tsc_freq != 0) 134340270Sjhb delay_tsc(1); 135340270Sjhb else 136340270Sjhb inb(0x84); 137340270Sjhb} 138