1 #include <linux/clocksource.h> 2 #include <linux/clockchips.h> 3 #include <linux/delay.h> 4 #include <linux/errno.h> 5 #include <linux/hpet.h> 6 #include <linux/init.h> 7 #include <linux/sysdev.h> 8 #include <linux/pm.h> 9 10 #include <asm/fixmap.h> 11 #include <asm/hpet.h> 12 #include <asm/i8253.h> 13 #include <asm/io.h> 14 15 #define HPET_MASK CLOCKSOURCE_MASK(32) 16 #define HPET_SHIFT 22 17 18 /* FSEC = 10^-15 19 NSEC = 10^-9 */ 20 #define FSEC_PER_NSEC 1000000L 21 22 /* 23 * HPET address is set in acpi/boot.c, when an ACPI entry exists 24 */ 25 unsigned long hpet_address; 26 static void __iomem *hpet_virt_address; 27 28 unsigned long hpet_readl(unsigned long a) 29 { 30 return readl(hpet_virt_address + a); 31 } 32 33 static inline void hpet_writel(unsigned long d, unsigned long a) 34 { 35 writel(d, hpet_virt_address + a); 36 } 37 38 #ifdef CONFIG_X86_64 39 #include <asm/pgtable.h> 40 #endif 41 42 static inline void hpet_set_mapping(void) 43 { 44 hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); 45 #ifdef CONFIG_X86_64 46 __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); 47 #endif 48 } 49 50 static inline void hpet_clear_mapping(void) 51 { 52 iounmap(hpet_virt_address); 53 hpet_virt_address = NULL; 54 } 55 56 /* 57 * HPET command line enable / disable 58 */ 59 static int boot_hpet_disable; 60 int hpet_force_user; 61 62 static int __init hpet_setup(char* str) 63 { 64 if (str) { 65 if (!strncmp("disable", str, 7)) 66 boot_hpet_disable = 1; 67 if (!strncmp("force", str, 5)) 68 hpet_force_user = 1; 69 } 70 return 1; 71 } 72 __setup("hpet=", hpet_setup); 73 74 static int __init disable_hpet(char *str) 75 { 76 boot_hpet_disable = 1; 77 return 1; 78 } 79 __setup("nohpet", disable_hpet); 80 81 static inline int is_hpet_capable(void) 82 { 83 return (!boot_hpet_disable && hpet_address); 84 } 85 86 /* 87 * HPET timer interrupt enable / disable 88 */ 89 static int hpet_legacy_int_enabled; 90 91 /** 92 * is_hpet_enabled - check whether the hpet timer interrupt is enabled 93 */ 94 int is_hpet_enabled(void) 95 { 96 return is_hpet_capable() && hpet_legacy_int_enabled; 97 } 98 EXPORT_SYMBOL_GPL(is_hpet_enabled); 99 100 /* 101 * When the hpet driver (/dev/hpet) is enabled, we need to reserve 102 * timer 0 and timer 1 in case of RTC emulation. 103 */ 104 #ifdef CONFIG_HPET 105 static void hpet_reserve_platform_timers(unsigned long id) 106 { 107 struct hpet __iomem *hpet = hpet_virt_address; 108 struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; 109 unsigned int nrtimers, i; 110 struct hpet_data hd; 111 112 nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; 113 114 memset(&hd, 0, sizeof (hd)); 115 hd.hd_phys_address = hpet_address; 116 hd.hd_address = hpet; 117 hd.hd_nirqs = nrtimers; 118 hd.hd_flags = HPET_DATA_PLATFORM; 119 hpet_reserve_timer(&hd, 0); 120 121 #ifdef CONFIG_HPET_EMULATE_RTC 122 hpet_reserve_timer(&hd, 1); 123 #endif 124 125 hd.hd_irq[0] = HPET_LEGACY_8254; 126 hd.hd_irq[1] = HPET_LEGACY_RTC; 127 128 for (i = 2; i < nrtimers; timer++, i++) { 129 hd.hd_irq[i] = (readl(&timer->hpet_config) & Tn_INT_ROUTE_CNF_MASK) >> 130 Tn_INT_ROUTE_CNF_SHIFT; 131 } 132 133 hpet_alloc(&hd); 134 135 } 136 #else 137 static void hpet_reserve_platform_timers(unsigned long id) { } 138 #endif 139 140 /* 141 * Common hpet info 142 */ 143 static unsigned long hpet_period; 144 145 static void hpet_legacy_set_mode(enum clock_event_mode mode, 146 struct clock_event_device *evt); 147 static int hpet_legacy_next_event(unsigned long delta, 148 struct clock_event_device *evt); 149 150 /* 151 * The hpet clock event device 152 */ 153 static struct clock_event_device hpet_clockevent = { 154 .name = "hpet", 155 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 156 .set_mode = hpet_legacy_set_mode, 157 .set_next_event = hpet_legacy_next_event, 158 .shift = 32, 159 .irq = 0, 160 .rating = 50, 161 }; 162 163 static void hpet_start_counter(void) 164 { 165 unsigned long cfg = hpet_readl(HPET_CFG); 166 167 cfg &= ~HPET_CFG_ENABLE; 168 hpet_writel(cfg, HPET_CFG); 169 hpet_writel(0, HPET_COUNTER); 170 hpet_writel(0, HPET_COUNTER + 4); 171 cfg |= HPET_CFG_ENABLE; 172 hpet_writel(cfg, HPET_CFG); 173 } 174 175 static void hpet_resume_device(void) 176 { 177 force_hpet_resume(); 178 } 179 180 static void hpet_restart_counter(void) 181 { 182 hpet_resume_device(); 183 hpet_start_counter(); 184 } 185 186 static void hpet_enable_legacy_int(void) 187 { 188 unsigned long cfg = hpet_readl(HPET_CFG); 189 190 cfg |= HPET_CFG_LEGACY; 191 hpet_writel(cfg, HPET_CFG); 192 hpet_legacy_int_enabled = 1; 193 } 194 195 static void hpet_legacy_clockevent_register(void) 196 { 197 /* Start HPET legacy interrupts */ 198 hpet_enable_legacy_int(); 199 200 /* 201 * The mult factor is defined as (include/linux/clockchips.h) 202 * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) 203 * hpet_period is in units of femtoseconds (per cycle), so 204 * mult/2^shift = cyc/ns = 10^6/hpet_period 205 * mult = (10^6 * 2^shift)/hpet_period 206 * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period 207 */ 208 hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, 209 hpet_period, hpet_clockevent.shift); 210 /* Calculate the min / max delta */ 211 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, 212 &hpet_clockevent); 213 /* 5 usec minimum reprogramming delta. */ 214 hpet_clockevent.min_delta_ns = 5000; 215 216 /* 217 * Start hpet with the boot cpu mask and make it 218 * global after the IO_APIC has been initialized. 219 */ 220 hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); 221 clockevents_register_device(&hpet_clockevent); 222 global_clock_event = &hpet_clockevent; 223 printk(KERN_DEBUG "hpet clockevent registered\n"); 224 } 225 226 static void hpet_legacy_set_mode(enum clock_event_mode mode, 227 struct clock_event_device *evt) 228 { 229 unsigned long cfg, cmp, now; 230 uint64_t delta; 231 232 switch(mode) { 233 case CLOCK_EVT_MODE_PERIODIC: 234 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult; 235 delta >>= hpet_clockevent.shift; 236 now = hpet_readl(HPET_COUNTER); 237 cmp = now + (unsigned long) delta; 238 cfg = hpet_readl(HPET_T0_CFG); 239 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 240 HPET_TN_SETVAL | HPET_TN_32BIT; 241 hpet_writel(cfg, HPET_T0_CFG); 242 /* 243 * The first write after writing TN_SETVAL to the 244 * config register sets the counter value, the second 245 * write sets the period. 246 */ 247 hpet_writel(cmp, HPET_T0_CMP); 248 udelay(1); 249 hpet_writel((unsigned long) delta, HPET_T0_CMP); 250 break; 251 252 case CLOCK_EVT_MODE_ONESHOT: 253 cfg = hpet_readl(HPET_T0_CFG); 254 cfg &= ~HPET_TN_PERIODIC; 255 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; 256 hpet_writel(cfg, HPET_T0_CFG); 257 break; 258 259 case CLOCK_EVT_MODE_UNUSED: 260 case CLOCK_EVT_MODE_SHUTDOWN: 261 cfg = hpet_readl(HPET_T0_CFG); 262 cfg &= ~HPET_TN_ENABLE; 263 hpet_writel(cfg, HPET_T0_CFG); 264 break; 265 266 case CLOCK_EVT_MODE_RESUME: 267 hpet_enable_legacy_int(); 268 break; 269 } 270 } 271 272 static int hpet_legacy_next_event(unsigned long delta, 273 struct clock_event_device *evt) 274 { 275 u32 cnt; 276 277 cnt = hpet_readl(HPET_COUNTER); 278 cnt += (u32) delta; 279 hpet_writel(cnt, HPET_T0_CMP); 280 281 /* 282 * We need to read back the CMP register to make sure that 283 * what we wrote hit the chip before we compare it to the 284 * counter. 285 */ 286 WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); 287 288 return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; 289 } 290 291 /* 292 * Clock source related code 293 */ 294 static cycle_t read_hpet(void) 295 { 296 return (cycle_t)hpet_readl(HPET_COUNTER); 297 } 298 299 #ifdef CONFIG_X86_64 300 static cycle_t __vsyscall_fn vread_hpet(void) 301 { 302 return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); 303 } 304 #endif 305 306 static struct clocksource clocksource_hpet = { 307 .name = "hpet", 308 .rating = 250, 309 .read = read_hpet, 310 .mask = HPET_MASK, 311 .shift = HPET_SHIFT, 312 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 313 .resume = hpet_restart_counter, 314 #ifdef CONFIG_X86_64 315 .vread = vread_hpet, 316 #endif 317 }; 318 319 static int hpet_clocksource_register(void) 320 { 321 u64 start, now; 322 cycle_t t1; 323 324 /* Start the counter */ 325 hpet_start_counter(); 326 327 /* Verify whether hpet counter works */ 328 t1 = read_hpet(); 329 rdtscll(start); 330 331 /* 332 * We don't know the TSC frequency yet, but waiting for 333 * 200000 TSC cycles is safe: 334 * 4 GHz == 50us 335 * 1 GHz == 200us 336 */ 337 do { 338 rep_nop(); 339 rdtscll(now); 340 } while ((now - start) < 200000UL); 341 342 if (t1 == read_hpet()) { 343 printk(KERN_WARNING 344 "HPET counter not counting. HPET disabled\n"); 345 return -ENODEV; 346 } 347 348 /* 349 * The definition of mult is (include/linux/clocksource.h) 350 * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc 351 * so we first need to convert hpet_period to ns/cyc units: 352 * mult/2^shift = ns/cyc = hpet_period/10^6 353 * mult = (hpet_period * 2^shift)/10^6 354 * mult = (hpet_period << shift)/FSEC_PER_NSEC 355 */ 356 clocksource_hpet.mult = div_sc(hpet_period, FSEC_PER_NSEC, HPET_SHIFT); 357 358 clocksource_register(&clocksource_hpet); 359 360 return 0; 361 } 362 363 /** 364 * hpet_enable - Try to setup the HPET timer. Returns 1 on success. 365 */ 366 int __init hpet_enable(void) 367 { 368 unsigned long id; 369 int i; 370 371 if (!is_hpet_capable()) 372 return 0; 373 374 hpet_set_mapping(); 375 376 /* 377 * Read the period and check for a sane value: 378 */ 379 hpet_period = hpet_readl(HPET_PERIOD); 380 381 /* 382 * AMD SB700 based systems with spread spectrum enabled use a 383 * SMM based HPET emulation to provide proper frequency 384 * setting. The SMM code is initialized with the first HPET 385 * register access and takes some time to complete. During 386 * this time the config register reads 0xffffffff. We check 387 * for max. 1000 loops whether the config register reads a non 388 * 0xffffffff value to make sure that HPET is up and running 389 * before we go further. A counting loop is safe, as the HPET 390 * access takes thousands of CPU cycles. On non SB700 based 391 * machines this check is only done once and has no side 392 * effects. 393 */ 394 for (i = 0; hpet_readl(HPET_CFG) == 0xFFFFFFFF; i++) { 395 if (i == 1000) { 396 printk(KERN_WARNING 397 "HPET config register value = 0xFFFFFFFF. " 398 "Disabling HPET\n"); 399 goto out_nohpet; 400 } 401 } 402 403 if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) 404 goto out_nohpet; 405 406 /* 407 * Read the HPET ID register to retrieve the IRQ routing 408 * information and the number of channels 409 */ 410 id = hpet_readl(HPET_ID); 411 412 #ifdef CONFIG_HPET_EMULATE_RTC 413 /* 414 * The legacy routing mode needs at least two channels, tick timer 415 * and the rtc emulation channel. 416 */ 417 if (!(id & HPET_ID_NUMBER)) 418 goto out_nohpet; 419 #endif 420 421 if (hpet_clocksource_register()) 422 goto out_nohpet; 423 424 if (id & HPET_ID_LEGSUP) { 425 hpet_legacy_clockevent_register(); 426 return 1; 427 } 428 return 0; 429 430 out_nohpet: 431 hpet_clear_mapping(); 432 boot_hpet_disable = 1; 433 return 0; 434 } 435 436 /* 437 * Needs to be late, as the reserve_timer code calls kalloc ! 438 * 439 * Not a problem on i386 as hpet_enable is called from late_time_init, 440 * but on x86_64 it is necessary ! 441 */ 442 static __init int hpet_late_init(void) 443 { 444 if (boot_hpet_disable) 445 return -ENODEV; 446 447 if (!hpet_address) { 448 if (!force_hpet_address) 449 return -ENODEV; 450 451 hpet_address = force_hpet_address; 452 hpet_enable(); 453 if (!hpet_virt_address) 454 return -ENODEV; 455 } 456 457 hpet_reserve_platform_timers(hpet_readl(HPET_ID)); 458 459 return 0; 460 } 461 fs_initcall(hpet_late_init); 462 463 void hpet_disable(void) 464 { 465 if (is_hpet_capable()) { 466 unsigned long cfg = hpet_readl(HPET_CFG); 467 468 if (hpet_legacy_int_enabled) { 469 cfg &= ~HPET_CFG_LEGACY; 470 hpet_legacy_int_enabled = 0; 471 } 472 cfg &= ~HPET_CFG_ENABLE; 473 hpet_writel(cfg, HPET_CFG); 474 } 475 } 476 477 #ifdef CONFIG_HPET_EMULATE_RTC 478 479 /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET 480 * is enabled, we support RTC interrupt functionality in software. 481 * RTC has 3 kinds of interrupts: 482 * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock 483 * is updated 484 * 2) Alarm Interrupt - generate an interrupt at a specific time of day 485 * 3) Periodic Interrupt - generate periodic interrupt, with frequencies 486 * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) 487 * (1) and (2) above are implemented using polling at a frequency of 488 * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt 489 * overhead. (DEFAULT_RTC_INT_FREQ) 490 * For (3), we use interrupts at 64Hz or user specified periodic 491 * frequency, whichever is higher. 492 */ 493 #include <linux/mc146818rtc.h> 494 #include <linux/rtc.h> 495 #include <asm/rtc.h> 496 497 #define DEFAULT_RTC_INT_FREQ 64 498 #define DEFAULT_RTC_SHIFT 6 499 #define RTC_NUM_INTS 1 500 501 static unsigned long hpet_rtc_flags; 502 static int hpet_prev_update_sec; 503 static struct rtc_time hpet_alarm_time; 504 static unsigned long hpet_pie_count; 505 static unsigned long hpet_t1_cmp; 506 static unsigned long hpet_default_delta; 507 static unsigned long hpet_pie_delta; 508 static unsigned long hpet_pie_limit; 509 510 static rtc_irq_handler irq_handler; 511 512 /* 513 * Registers a IRQ handler. 514 */ 515 int hpet_register_irq_handler(rtc_irq_handler handler) 516 { 517 if (!is_hpet_enabled()) 518 return -ENODEV; 519 if (irq_handler) 520 return -EBUSY; 521 522 irq_handler = handler; 523 524 return 0; 525 } 526 EXPORT_SYMBOL_GPL(hpet_register_irq_handler); 527 528 /* 529 * Deregisters the IRQ handler registered with hpet_register_irq_handler() 530 * and does cleanup. 531 */ 532 void hpet_unregister_irq_handler(rtc_irq_handler handler) 533 { 534 if (!is_hpet_enabled()) 535 return; 536 537 irq_handler = NULL; 538 hpet_rtc_flags = 0; 539 } 540 EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler); 541 542 /* 543 * Timer 1 for RTC emulation. We use one shot mode, as periodic mode 544 * is not supported by all HPET implementations for timer 1. 545 * 546 * hpet_rtc_timer_init() is called when the rtc is initialized. 547 */ 548 int hpet_rtc_timer_init(void) 549 { 550 unsigned long cfg, cnt, delta, flags; 551 552 if (!is_hpet_enabled()) 553 return 0; 554 555 if (!hpet_default_delta) { 556 uint64_t clc; 557 558 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; 559 clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; 560 hpet_default_delta = (unsigned long) clc; 561 } 562 563 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) 564 delta = hpet_default_delta; 565 else 566 delta = hpet_pie_delta; 567 568 local_irq_save(flags); 569 570 cnt = delta + hpet_readl(HPET_COUNTER); 571 hpet_writel(cnt, HPET_T1_CMP); 572 hpet_t1_cmp = cnt; 573 574 cfg = hpet_readl(HPET_T1_CFG); 575 cfg &= ~HPET_TN_PERIODIC; 576 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; 577 hpet_writel(cfg, HPET_T1_CFG); 578 579 local_irq_restore(flags); 580 581 return 1; 582 } 583 EXPORT_SYMBOL_GPL(hpet_rtc_timer_init); 584 585 /* 586 * The functions below are called from rtc driver. 587 * Return 0 if HPET is not being used. 588 * Otherwise do the necessary changes and return 1. 589 */ 590 int hpet_mask_rtc_irq_bit(unsigned long bit_mask) 591 { 592 if (!is_hpet_enabled()) 593 return 0; 594 595 hpet_rtc_flags &= ~bit_mask; 596 return 1; 597 } 598 EXPORT_SYMBOL_GPL(hpet_mask_rtc_irq_bit); 599 600 int hpet_set_rtc_irq_bit(unsigned long bit_mask) 601 { 602 unsigned long oldbits = hpet_rtc_flags; 603 604 if (!is_hpet_enabled()) 605 return 0; 606 607 hpet_rtc_flags |= bit_mask; 608 609 if ((bit_mask & RTC_UIE) && !(oldbits & RTC_UIE)) 610 hpet_prev_update_sec = -1; 611 612 if (!oldbits) 613 hpet_rtc_timer_init(); 614 615 return 1; 616 } 617 EXPORT_SYMBOL_GPL(hpet_set_rtc_irq_bit); 618 619 int hpet_set_alarm_time(unsigned char hrs, unsigned char min, 620 unsigned char sec) 621 { 622 if (!is_hpet_enabled()) 623 return 0; 624 625 hpet_alarm_time.tm_hour = hrs; 626 hpet_alarm_time.tm_min = min; 627 hpet_alarm_time.tm_sec = sec; 628 629 return 1; 630 } 631 EXPORT_SYMBOL_GPL(hpet_set_alarm_time); 632 633 int hpet_set_periodic_freq(unsigned long freq) 634 { 635 uint64_t clc; 636 637 if (!is_hpet_enabled()) 638 return 0; 639 640 if (freq <= DEFAULT_RTC_INT_FREQ) 641 hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq; 642 else { 643 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; 644 do_div(clc, freq); 645 clc >>= hpet_clockevent.shift; 646 hpet_pie_delta = (unsigned long) clc; 647 } 648 return 1; 649 } 650 EXPORT_SYMBOL_GPL(hpet_set_periodic_freq); 651 652 int hpet_rtc_dropped_irq(void) 653 { 654 return is_hpet_enabled(); 655 } 656 EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq); 657 658 static void hpet_rtc_timer_reinit(void) 659 { 660 unsigned long cfg, delta; 661 int lost_ints = -1; 662 663 if (unlikely(!hpet_rtc_flags)) { 664 cfg = hpet_readl(HPET_T1_CFG); 665 cfg &= ~HPET_TN_ENABLE; 666 hpet_writel(cfg, HPET_T1_CFG); 667 return; 668 } 669 670 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) 671 delta = hpet_default_delta; 672 else 673 delta = hpet_pie_delta; 674 675 /* 676 * Increment the comparator value until we are ahead of the 677 * current count. 678 */ 679 do { 680 hpet_t1_cmp += delta; 681 hpet_writel(hpet_t1_cmp, HPET_T1_CMP); 682 lost_ints++; 683 } while ((long)(hpet_readl(HPET_COUNTER) - hpet_t1_cmp) > 0); 684 685 if (lost_ints) { 686 if (hpet_rtc_flags & RTC_PIE) 687 hpet_pie_count += lost_ints; 688 if (printk_ratelimit()) 689 printk(KERN_WARNING "hpet1: lost %d rtc interrupts\n", 690 lost_ints); 691 } 692 } 693 694 irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) 695 { 696 struct rtc_time curr_time; 697 unsigned long rtc_int_flag = 0; 698 699 hpet_rtc_timer_reinit(); 700 memset(&curr_time, 0, sizeof(struct rtc_time)); 701 702 if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) 703 get_rtc_time(&curr_time); 704 705 if (hpet_rtc_flags & RTC_UIE && 706 curr_time.tm_sec != hpet_prev_update_sec) { 707 if (hpet_prev_update_sec >= 0) 708 rtc_int_flag = RTC_UF; 709 hpet_prev_update_sec = curr_time.tm_sec; 710 } 711 712 if (hpet_rtc_flags & RTC_PIE && 713 ++hpet_pie_count >= hpet_pie_limit) { 714 rtc_int_flag |= RTC_PF; 715 hpet_pie_count = 0; 716 } 717 718 if (hpet_rtc_flags & RTC_AIE && 719 (curr_time.tm_sec == hpet_alarm_time.tm_sec) && 720 (curr_time.tm_min == hpet_alarm_time.tm_min) && 721 (curr_time.tm_hour == hpet_alarm_time.tm_hour)) 722 rtc_int_flag |= RTC_AF; 723 724 if (rtc_int_flag) { 725 rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); 726 if (irq_handler) 727 irq_handler(rtc_int_flag, dev_id); 728 } 729 return IRQ_HANDLED; 730 } 731 EXPORT_SYMBOL_GPL(hpet_rtc_interrupt); 732 #endif 733