time.c (2cfa7660dbf94a61b9d43edaa84be454f9dc25fc) | time.c (42f77542f4a1c104bb6fbba2e18e04e84415a96b) |
---|---|
1/* 2 * Copyright 2001 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * Copyright (c) 2003, 2004 Maciej W. Rozycki 5 * 6 * Common time service routines for MIPS machines. See 7 * Documentation/mips/time.README. 8 * --- 67 unchanged lines hidden (view full) --- 76 * Null high precision timer functions for systems lacking one. 77 */ 78static cycle_t null_hpt_read(void) 79{ 80 return 0; 81} 82 83/* | 1/* 2 * Copyright 2001 MontaVista Software Inc. 3 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net 4 * Copyright (c) 2003, 2004 Maciej W. Rozycki 5 * 6 * Common time service routines for MIPS machines. See 7 * Documentation/mips/time.README. 8 * --- 67 unchanged lines hidden (view full) --- 76 * Null high precision timer functions for systems lacking one. 77 */ 78static cycle_t null_hpt_read(void) 79{ 80 return 0; 81} 82 83/* |
84 * Timer ack for an R4k-compatible timer of a known frequency. 85 */ 86static void c0_timer_ack(void) 87{ 88 write_c0_compare(read_c0_compare()); 89} 90 91/* | |
92 * High precision timer functions for a R4k-compatible timer. 93 */ 94static cycle_t c0_hpt_read(void) 95{ 96 return read_c0_count(); 97} 98 99int (*mips_timer_state)(void); --- 21 unchanged lines hidden (view full) --- 121 122EXPORT_SYMBOL(null_perf_irq); 123 124int (*perf_irq)(void) = null_perf_irq; 125 126EXPORT_SYMBOL(perf_irq); 127 128/* | 84 * High precision timer functions for a R4k-compatible timer. 85 */ 86static cycle_t c0_hpt_read(void) 87{ 88 return read_c0_count(); 89} 90 91int (*mips_timer_state)(void); --- 21 unchanged lines hidden (view full) --- 113 114EXPORT_SYMBOL(null_perf_irq); 115 116int (*perf_irq)(void) = null_perf_irq; 117 118EXPORT_SYMBOL(perf_irq); 119 120/* |
129 * Timer interrupt 130 */ 131int cp0_compare_irq; 132 133/* 134 * Performance counter IRQ or -1 if shared with timer 135 */ 136int cp0_perfcount_irq; 137EXPORT_SYMBOL_GPL(cp0_perfcount_irq); 138 139/* 140 * Possibly handle a performance counter interrupt. 141 * Return true if the timer interrupt should not be checked 142 */ 143static inline int handle_perf_irq(int r2) 144{ 145 /* 146 * The performance counter overflow interrupt may be shared with the 147 * timer interrupt (cp0_perfcount_irq < 0). If it is and a 148 * performance counter has overflowed (perf_irq() == IRQ_HANDLED) 149 * and we can't reliably determine if a counter interrupt has also 150 * happened (!r2) then don't check for a timer interrupt. 151 */ 152 return (cp0_perfcount_irq < 0) && 153 perf_irq() == IRQ_HANDLED && 154 !r2; 155} 156 157/* | |
158 * time_init() - it does the following things. 159 * 160 * 1) plat_time_init() - 161 * a) (optional) set up RTC routines, 162 * b) (optional) calibrate and set the mips_hpt_frequency 163 * (only needed if you intended to use cpu counter as timer interrupt 164 * source) 165 * 2) calculate a couple of cached variables for later usage --- 48 unchanged lines hidden (view full) --- 214} 215 216struct clocksource clocksource_mips = { 217 .name = "MIPS", 218 .mask = CLOCKSOURCE_MASK(32), 219 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 220}; 221 | 121 * time_init() - it does the following things. 122 * 123 * 1) plat_time_init() - 124 * a) (optional) set up RTC routines, 125 * b) (optional) calibrate and set the mips_hpt_frequency 126 * (only needed if you intended to use cpu counter as timer interrupt 127 * source) 128 * 2) calculate a couple of cached variables for later usage --- 48 unchanged lines hidden (view full) --- 177} 178 179struct clocksource clocksource_mips = { 180 .name = "MIPS", 181 .mask = CLOCKSOURCE_MASK(32), 182 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 183}; 184 |
222static int mips_next_event(unsigned long delta, 223 struct clock_event_device *evt) 224{ 225 unsigned int cnt; 226 int res; 227 228#ifdef CONFIG_MIPS_MT_SMTC 229 { 230 unsigned long flags, vpflags; 231 local_irq_save(flags); 232 vpflags = dvpe(); 233#endif 234 cnt = read_c0_count(); 235 cnt += delta; 236 write_c0_compare(cnt); 237 res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; 238#ifdef CONFIG_MIPS_MT_SMTC 239 evpe(vpflags); 240 local_irq_restore(flags); 241 } 242#endif 243 return res; 244} 245 246static void mips_set_mode(enum clock_event_mode mode, 247 struct clock_event_device *evt) 248{ 249 /* Nothing to do ... */ 250} 251 252static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); 253static int cp0_timer_irq_installed; 254 255static irqreturn_t timer_interrupt(int irq, void *dev_id) 256{ 257 const int r2 = cpu_has_mips_r2; 258 struct clock_event_device *cd; 259 int cpu = smp_processor_id(); 260 261 /* 262 * Suckage alert: 263 * Before R2 of the architecture there was no way to see if a 264 * performance counter interrupt was pending, so we have to run 265 * the performance counter interrupt handler anyway. 266 */ 267 if (handle_perf_irq(r2)) 268 goto out; 269 270 /* 271 * The same applies to performance counter interrupts. But with the 272 * above we now know that the reason we got here must be a timer 273 * interrupt. Being the paranoiacs we are we check anyway. 274 */ 275 if (!r2 || (read_c0_cause() & (1 << 30))) { 276 c0_timer_ack(); 277#ifdef CONFIG_MIPS_MT_SMTC 278 if (cpu_data[cpu].vpe_id) 279 goto out; 280 cpu = 0; 281#endif 282 cd = &per_cpu(mips_clockevent_device, cpu); 283 cd->event_handler(cd); 284 } 285 286out: 287 return IRQ_HANDLED; 288} 289 290static struct irqaction timer_irqaction = { 291 .handler = timer_interrupt, 292#ifdef CONFIG_MIPS_MT_SMTC 293 .flags = IRQF_DISABLED, 294#else 295 .flags = IRQF_DISABLED | IRQF_PERCPU, 296#endif 297 .name = "timer", 298}; 299 | |
300static void __init init_mips_clocksource(void) 301{ 302 u64 temp; 303 u32 shift; 304 305 if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read) 306 return; 307 --- 23 unchanged lines hidden (view full) --- 331#ifdef CONFIG_MIPS_MT_SMTC 332DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); 333 334static void smtc_set_mode(enum clock_event_mode mode, 335 struct clock_event_device *evt) 336{ 337} 338 | 185static void __init init_mips_clocksource(void) 186{ 187 u64 temp; 188 u32 shift; 189 190 if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read) 191 return; 192 --- 23 unchanged lines hidden (view full) --- 216#ifdef CONFIG_MIPS_MT_SMTC 217DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); 218 219static void smtc_set_mode(enum clock_event_mode mode, 220 struct clock_event_device *evt) 221{ 222} 223 |
339int dummycnt[NR_CPUS]; 340 | |
341static void mips_broadcast(cpumask_t mask) 342{ 343 unsigned int cpu; 344 345 for_each_cpu_mask(cpu, mask) 346 smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); 347} 348 --- 24 unchanged lines hidden (view full) --- 373 cd->set_mode = smtc_set_mode; 374 375 cd->broadcast = mips_broadcast; 376 377 clockevents_register_device(cd); 378} 379#endif 380 | 224static void mips_broadcast(cpumask_t mask) 225{ 226 unsigned int cpu; 227 228 for_each_cpu_mask(cpu, mask) 229 smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); 230} 231 --- 24 unchanged lines hidden (view full) --- 256 cd->set_mode = smtc_set_mode; 257 258 cd->broadcast = mips_broadcast; 259 260 clockevents_register_device(cd); 261} 262#endif 263 |
381static void mips_event_handler(struct clock_event_device *dev) 382{ 383} 384 385/* 386 * FIXME: This doesn't hold for the relocated E9000 compare interrupt. 387 */ 388static int c0_compare_int_pending(void) 389{ 390 return (read_c0_cause() >> cp0_compare_irq) & 0x100; 391} 392 393static int c0_compare_int_usable(void) 394{ 395 const unsigned int delta = 0x300000; 396 unsigned int cnt; 397 398 /* 399 * IP7 already pending? Try to clear it by acking the timer. 400 */ 401 if (c0_compare_int_pending()) { 402 write_c0_compare(read_c0_compare()); 403 irq_disable_hazard(); 404 if (c0_compare_int_pending()) 405 return 0; 406 } 407 408 cnt = read_c0_count(); 409 cnt += delta; 410 write_c0_compare(cnt); 411 412 while ((long)(read_c0_count() - cnt) <= 0) 413 ; /* Wait for expiry */ 414 415 if (!c0_compare_int_pending()) 416 return 0; 417 418 write_c0_compare(read_c0_compare()); 419 irq_disable_hazard(); 420 if (c0_compare_int_pending()) 421 return 0; 422 423 /* 424 * Feels like a real count / compare timer. 425 */ 426 return 1; 427} 428 429void __cpuinit mips_clockevent_init(void) 430{ 431 uint64_t mips_freq = mips_hpt_frequency; 432 unsigned int cpu = smp_processor_id(); 433 struct clock_event_device *cd; 434 unsigned int irq = MIPS_CPU_IRQ_BASE + 7; 435 436 if (!cpu_has_counter) 437 return; 438 439#ifdef CONFIG_MIPS_MT_SMTC 440 setup_smtc_dummy_clockevent_device(); 441 442 /* 443 * On SMTC we only register VPE0's compare interrupt as clockevent 444 * device. 445 */ 446 if (cpu) 447 return; 448#endif 449 450 if (!c0_compare_int_usable()) 451 return; 452 453 cd = &per_cpu(mips_clockevent_device, cpu); 454 455 cd->name = "MIPS"; 456 cd->features = CLOCK_EVT_FEAT_ONESHOT; 457 458 /* Calculate the min / max delta */ 459 cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); 460 cd->shift = 32; 461 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); 462 cd->min_delta_ns = clockevent_delta2ns(0x300, cd); 463 464 cd->rating = 300; 465 cd->irq = irq; 466#ifdef CONFIG_MIPS_MT_SMTC 467 cd->cpumask = CPU_MASK_ALL; 468#else 469 cd->cpumask = cpumask_of_cpu(cpu); 470#endif 471 cd->set_next_event = mips_next_event; 472 cd->set_mode = mips_set_mode; 473 cd->event_handler = mips_event_handler; 474 475 clockevents_register_device(cd); 476 477 if (!cp0_timer_irq_installed) { 478#ifdef CONFIG_MIPS_MT_SMTC 479#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq) 480 setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT); 481#else 482 setup_irq(irq, &timer_irqaction); 483#endif /* CONFIG_MIPS_MT_SMTC */ 484 cp0_timer_irq_installed = 1; 485 } 486} 487 | |
488void __init time_init(void) 489{ 490 plat_time_init(); 491 492 /* Choose appropriate high precision timer routines. */ 493 if (!cpu_has_counter && !clocksource_mips.read) 494 /* No high precision timer -- sorry. */ 495 clocksource_mips.read = null_hpt_read; --- 10 unchanged lines hidden (view full) --- 506 } 507 if (!mips_hpt_frequency) 508 mips_hpt_frequency = calibrate_hpt(); 509 510 /* Report the high precision timer rate for a reference. */ 511 printk("Using %u.%03u MHz high precision timer.\n", 512 ((mips_hpt_frequency + 500) / 1000) / 1000, 513 ((mips_hpt_frequency + 500) / 1000) % 1000); | 264void __init time_init(void) 265{ 266 plat_time_init(); 267 268 /* Choose appropriate high precision timer routines. */ 269 if (!cpu_has_counter && !clocksource_mips.read) 270 /* No high precision timer -- sorry. */ 271 clocksource_mips.read = null_hpt_read; --- 10 unchanged lines hidden (view full) --- 282 } 283 if (!mips_hpt_frequency) 284 mips_hpt_frequency = calibrate_hpt(); 285 286 /* Report the high precision timer rate for a reference. */ 287 printk("Using %u.%03u MHz high precision timer.\n", 288 ((mips_hpt_frequency + 500) / 1000) / 1000, 289 ((mips_hpt_frequency + 500) / 1000) % 1000); |
514 515#ifdef CONFIG_IRQ_CPU 516 setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction); 517#endif | |
518 } 519 | 290 } 291 |
520 /* 521 * Call board specific timer interrupt setup. 522 * 523 * this pointer must be setup in machine setup routine. 524 * 525 * Even if a machine chooses to use a low-level timer interrupt, 526 * it still needs to setup the timer_irqaction. 527 * In that case, it might be better to set timer_irqaction.handler 528 * to be NULL function so that we are sure the high-level code 529 * is not invoked accidentally. 530 */ 531 plat_timer_setup(&timer_irqaction); 532 | |
533 init_mips_clocksource(); 534 mips_clockevent_init(); 535} | 292 init_mips_clocksource(); 293 mips_clockevent_init(); 294} |