1 1.59 thorpej /* $NetBSD: clock.c,v 1.59 2023/12/20 00:40:42 thorpej Exp $ */ 2 1.6 cgd 3 1.1 chopps /* 4 1.52 rmind * Copyright (c) 1988 University of Utah. 5 1.1 chopps * Copyright (c) 1982, 1990 The Regents of the University of California. 6 1.1 chopps * All rights reserved. 7 1.1 chopps * 8 1.1 chopps * This code is derived from software contributed to Berkeley by 9 1.1 chopps * the Systems Programming Group of the University of Utah Computer 10 1.1 chopps * Science Department. 11 1.1 chopps * 12 1.1 chopps * Redistribution and use in source and binary forms, with or without 13 1.1 chopps * modification, are permitted provided that the following conditions 14 1.1 chopps * are met: 15 1.1 chopps * 1. Redistributions of source code must retain the above copyright 16 1.1 chopps * notice, this list of conditions and the following disclaimer. 17 1.1 chopps * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 chopps * notice, this list of conditions and the following disclaimer in the 19 1.1 chopps * documentation and/or other materials provided with the distribution. 20 1.42 agc * 3. Neither the name of the University nor the names of its contributors 21 1.42 agc * may be used to endorse or promote products derived from this software 22 1.42 agc * without specific prior written permission. 23 1.42 agc * 24 1.42 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 1.42 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.42 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.42 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 1.42 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.42 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.42 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.42 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.42 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.42 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.42 agc * SUCH DAMAGE. 35 1.42 agc * 36 1.42 agc * from: Utah $Hdr: clock.c 1.18 91/01/21$ 37 1.42 agc * 38 1.42 agc * @(#)clock.c 7.6 (Berkeley) 5/7/91 39 1.42 agc */ 40 1.38 aymeric 41 1.38 aymeric #include <sys/cdefs.h> 42 1.59 thorpej __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.59 2023/12/20 00:40:42 thorpej Exp $"); 43 1.1 chopps 44 1.1 chopps #include <sys/param.h> 45 1.1 chopps #include <sys/kernel.h> 46 1.1 chopps #include <sys/device.h> 47 1.13 veego #include <sys/systm.h> 48 1.47 mhitch #include <sys/timetc.h> 49 1.1 chopps #include <machine/psl.h> 50 1.1 chopps #include <machine/cpu.h> 51 1.1 chopps #include <amiga/amiga/device.h> 52 1.1 chopps #include <amiga/amiga/custom.h> 53 1.1 chopps #include <amiga/amiga/cia.h> 54 1.14 is #ifdef DRACO 55 1.14 is #include <amiga/amiga/drcustom.h> 56 1.33 is #include <m68k/include/asm_single.h> 57 1.14 is #endif 58 1.1 chopps #include <amiga/dev/rtc.h> 59 1.8 chopps #include <amiga/dev/zbusvar.h> 60 1.1 chopps 61 1.1 chopps #if defined(PROF) && defined(PROFTIMER) 62 1.1 chopps #include <sys/PROF.h> 63 1.1 chopps #endif 64 1.1 chopps 65 1.1 chopps /* 66 1.1 chopps * Machine-dependent clock routines. 67 1.1 chopps * 68 1.1 chopps * Startrtclock restarts the real-time clock, which provides 69 1.1 chopps * hardclock interrupts to kern_clock.c. 70 1.1 chopps * 71 1.1 chopps * Inittodr initializes the time of day hardware which provides 72 1.1 chopps * date functions. 73 1.1 chopps * 74 1.1 chopps * Resettodr restores the time of day hardware after a time change. 75 1.1 chopps * 76 1.1 chopps * A note on the real-time clock: 77 1.47 mhitch * We actually load the clock with amiga_clk_interval-1 instead of amiga_clk_interval. 78 1.1 chopps * This is because the counter decrements to zero after N+1 enabled clock 79 1.1 chopps * periods where N is the value loaded into the counter. 80 1.1 chopps */ 81 1.1 chopps 82 1.53 matt int clockmatch(device_t, cfdata_t, void *); 83 1.53 matt void clockattach(device_t, device_t, void *); 84 1.37 aymeric void cpu_initclocks(void); 85 1.53 matt static void calibrate_delay(device_t); 86 1.51 phx 87 1.51 phx /* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz. 88 1.51 phx We're using a 100 Hz clock. */ 89 1.51 phx int amiga_clk_interval; 90 1.51 phx int eclockfreq; 91 1.51 phx struct CIA *clockcia; 92 1.51 phx 93 1.51 phx static u_int clk_getcounter(struct timecounter *); 94 1.51 phx 95 1.51 phx static struct timecounter clk_timecounter = { 96 1.57 rin .tc_get_timecount = clk_getcounter, 97 1.57 rin .tc_counter_mask = ~0u, 98 1.57 rin .tc_quality = 100, 99 1.51 phx }; 100 1.1 chopps 101 1.53 matt CFATTACH_DECL_NEW(clock, 0, 102 1.41 thorpej clockmatch, clockattach, NULL, NULL); 103 1.1 chopps 104 1.1 chopps int 105 1.54 chs clockmatch(device_t parent, cfdata_t cf, void *aux) 106 1.1 chopps { 107 1.54 chs if (matchname("clock", aux)) 108 1.1 chopps return(1); 109 1.1 chopps return(0); 110 1.1 chopps } 111 1.1 chopps 112 1.1 chopps /* 113 1.1 chopps * Start the real-time clock. 114 1.1 chopps */ 115 1.1 chopps void 116 1.54 chs clockattach(device_t parent, device_t self, void *aux) 117 1.1 chopps { 118 1.43 jmc const char *clockchip; 119 1.1 chopps unsigned short interval; 120 1.51 phx int chipfreq; 121 1.18 is #ifdef DRACO 122 1.18 is u_char dracorev; 123 1.18 is #endif 124 1.1 chopps 125 1.4 chopps if (eclockfreq == 0) 126 1.4 chopps eclockfreq = 715909; /* guess NTSC */ 127 1.37 aymeric 128 1.51 phx chipfreq = eclockfreq; 129 1.51 phx 130 1.14 is #ifdef DRACO 131 1.51 phx dracorev = is_draco(); 132 1.18 is if (dracorev >= 4) { 133 1.51 phx chipfreq = eclockfreq / 7; 134 1.18 is clockchip = "QuickLogic"; 135 1.18 is } else if (dracorev) { 136 1.14 is clockcia = (struct CIA *)CIAAbase; 137 1.18 is clockchip = "CIA A"; 138 1.37 aymeric } else 139 1.14 is #endif 140 1.14 is { 141 1.14 is clockcia = (struct CIA *)CIABbase; 142 1.18 is clockchip = "CIA B"; 143 1.14 is } 144 1.14 is 145 1.56 rin /* round nearest to mitigate clock drift for PAL */ 146 1.51 phx amiga_clk_interval = chipfreq / hz; 147 1.56 rin if (chipfreq % hz >= hz / 2) 148 1.56 rin amiga_clk_interval++; 149 1.47 mhitch 150 1.54 chs if (self != NULL) { /* real autoconfig? */ 151 1.23 is printf(": %s system hz %d hardware hz %d\n", clockchip, hz, 152 1.51 phx chipfreq); 153 1.51 phx 154 1.51 phx clk_timecounter.tc_name = clockchip; 155 1.51 phx clk_timecounter.tc_frequency = chipfreq; 156 1.47 mhitch tc_init(&clk_timecounter); 157 1.47 mhitch } 158 1.18 is 159 1.18 is #ifdef DRACO 160 1.18 is if (dracorev >= 4) { 161 1.37 aymeric /* 162 1.18 is * can't preload anything beforehand, timer is free_running; 163 1.18 is * but need this for delay calibration. 164 1.18 is */ 165 1.18 is 166 1.47 mhitch draco_ioct->io_timerlo = amiga_clk_interval & 0xff; 167 1.47 mhitch draco_ioct->io_timerhi = amiga_clk_interval >> 8; 168 1.18 is 169 1.54 chs calibrate_delay(self); 170 1.51 phx 171 1.18 is return; 172 1.18 is } 173 1.18 is #endif 174 1.1 chopps /* 175 1.37 aymeric * stop timer A 176 1.1 chopps */ 177 1.14 is clockcia->cra = clockcia->cra & 0xc0; 178 1.14 is clockcia->icr = 1 << 0; /* disable timer A interrupt */ 179 1.14 is interval = clockcia->icr; /* and make sure it's clear */ 180 1.1 chopps 181 1.1 chopps /* 182 1.1 chopps * load interval into registers. 183 1.1 chopps * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz 184 1.1 chopps */ 185 1.47 mhitch interval = amiga_clk_interval - 1; 186 1.1 chopps 187 1.1 chopps /* 188 1.1 chopps * order of setting is important ! 189 1.1 chopps */ 190 1.14 is clockcia->talo = interval & 0xff; 191 1.14 is clockcia->tahi = interval >> 8; 192 1.18 is /* 193 1.18 is * start timer A in continuous mode 194 1.18 is */ 195 1.18 is clockcia->cra = (clockcia->cra & 0xc0) | 1; 196 1.51 phx 197 1.54 chs calibrate_delay(self); 198 1.1 chopps } 199 1.1 chopps 200 1.1 chopps void 201 1.37 aymeric cpu_initclocks(void) 202 1.1 chopps { 203 1.20 mhitch #ifdef DRACO 204 1.18 is unsigned char dracorev; 205 1.18 is dracorev = is_draco(); 206 1.18 is if (dracorev >= 4) { 207 1.47 mhitch draco_ioct->io_timerlo = amiga_clk_interval & 0xFF; 208 1.47 mhitch draco_ioct->io_timerhi = amiga_clk_interval >> 8; 209 1.18 is draco_ioct->io_timerrst = 0; /* any value resets */ 210 1.33 is single_inst_bset_b(draco_ioct->io_status2, DRSTAT2_TMRINTENA); 211 1.18 is 212 1.18 is return; 213 1.18 is } 214 1.18 is #endif 215 1.1 chopps /* 216 1.1 chopps * enable interrupts for timer A 217 1.1 chopps */ 218 1.14 is clockcia->icr = (1<<7) | (1<<0); 219 1.1 chopps 220 1.1 chopps /* 221 1.1 chopps * start timer A in continuous shot mode 222 1.1 chopps */ 223 1.14 is clockcia->cra = (clockcia->cra & 0xc0) | 1; 224 1.37 aymeric 225 1.1 chopps /* 226 1.1 chopps * and globally enable interrupts for ciab 227 1.1 chopps */ 228 1.14 is #ifdef DRACO 229 1.18 is if (dracorev) /* we use cia a on DraCo */ 230 1.33 is single_inst_bset_b(*draco_intena, DRIRQ_INT2); 231 1.14 is else 232 1.14 is #endif 233 1.14 is custom.intena = INTF_SETCLR | INTF_EXTER; 234 1.18 is 235 1.1 chopps } 236 1.1 chopps 237 1.13 veego void 238 1.43 jmc setstatclockrate(int hertz) 239 1.1 chopps { 240 1.1 chopps } 241 1.1 chopps 242 1.1 chopps /* 243 1.51 phx * Returns ticks since last recorded clock "tick" 244 1.1 chopps * (i.e. clock interrupt). 245 1.1 chopps */ 246 1.47 mhitch static u_int 247 1.47 mhitch clk_gettick(void) 248 1.1 chopps { 249 1.18 is u_int interval; 250 1.1 chopps u_char hi, hi2, lo; 251 1.1 chopps 252 1.14 is #ifdef DRACO 253 1.18 is if (is_draco() >= 4) { 254 1.18 is hi2 = draco_ioct->io_chiprev; /* latch timer */ 255 1.18 is hi = draco_ioct->io_timerhi; 256 1.18 is lo = draco_ioct->io_timerlo; 257 1.18 is interval = ((hi<<8) | lo); 258 1.47 mhitch if (interval > amiga_clk_interval) /* timer underflow */ 259 1.47 mhitch interval = 65536 + amiga_clk_interval - interval; 260 1.18 is else 261 1.47 mhitch interval = amiga_clk_interval - interval; 262 1.1 chopps 263 1.18 is } else 264 1.14 is #endif 265 1.18 is { 266 1.18 is hi = clockcia->tahi; 267 1.18 is lo = clockcia->talo; 268 1.18 is hi2 = clockcia->tahi; 269 1.18 is if (hi != hi2) { 270 1.18 is lo = clockcia->talo; 271 1.18 is hi = hi2; 272 1.18 is } 273 1.1 chopps 274 1.47 mhitch interval = (amiga_clk_interval - 1) - ((hi<<8) | lo); 275 1.37 aymeric 276 1.1 chopps /* 277 1.18 is * should read ICR and if there's an int pending, adjust 278 1.18 is * interval. However, since reading ICR clears the interrupt, 279 1.18 is * we'd lose a hardclock int, and this is not tolerable. 280 1.1 chopps */ 281 1.1 chopps } 282 1.1 chopps 283 1.47 mhitch return interval; 284 1.47 mhitch } 285 1.47 mhitch 286 1.47 mhitch static u_int 287 1.47 mhitch clk_getcounter(struct timecounter *tc) 288 1.47 mhitch { 289 1.51 phx static int prev_hardclock; 290 1.51 phx static u_int prev_counter; 291 1.51 phx int cur_hardclock; 292 1.51 phx u_int counter; 293 1.47 mhitch 294 1.47 mhitch do { 295 1.58 maxv cur_hardclock = getticks(); 296 1.51 phx counter = clk_gettick(); 297 1.58 maxv } while (cur_hardclock != getticks()); 298 1.47 mhitch 299 1.50 phx /* 300 1.50 phx * Handle the situation of a wrapped interval counter, while 301 1.50 phx * the hardclock() interrupt was not yet executed to update 302 1.50 phx * hardclock_ticks. 303 1.50 phx */ 304 1.51 phx if (cur_hardclock < prev_hardclock) 305 1.51 phx cur_hardclock = prev_hardclock; 306 1.51 phx if (counter < prev_counter && cur_hardclock == prev_hardclock) 307 1.51 phx cur_hardclock++; 308 1.51 phx 309 1.51 phx prev_hardclock = cur_hardclock; 310 1.51 phx prev_counter = counter; 311 1.51 phx 312 1.51 phx return cur_hardclock * amiga_clk_interval + counter; 313 1.51 phx } 314 1.51 phx 315 1.51 phx /* 316 1.51 phx * Calibrate delay loop. 317 1.51 phx * We use two iterations because we don't have enough bits to do a factor of 318 1.51 phx * 8 with better than 1%. 319 1.51 phx * 320 1.51 phx * XXX Note that we MUST stay below 1 tick if using clk_gettick(), even for 321 1.51 phx * underestimated values of delaydivisor. 322 1.51 phx * 323 1.51 phx * XXX the "ns" below is only correct for a shift of 10 bits, and even then 324 1.51 phx * off by 2.4% 325 1.51 phx */ 326 1.51 phx static void 327 1.54 chs calibrate_delay(device_t self) 328 1.51 phx { 329 1.51 phx unsigned long t1, t2; 330 1.51 phx extern u_int32_t delaydivisor; 331 1.51 phx /* XXX this should be defined elsewhere */ 332 1.50 phx 333 1.54 chs if (self) 334 1.51 phx printf("Calibrating delay loop... "); 335 1.51 phx 336 1.51 phx do { 337 1.51 phx t1 = clk_gettick(); 338 1.51 phx delay(1024); 339 1.51 phx t2 = clk_gettick(); 340 1.51 phx } while (t2 <= t1); 341 1.51 phx t2 = ((t2 - t1) * 1000000) / (amiga_clk_interval * hz); 342 1.51 phx delaydivisor = (delaydivisor * t2 + 1023) >> 10; 343 1.51 phx #ifdef DEBUG 344 1.54 chs if (self) 345 1.51 phx printf("\ndiff %ld us, new divisor %u/1024 us\n", t2, 346 1.51 phx delaydivisor); 347 1.51 phx do { 348 1.51 phx t1 = clk_gettick(); 349 1.51 phx delay(1024); 350 1.51 phx t2 = clk_gettick(); 351 1.51 phx } while (t2 <= t1); 352 1.51 phx t2 = ((t2 - t1) * 1000000) / (amiga_clk_interval * hz); 353 1.51 phx delaydivisor = (delaydivisor * t2 + 1023) >> 10; 354 1.54 chs if (self) 355 1.51 phx printf("diff %ld us, new divisor %u/1024 us\n", t2, 356 1.51 phx delaydivisor); 357 1.51 phx #endif 358 1.51 phx do { 359 1.51 phx t1 = clk_gettick(); 360 1.51 phx delay(1024); 361 1.51 phx t2 = clk_gettick(); 362 1.51 phx } while (t2 <= t1); 363 1.51 phx t2 = ((t2 - t1) * 1000000) / (amiga_clk_interval * hz); 364 1.51 phx delaydivisor = (delaydivisor * t2 + 1023) >> 10; 365 1.51 phx #ifdef DEBUG 366 1.54 chs if (self) 367 1.51 phx printf("diff %ld us, new divisor ", t2); 368 1.51 phx #endif 369 1.54 chs if (self) 370 1.51 phx printf("%u/1024 us\n", delaydivisor); 371 1.1 chopps } 372 1.1 chopps 373 1.1 chopps #if notyet 374 1.1 chopps 375 1.1 chopps /* implement this later. I'd suggest using both timers in CIA-A, they're 376 1.1 chopps not yet used. */ 377 1.1 chopps 378 1.1 chopps #include "clock.h" 379 1.1 chopps #if NCLOCK > 0 380 1.1 chopps /* 381 1.1 chopps * /dev/clock: mappable high resolution timer. 382 1.1 chopps * 383 1.1 chopps * This code implements a 32-bit recycling counter (with a 4 usec period) 384 1.1 chopps * using timers 2 & 3 on the 6840 clock chip. The counter can be mapped 385 1.1 chopps * RO into a user's address space to achieve low overhead (no system calls), 386 1.1 chopps * high-precision timing. 387 1.1 chopps * 388 1.1 chopps * Note that timer 3 is also used for the high precision profiling timer 389 1.1 chopps * (PROFTIMER code above). Care should be taken when both uses are 390 1.1 chopps * configured as only a token effort is made to avoid conflicting use. 391 1.1 chopps */ 392 1.1 chopps #include <sys/proc.h> 393 1.1 chopps #include <sys/resourcevar.h> 394 1.1 chopps #include <sys/ioctl.h> 395 1.35 mrg #include <uvm/uvm_extern.h> 396 1.1 chopps #include <amiga/amiga/clockioctl.h> 397 1.1 chopps #include <sys/specdev.h> 398 1.1 chopps #include <sys/vnode.h> 399 1.1 chopps #include <sys/mman.h> 400 1.1 chopps 401 1.1 chopps int clockon = 0; /* non-zero if high-res timer enabled */ 402 1.1 chopps #ifdef PROFTIMER 403 1.1 chopps int profprocs = 0; /* # of procs using profiling timer */ 404 1.1 chopps #endif 405 1.1 chopps #ifdef DEBUG 406 1.1 chopps int clockdebug = 0; 407 1.1 chopps #endif 408 1.1 chopps 409 1.1 chopps /*ARGSUSED*/ 410 1.37 aymeric int 411 1.37 aymeric clockopen(dev_t dev, int flags) 412 1.1 chopps { 413 1.1 chopps #ifdef PROFTIMER 414 1.1 chopps #ifdef PROF 415 1.1 chopps /* 416 1.1 chopps * Kernel profiling enabled, give up. 417 1.1 chopps */ 418 1.1 chopps if (profiling) 419 1.1 chopps return(EBUSY); 420 1.1 chopps #endif 421 1.1 chopps /* 422 1.1 chopps * If any user processes are profiling, give up. 423 1.1 chopps */ 424 1.1 chopps if (profprocs) 425 1.1 chopps return(EBUSY); 426 1.1 chopps #endif 427 1.1 chopps if (!clockon) { 428 1.1 chopps startclock(); 429 1.1 chopps clockon++; 430 1.1 chopps } 431 1.1 chopps return(0); 432 1.1 chopps } 433 1.1 chopps 434 1.1 chopps /*ARGSUSED*/ 435 1.37 aymeric int 436 1.37 aymeric clockclose(dev_t dev, int flags) 437 1.1 chopps { 438 1.46 christos (void) clockunmmap(dev, (void *)0, curproc); /* XXX */ 439 1.1 chopps stopclock(); 440 1.1 chopps clockon = 0; 441 1.1 chopps return(0); 442 1.1 chopps } 443 1.1 chopps 444 1.1 chopps /*ARGSUSED*/ 445 1.37 aymeric int 446 1.46 christos clockioctl(dev_t dev, u_long cmd, void *data, int flag, struct proc *p) 447 1.1 chopps { 448 1.1 chopps int error = 0; 449 1.37 aymeric 450 1.1 chopps switch (cmd) { 451 1.1 chopps 452 1.1 chopps case CLOCKMAP: 453 1.46 christos error = clockmmap(dev, (void **)data, p); 454 1.1 chopps break; 455 1.1 chopps 456 1.1 chopps case CLOCKUNMAP: 457 1.46 christos error = clockunmmap(dev, *(void **)data, p); 458 1.1 chopps break; 459 1.1 chopps 460 1.1 chopps case CLOCKGETRES: 461 1.1 chopps *(int *)data = CLK_RESOLUTION; 462 1.1 chopps break; 463 1.1 chopps 464 1.1 chopps default: 465 1.1 chopps error = EINVAL; 466 1.1 chopps break; 467 1.1 chopps } 468 1.1 chopps return(error); 469 1.1 chopps } 470 1.1 chopps 471 1.1 chopps /*ARGSUSED*/ 472 1.37 aymeric void 473 1.37 aymeric clockmap(dev_t dev, int off, int prot) 474 1.1 chopps { 475 1.55 phx return MD_BTOP(off + (INTIOBASE+CLKBASE+CLKSR-1)); 476 1.1 chopps } 477 1.1 chopps 478 1.37 aymeric int 479 1.46 christos clockmmap(dev_t dev, void **addrp, struct proc *p) 480 1.1 chopps { 481 1.1 chopps int error; 482 1.1 chopps struct vnode vn; 483 1.1 chopps struct specinfo si; 484 1.1 chopps int flags; 485 1.1 chopps 486 1.1 chopps flags = MAP_FILE|MAP_SHARED; 487 1.1 chopps if (*addrp) 488 1.1 chopps flags |= MAP_FIXED; 489 1.1 chopps else 490 1.46 christos *addrp = (void *)0x1000000; /* XXX */ 491 1.1 chopps vn.v_type = VCHR; /* XXX */ 492 1.1 chopps vn.v_specinfo = &si; /* XXX */ 493 1.1 chopps vn.v_rdev = dev; /* XXX */ 494 1.1 chopps error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 495 1.46 christos PAGE_SIZE, VM_PROT_ALL, flags, (void *)&vn, 0); 496 1.1 chopps return(error); 497 1.1 chopps } 498 1.1 chopps 499 1.37 aymeric int 500 1.46 christos clockunmmap(dev_t dev, void *addr, struct proc *p) 501 1.1 chopps { 502 1.1 chopps int rv; 503 1.1 chopps 504 1.1 chopps if (addr == 0) 505 1.1 chopps return(EINVAL); /* XXX: how do we deal with this? */ 506 1.36 chs uvm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, PAGE_SIZE); 507 1.36 chs return 0; 508 1.1 chopps } 509 1.1 chopps 510 1.37 aymeric void 511 1.37 aymeric startclock(void) 512 1.1 chopps { 513 1.1 chopps register struct clkreg *clk = (struct clkreg *)clkstd[0]; 514 1.1 chopps 515 1.1 chopps clk->clk_msb2 = -1; clk->clk_lsb2 = -1; 516 1.1 chopps clk->clk_msb3 = -1; clk->clk_lsb3 = -1; 517 1.1 chopps 518 1.1 chopps clk->clk_cr2 = CLK_CR3; 519 1.1 chopps clk->clk_cr3 = CLK_OENAB|CLK_8BIT; 520 1.1 chopps clk->clk_cr2 = CLK_CR1; 521 1.1 chopps clk->clk_cr1 = CLK_IENAB; 522 1.1 chopps } 523 1.1 chopps 524 1.37 aymeric void 525 1.37 aymeric stopclock(void) 526 1.1 chopps { 527 1.1 chopps register struct clkreg *clk = (struct clkreg *)clkstd[0]; 528 1.1 chopps 529 1.1 chopps clk->clk_cr2 = CLK_CR3; 530 1.1 chopps clk->clk_cr3 = 0; 531 1.1 chopps clk->clk_cr2 = CLK_CR1; 532 1.1 chopps clk->clk_cr1 = CLK_IENAB; 533 1.1 chopps } 534 1.1 chopps #endif 535 1.1 chopps 536 1.1 chopps #endif 537 1.1 chopps 538 1.1 chopps 539 1.1 chopps #ifdef PROFTIMER 540 1.1 chopps /* 541 1.1 chopps * This code allows the amiga kernel to use one of the extra timers on 542 1.1 chopps * the clock chip for profiling, instead of the regular system timer. 543 1.1 chopps * The advantage of this is that the profiling timer can be turned up to 544 1.1 chopps * a higher interrupt rate, giving finer resolution timing. The profclock 545 1.1 chopps * routine is called from the lev6intr in locore, and is a specialized 546 1.1 chopps * routine that calls addupc. The overhead then is far less than if 547 1.1 chopps * hardclock/softclock was called. Further, the context switch code in 548 1.1 chopps * locore has been changed to turn the profile clock on/off when switching 549 1.1 chopps * into/out of a process that is profiling (startprofclock/stopprofclock). 550 1.1 chopps * This reduces the impact of the profiling clock on other users, and might 551 1.37 aymeric * possibly increase the accuracy of the profiling. 552 1.1 chopps */ 553 1.1 chopps int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ 554 1.1 chopps int profscale = 0; /* Scale factor from sys clock to prof clock */ 555 1.1 chopps char profon = 0; /* Is profiling clock on? */ 556 1.1 chopps 557 1.1 chopps /* profon values - do not change, locore.s assumes these values */ 558 1.1 chopps #define PRF_NONE 0x00 559 1.1 chopps #define PRF_USER 0x01 560 1.1 chopps #define PRF_KERNEL 0x80 561 1.1 chopps 562 1.37 aymeric void 563 1.37 aymeric initprofclock(void) 564 1.1 chopps { 565 1.1 chopps #if NCLOCK > 0 566 1.1 chopps struct proc *p = curproc; /* XXX */ 567 1.1 chopps 568 1.1 chopps /* 569 1.1 chopps * If the high-res timer is running, force profiling off. 570 1.1 chopps * Unfortunately, this gets reflected back to the user not as 571 1.1 chopps * an error but as a lack of results. 572 1.1 chopps */ 573 1.1 chopps if (clockon) { 574 1.1 chopps p->p_stats->p_prof.pr_scale = 0; 575 1.1 chopps return; 576 1.1 chopps } 577 1.1 chopps /* 578 1.1 chopps * Keep track of the number of user processes that are profiling 579 1.1 chopps * by checking the scale value. 580 1.1 chopps * 581 1.1 chopps * XXX: this all assumes that the profiling code is well behaved; 582 1.1 chopps * i.e. profil() is called once per process with pcscale non-zero 583 1.1 chopps * to turn it on, and once with pcscale zero to turn it off. 584 1.1 chopps * Also assumes you don't do any forks or execs. Oh well, there 585 1.1 chopps * is always adb... 586 1.1 chopps */ 587 1.1 chopps if (p->p_stats->p_prof.pr_scale) 588 1.1 chopps profprocs++; 589 1.1 chopps else 590 1.1 chopps profprocs--; 591 1.1 chopps #endif 592 1.1 chopps /* 593 1.1 chopps * The profile interrupt interval must be an even divisor 594 1.47 mhitch * of the amiga_clk_interval so that scaling from a system clock 595 1.1 chopps * tick to a profile clock tick is possible using integer math. 596 1.1 chopps */ 597 1.47 mhitch if (profint > amiga_clk_interval || (amiga_clk_interval % profint) != 0) 598 1.47 mhitch profint = amiga_clk_interval; 599 1.47 mhitch profscale = amiga_clk_interval / profint; 600 1.1 chopps } 601 1.1 chopps 602 1.37 aymeric void 603 1.37 aymeric startprofclock(void) 604 1.1 chopps { 605 1.1 chopps unsigned short interval; 606 1.1 chopps 607 1.1 chopps /* stop timer B */ 608 1.14 is clockcia->crb = clockcia->crb & 0xc0; 609 1.1 chopps 610 1.1 chopps /* load interval into registers. 611 1.1 chopps the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */ 612 1.1 chopps 613 1.1 chopps interval = profint - 1; 614 1.1 chopps 615 1.1 chopps /* order of setting is important ! */ 616 1.14 is clockcia->tblo = interval & 0xff; 617 1.14 is clockcia->tbhi = interval >> 8; 618 1.1 chopps 619 1.1 chopps /* enable interrupts for timer B */ 620 1.14 is clockcia->icr = (1<<7) | (1<<1); 621 1.1 chopps 622 1.1 chopps /* start timer B in continuous shot mode */ 623 1.14 is clockcia->crb = (clockcia->crb & 0xc0) | 1; 624 1.1 chopps } 625 1.1 chopps 626 1.37 aymeric void 627 1.37 aymeric stopprofclock(void) 628 1.1 chopps { 629 1.1 chopps /* stop timer B */ 630 1.14 is clockcia->crb = clockcia->crb & 0xc0; 631 1.1 chopps } 632 1.1 chopps 633 1.1 chopps #ifdef PROF 634 1.1 chopps /* 635 1.1 chopps * profclock() is expanded in line in lev6intr() unless profiling kernel. 636 1.1 chopps * Assumes it is called with clock interrupts blocked. 637 1.1 chopps */ 638 1.37 aymeric void 639 1.46 christos profclock(void *pc, int ps) 640 1.1 chopps { 641 1.1 chopps /* 642 1.1 chopps * Came from user mode. 643 1.1 chopps * If this process is being profiled record the tick. 644 1.1 chopps */ 645 1.1 chopps if (USERMODE(ps)) { 646 1.1 chopps if (p->p_stats.p_prof.pr_scale) 647 1.1 chopps addupc(pc, &curproc->p_stats.p_prof, 1); 648 1.1 chopps } 649 1.1 chopps /* 650 1.1 chopps * Came from kernel (supervisor) mode. 651 1.1 chopps * If we are profiling the kernel, record the tick. 652 1.1 chopps */ 653 1.1 chopps else if (profiling < 2) { 654 1.1 chopps register int s = pc - s_lowpc; 655 1.1 chopps 656 1.1 chopps if (s < s_textsize) 657 1.1 chopps kcount[s / (HISTFRACTION * sizeof (*kcount))]++; 658 1.1 chopps } 659 1.1 chopps /* 660 1.1 chopps * Kernel profiling was on but has been disabled. 661 1.1 chopps * Mark as no longer profiling kernel and if all profiling done, 662 1.1 chopps * disable the clock. 663 1.1 chopps */ 664 1.1 chopps if (profiling && (profon & PRF_KERNEL)) { 665 1.1 chopps profon &= ~PRF_KERNEL; 666 1.1 chopps if (profon == PRF_NONE) 667 1.1 chopps stopprofclock(); 668 1.1 chopps } 669 1.1 chopps } 670 1.1 chopps #endif 671 1.1 chopps #endif 672