clock.c revision 270296
1/*- 2 * Copyright (c) 2005, 2009-2011 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/10/sys/ia64/ia64/clock.c 270296 2014-08-21 19:51:07Z emaste $"); 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/bus.h> 33#include <sys/efi.h> 34#include <sys/interrupt.h> 35#include <sys/priority.h> 36#include <sys/proc.h> 37#include <sys/queue.h> 38#include <sys/sysctl.h> 39#include <sys/systm.h> 40#include <sys/timeet.h> 41#include <sys/timetc.h> 42#include <sys/pcpu.h> 43 44#include <machine/cpu.h> 45#include <machine/intr.h> 46#include <machine/intrcnt.h> 47#include <machine/md_var.h> 48#include <machine/smp.h> 49 50#define CLOCK_ET_OFF 0 51#define CLOCK_ET_PERIODIC 1 52#define CLOCK_ET_ONESHOT 2 53 54static struct eventtimer ia64_clock_et; 55static u_int ia64_clock_xiv; 56 57#ifndef SMP 58static timecounter_get_t ia64_get_timecount; 59 60static struct timecounter ia64_timecounter = { 61 ia64_get_timecount, /* get_timecount */ 62 0, /* no poll_pps */ 63 ~0u, /* counter_mask */ 64 0, /* frequency */ 65 "ITC" /* name */ 66}; 67 68static u_int 69ia64_get_timecount(struct timecounter* tc) 70{ 71 return ia64_get_itc(); 72} 73#endif 74 75static u_int 76ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf) 77{ 78 struct eventtimer *et; 79 struct trapframe *stf; 80 uint64_t itc, load; 81 uint32_t mode; 82 83 PCPU_INC(md.stats.pcs_nclks); 84 intrcnt[INTRCNT_CLOCK]++; 85 86 itc = ia64_get_itc(); 87 PCPU_SET(md.clock, itc); 88 89 mode = PCPU_GET(md.clock_mode); 90 if (mode == CLOCK_ET_PERIODIC) { 91 load = PCPU_GET(md.clock_load); 92 ia64_set_itm(itc + load); 93 } else 94 ia64_set_itv((1 << 16) | xiv); 95 96 ia64_set_eoi(0); 97 ia64_srlz_d(); 98 99 et = &ia64_clock_et; 100 if (et->et_active) { 101 stf = td->td_intr_frame; 102 td->td_intr_frame = tf; 103 et->et_event_cb(et, et->et_arg); 104 td->td_intr_frame = stf; 105 } 106 return (1); 107} 108 109/* 110 * Event timer start method. 111 */ 112static int 113ia64_clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 114{ 115 u_long itc, load; 116 register_t is; 117 118 if (period != 0) { 119 PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC); 120 load = (et->et_frequency * period) >> 32; 121 } else { 122 PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT); 123 load = 0; 124 } 125 126 PCPU_SET(md.clock_load, load); 127 128 if (first != 0) 129 load = (et->et_frequency * first) >> 32; 130 131 is = intr_disable(); 132 itc = ia64_get_itc(); 133 ia64_set_itm(itc + load); 134 ia64_set_itv(ia64_clock_xiv); 135 ia64_srlz_d(); 136 intr_restore(is); 137 return (0); 138} 139 140/* 141 * Event timer stop method. 142 */ 143static int 144ia64_clock_stop(struct eventtimer *et) 145{ 146 147 ia64_set_itv((1 << 16) | ia64_clock_xiv); 148 ia64_srlz_d(); 149 PCPU_SET(md.clock_mode, CLOCK_ET_OFF); 150 PCPU_SET(md.clock_load, 0); 151 return (0); 152} 153 154/* 155 * We call cpu_initclocks() on the APs as well. It allows us to 156 * group common initialization in the same function. 157 */ 158void 159cpu_initclocks() 160{ 161 162 ia64_clock_stop(NULL); 163 if (PCPU_GET(cpuid) == 0) 164 cpu_initclocks_bsp(); 165 else 166 cpu_initclocks_ap(); 167} 168 169static void 170clock_configure(void *dummy) 171{ 172 struct eventtimer *et; 173 u_long itc_freq; 174 175 ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, 176 ia64_ih_clock); 177 if (ia64_clock_xiv == 0) 178 panic("No XIV for clock interrupts"); 179 180 itc_freq = (u_long)ia64_itc_freq() * 1000000ul; 181 182 et = &ia64_clock_et; 183 et->et_name = "ITC"; 184 et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 185 et->et_quality = 1000; 186 et->et_frequency = itc_freq; 187 et->et_min_period = SBT_1S / (10 * hz); 188 et->et_max_period = (0xfffffffeul << 32) / itc_freq; 189 et->et_start = ia64_clock_start; 190 et->et_stop = ia64_clock_stop; 191 et->et_priv = NULL; 192 et_register(et); 193 194#ifndef SMP 195 ia64_timecounter.tc_frequency = itc_freq; 196 tc_init(&ia64_timecounter); 197#endif 198} 199SYSINIT(clkcfg, SI_SUB_CONFIGURE, SI_ORDER_SECOND, clock_configure, NULL); 200