| 1 | /* $Id: timer.c,v 1.1.1.1 2003/07/02 13:57:04 eleph Exp $ */ | 
|---|
| 2 | /* | 
|---|
| 3 | * OS/2 implementation of Linux timer kernel functions | 
|---|
| 4 | * | 
|---|
| 5 | * (C) 2000-2002 InnoTek Systemberatung GmbH | 
|---|
| 6 | * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl) | 
|---|
| 7 | * | 
|---|
| 8 | * This program is free software; you can redistribute it and/or | 
|---|
| 9 | * modify it under the terms of the GNU General Public License as | 
|---|
| 10 | * published by the Free Software Foundation; either version 2 of | 
|---|
| 11 | * the License, or (at your option) any later version. | 
|---|
| 12 | * | 
|---|
| 13 | * This program is distributed in the hope that it will be useful, | 
|---|
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 16 | * GNU General Public License for more details. | 
|---|
| 17 | * | 
|---|
| 18 | * You should have received a copy of the GNU General Public | 
|---|
| 19 | * License along with this program; if not, write to the Free | 
|---|
| 20 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, | 
|---|
| 21 | * USA. | 
|---|
| 22 | * | 
|---|
| 23 | */ | 
|---|
| 24 |  | 
|---|
| 25 | #include "linux.h" | 
|---|
| 26 | #include <linux/init.h> | 
|---|
| 27 | #include <linux/poll.h> | 
|---|
| 28 | #include <asm/uaccess.h> | 
|---|
| 29 | #include <asm/hardirq.h> | 
|---|
| 30 | #include <asm/io.h> | 
|---|
| 31 | #include <linux/time.h> | 
|---|
| 32 | #include <linux/math64.h> | 
|---|
| 33 | #include <linux/clocksource.h> | 
|---|
| 34 |  | 
|---|
| 35 | #define LINUX | 
|---|
| 36 | #include <ossidc.h> | 
|---|
| 37 | #include <irqos2.h> | 
|---|
| 38 | #include <dbgos2.h> | 
|---|
| 39 |  | 
|---|
| 40 | #pragma pack(1) | 
|---|
| 41 | #include     "infoseg.h" | 
|---|
| 42 | #pragma pack() | 
|---|
| 43 | extern PVOID  KernSISData; | 
|---|
| 44 | #define KernSISData             ((struct InfoSegGDT *)&KernSISData) | 
|---|
| 45 |  | 
|---|
| 46 | static   long          jiffiems    = 1000/HZ; | 
|---|
| 47 | static   long          lasttime    = 0; | 
|---|
| 48 | unsigned long volatile jiffies     = 0; | 
|---|
| 49 |  | 
|---|
| 50 | //****************************************************************************** | 
|---|
| 51 | //Timer handler that is called on each timer tick (32 times/second) | 
|---|
| 52 | //****************************************************************************** | 
|---|
| 53 | void ALSA_TIMER() | 
|---|
| 54 | { | 
|---|
| 55 | long delta, newtime, remainder; | 
|---|
| 56 |  | 
|---|
| 57 | newtime    = KernSISData->SIS_MsCount; | 
|---|
| 58 | delta      = newtime - lasttime; | 
|---|
| 59 |  | 
|---|
| 60 | jiffies   += delta/jiffiems; | 
|---|
| 61 | remainder  = delta%jiffiems; | 
|---|
| 62 |  | 
|---|
| 63 | lasttime   = newtime - remainder; | 
|---|
| 64 | } | 
|---|
| 65 | //****************************************************************************** | 
|---|
| 66 | //timeout is in 'jiffies', linux talk for units of 1000/HZ ms | 
|---|
| 67 | //****************************************************************************** | 
|---|
| 68 | signed long schedule_timeout(signed long timeout) | 
|---|
| 69 | { | 
|---|
| 70 | dprintf2(("schedule_timeout %d jiffies %x", timeout, jiffies)); | 
|---|
| 71 | mdelay(timeout*jiffiems); | 
|---|
| 72 | return 0; | 
|---|
| 73 | } | 
|---|
| 74 | //****************************************************************************** | 
|---|
| 75 | //iodelay is in 500ns units | 
|---|
| 76 | void iodelay32(unsigned long); | 
|---|
| 77 | #pragma aux iodelay32 parm nomemory [ecx] modify nomemory exact [eax ecx]; | 
|---|
| 78 | //****************************************************************************** | 
|---|
| 79 | //microsecond delay | 
|---|
| 80 | //****************************************************************************** | 
|---|
| 81 | void __udelay(unsigned long usecs) | 
|---|
| 82 | { | 
|---|
| 83 | if(usecs == 0) { | 
|---|
| 84 | DebugInt3(); | 
|---|
| 85 | usecs = 1; | 
|---|
| 86 | } | 
|---|
| 87 | iodelay32(usecs*2); | 
|---|
| 88 | } | 
|---|
| 89 | //****************************************************************************** | 
|---|
| 90 | //millisecond delay | 
|---|
| 91 | //****************************************************************************** | 
|---|
| 92 | void mdelay(unsigned long msecs) | 
|---|
| 93 | { | 
|---|
| 94 | if(msecs == 0) { | 
|---|
| 95 | DebugInt3(); | 
|---|
| 96 | msecs = 1; | 
|---|
| 97 | } | 
|---|
| 98 | iodelay32(msecs*2*1000); | 
|---|
| 99 | } | 
|---|
| 100 | //****************************************************************************** | 
|---|
| 101 | //****************************************************************************** | 
|---|
| 102 | void do_gettimeofday(struct timeval *tv) | 
|---|
| 103 | { | 
|---|
| 104 | #if 0 | 
|---|
| 105 | tv->tv_sec  = 0; //KernSISData->SIS_BigTime; | 
|---|
| 106 | tv->tv_usec = KernSISData->SIS_MsCount * 1000; | 
|---|
| 107 | #else /* r.ihle patch */ | 
|---|
| 108 | unsigned u = KernSISData->SIS_MsCount; | 
|---|
| 109 | tv->tv_sec  = u / 1000; | 
|---|
| 110 | tv->tv_usec = (u % 1000) * 1000; | 
|---|
| 111 | #endif | 
|---|
| 112 | } | 
|---|
| 113 | //****************************************************************************** | 
|---|
| 114 | //****************************************************************************** | 
|---|
| 115 | void add_timer(struct timer_list * timer) | 
|---|
| 116 | { | 
|---|
| 117 |  | 
|---|
| 118 | } | 
|---|
| 119 | //****************************************************************************** | 
|---|
| 120 | //****************************************************************************** | 
|---|
| 121 | int  del_timer(struct timer_list * timer) | 
|---|
| 122 | { | 
|---|
| 123 | return 0; | 
|---|
| 124 | } | 
|---|
| 125 | //****************************************************************************** | 
|---|
| 126 | /* | 
|---|
| 127 | * mod_timer is a more efficient way to update the expire field of an | 
|---|
| 128 | * active timer (if the timer is inactive it will be activated) | 
|---|
| 129 | * mod_timer(a,b) is equivalent to del_timer(a); a->expires = b; add_timer(a) | 
|---|
| 130 | */ | 
|---|
| 131 | void mod_timer(struct timer_list *timer, unsigned long expires) | 
|---|
| 132 | { | 
|---|
| 133 |  | 
|---|
| 134 | } | 
|---|
| 135 | //****************************************************************************** | 
|---|
| 136 | //****************************************************************************** | 
|---|
| 137 | #include <linux/delay.h> | 
|---|
| 138 | void msleep(unsigned int msecs) | 
|---|
| 139 | { | 
|---|
| 140 | unsigned long timeout = ((msecs) * HZ + 999) / 1000; | 
|---|
| 141 |  | 
|---|
| 142 | while (timeout) { | 
|---|
| 143 | set_current_state(TASK_UNINTERRUPTIBLE); | 
|---|
| 144 | timeout = schedule_timeout(timeout); | 
|---|
| 145 | } | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | //****************************************************************************** | 
|---|
| 149 | //****************************************************************************** | 
|---|
| 150 |  | 
|---|
| 151 | /** | 
|---|
| 152 | * ns_to_timespec - Convert nanoseconds to timespec | 
|---|
| 153 | * @nsec:       the nanoseconds value to be converted | 
|---|
| 154 | * | 
|---|
| 155 | * Returns the timespec representation of the nsec parameter. | 
|---|
| 156 | */ | 
|---|
| 157 | struct timespec ns_to_timespec(const s64 nsec) | 
|---|
| 158 | { | 
|---|
| 159 | struct timespec ts; | 
|---|
| 160 | s32 rem; | 
|---|
| 161 |  | 
|---|
| 162 | if (!nsec) { | 
|---|
| 163 | ts.tv_sec = 0; | 
|---|
| 164 | ts.tv_nsec = 0; | 
|---|
| 165 | return ts; | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); | 
|---|
| 169 | if (unlikely(rem < 0)) { | 
|---|
| 170 | ts.tv_sec--; | 
|---|
| 171 | rem += NSEC_PER_SEC; | 
|---|
| 172 | } | 
|---|
| 173 | ts.tv_nsec = rem; | 
|---|
| 174 |  | 
|---|
| 175 | return ts; | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 |  | 
|---|
| 179 | //****************************************************************************** | 
|---|
| 180 | //****************************************************************************** | 
|---|
| 181 |  | 
|---|
| 182 | /** | 
|---|
| 183 | * ns_to_timespec - Convert nanoseconds to timespec | 
|---|
| 184 | * @nsec:       the nanoseconds value to be converted | 
|---|
| 185 | * | 
|---|
| 186 | * Returns the timespec representation of the nsec parameter. | 
|---|
| 187 | */ | 
|---|
| 188 | struct timespec64 ns_to_timespec64(const s64 nsec) | 
|---|
| 189 | { | 
|---|
| 190 | struct timespec64 ts; | 
|---|
| 191 | s32 rem; | 
|---|
| 192 |  | 
|---|
| 193 | if (!nsec) { | 
|---|
| 194 | ts.tv_sec = 0; | 
|---|
| 195 | ts.tv_nsec = 0; | 
|---|
| 196 | return ts; | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); | 
|---|
| 200 | if (unlikely(rem < 0)) { | 
|---|
| 201 | ts.tv_sec--; | 
|---|
| 202 | rem += NSEC_PER_SEC; | 
|---|
| 203 | } | 
|---|
| 204 | ts.tv_nsec = rem; | 
|---|
| 205 |  | 
|---|
| 206 | return ts; | 
|---|
| 207 | } | 
|---|
| 208 | //****************************************************************************** | 
|---|
| 209 | //****************************************************************************** | 
|---|
| 210 |  | 
|---|
| 211 | void timecounter_init(struct timecounter *tc, | 
|---|
| 212 | const struct cyclecounter *cc, | 
|---|
| 213 | u64 start_tstamp) | 
|---|
| 214 | { | 
|---|
| 215 | tc->cc = cc; | 
|---|
| 216 | tc->cycle_last = cc->read(cc); | 
|---|
| 217 | tc->nsec = start_tstamp; | 
|---|
| 218 | } | 
|---|
| 219 |  | 
|---|
| 220 | /** | 
|---|
| 221 | * timecounter_read_delta - get nanoseconds since last call of this function | 
|---|
| 222 | * @tc:         Pointer to time counter | 
|---|
| 223 | * | 
|---|
| 224 | * When the underlying cycle counter runs over, this will be handled | 
|---|
| 225 | * correctly as long as it does not run over more than once between | 
|---|
| 226 | * calls. | 
|---|
| 227 | * | 
|---|
| 228 | * The first call to this function for a new time counter initializes | 
|---|
| 229 | * the time tracking and returns an undefined result. | 
|---|
| 230 | */ | 
|---|
| 231 | static u64 timecounter_read_delta(struct timecounter *tc) | 
|---|
| 232 | { | 
|---|
| 233 | cycle_t cycle_now, cycle_delta; | 
|---|
| 234 | u64 ns_offset; | 
|---|
| 235 |  | 
|---|
| 236 | /* read cycle counter: */ | 
|---|
| 237 | cycle_now = tc->cc->read(tc->cc); | 
|---|
| 238 |  | 
|---|
| 239 | /* calculate the delta since the last timecounter_read_delta(): */ | 
|---|
| 240 | cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; | 
|---|
| 241 |  | 
|---|
| 242 | /* convert to nanoseconds: */ | 
|---|
| 243 | ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta); | 
|---|
| 244 |  | 
|---|
| 245 | /* update time stamp of timecounter_read_delta() call: */ | 
|---|
| 246 | tc->cycle_last = cycle_now; | 
|---|
| 247 |  | 
|---|
| 248 | return ns_offset; | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | u64 timecounter_read(struct timecounter *tc) | 
|---|
| 252 | { | 
|---|
| 253 | u64 nsec; | 
|---|
| 254 |  | 
|---|
| 255 | /* increment time by nanoseconds since last call */ | 
|---|
| 256 | nsec = timecounter_read_delta(tc); | 
|---|
| 257 | nsec += tc->nsec; | 
|---|
| 258 | tc->nsec = nsec; | 
|---|
| 259 |  | 
|---|
| 260 | return nsec; | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | /** | 
|---|
| 264 | * set_normalized_timespec - set timespec sec and nsec parts and normalize | 
|---|
| 265 | * | 
|---|
| 266 | * @ts:         pointer to timespec variable to be set | 
|---|
| 267 | * @sec:        seconds to set | 
|---|
| 268 | * @nsec:       nanoseconds to set | 
|---|
| 269 | * | 
|---|
| 270 | * Set seconds and nanoseconds field of a timespec variable and | 
|---|
| 271 | * normalize to the timespec storage format | 
|---|
| 272 | * | 
|---|
| 273 | * Note: The tv_nsec part is always in the range of | 
|---|
| 274 | *      0 <= tv_nsec < NSEC_PER_SEC | 
|---|
| 275 | * For negative values only the tv_sec field is negative ! | 
|---|
| 276 | */ | 
|---|
| 277 | void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec) | 
|---|
| 278 | { | 
|---|
| 279 | while (nsec >= NSEC_PER_SEC) { | 
|---|
| 280 | /* | 
|---|
| 281 | * The following asm() prevents the compiler from | 
|---|
| 282 | * optimising this loop into a modulo operation. See | 
|---|
| 283 | * also __iter_div_u64_rem() in include/linux/time.h | 
|---|
| 284 | */ | 
|---|
| 285 | //              asm("" : "+rm"(nsec)); | 
|---|
| 286 | nsec -= NSEC_PER_SEC; | 
|---|
| 287 | ++sec; | 
|---|
| 288 | } | 
|---|
| 289 | while (nsec < 0) { | 
|---|
| 290 | //              asm("" : "+rm"(nsec)); | 
|---|
| 291 | nsec += NSEC_PER_SEC; | 
|---|
| 292 | --sec; | 
|---|
| 293 | } | 
|---|
| 294 | ts->tv_sec = sec; | 
|---|
| 295 | ts->tv_nsec = nsec; | 
|---|
| 296 | } | 
|---|