@@ -470,10 +470,57 @@ static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
470
470
return 0 ;
471
471
}
472
472
473
+ struct cmos_set_alarm_callback_param {
474
+ struct cmos_rtc * cmos ;
475
+ unsigned char mon , mday , hrs , min , sec ;
476
+ struct rtc_wkalrm * t ;
477
+ };
478
+
479
+ /* Note: this function may be executed by mc146818_avoid_UIP() more then
480
+ * once
481
+ */
482
+ static void cmos_set_alarm_callback (unsigned char __always_unused seconds ,
483
+ void * param_in )
484
+ {
485
+ struct cmos_set_alarm_callback_param * p =
486
+ (struct cmos_set_alarm_callback_param * )param_in ;
487
+
488
+ /* next rtc irq must not be from previous alarm setting */
489
+ cmos_irq_disable (p -> cmos , RTC_AIE );
490
+
491
+ /* update alarm */
492
+ CMOS_WRITE (p -> hrs , RTC_HOURS_ALARM );
493
+ CMOS_WRITE (p -> min , RTC_MINUTES_ALARM );
494
+ CMOS_WRITE (p -> sec , RTC_SECONDS_ALARM );
495
+
496
+ /* the system may support an "enhanced" alarm */
497
+ if (p -> cmos -> day_alrm ) {
498
+ CMOS_WRITE (p -> mday , p -> cmos -> day_alrm );
499
+ if (p -> cmos -> mon_alrm )
500
+ CMOS_WRITE (p -> mon , p -> cmos -> mon_alrm );
501
+ }
502
+
503
+ if (use_hpet_alarm ()) {
504
+ /*
505
+ * FIXME the HPET alarm glue currently ignores day_alrm
506
+ * and mon_alrm ...
507
+ */
508
+ hpet_set_alarm_time (p -> t -> time .tm_hour , p -> t -> time .tm_min ,
509
+ p -> t -> time .tm_sec );
510
+ }
511
+
512
+ if (p -> t -> enabled )
513
+ cmos_irq_enable (p -> cmos , RTC_AIE );
514
+ }
515
+
473
516
static int cmos_set_alarm (struct device * dev , struct rtc_wkalrm * t )
474
517
{
475
518
struct cmos_rtc * cmos = dev_get_drvdata (dev );
476
- unsigned char mon , mday , hrs , min , sec , rtc_control ;
519
+ struct cmos_set_alarm_callback_param p = {
520
+ .cmos = cmos ,
521
+ .t = t
522
+ };
523
+ unsigned char rtc_control ;
477
524
int ret ;
478
525
479
526
/* This not only a rtc_op, but also called directly */
@@ -484,55 +531,33 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
484
531
if (ret < 0 )
485
532
return ret ;
486
533
487
- mon = t -> time .tm_mon + 1 ;
488
- mday = t -> time .tm_mday ;
489
- hrs = t -> time .tm_hour ;
490
- min = t -> time .tm_min ;
491
- sec = t -> time .tm_sec ;
534
+ p . mon = t -> time .tm_mon + 1 ;
535
+ p . mday = t -> time .tm_mday ;
536
+ p . hrs = t -> time .tm_hour ;
537
+ p . min = t -> time .tm_min ;
538
+ p . sec = t -> time .tm_sec ;
492
539
493
540
spin_lock_irq (& rtc_lock );
494
541
rtc_control = CMOS_READ (RTC_CONTROL );
495
542
spin_unlock_irq (& rtc_lock );
496
543
497
544
if (!(rtc_control & RTC_DM_BINARY ) || RTC_ALWAYS_BCD ) {
498
545
/* Writing 0xff means "don't care" or "match all". */
499
- mon = (mon <= 12 ) ? bin2bcd (mon ) : 0xff ;
500
- mday = (mday >= 1 && mday <= 31 ) ? bin2bcd (mday ) : 0xff ;
501
- hrs = (hrs < 24 ) ? bin2bcd (hrs ) : 0xff ;
502
- min = (min < 60 ) ? bin2bcd (min ) : 0xff ;
503
- sec = (sec < 60 ) ? bin2bcd (sec ) : 0xff ;
504
- }
505
-
506
- spin_lock_irq (& rtc_lock );
507
-
508
- /* next rtc irq must not be from previous alarm setting */
509
- cmos_irq_disable (cmos , RTC_AIE );
510
-
511
- /* update alarm */
512
- CMOS_WRITE (hrs , RTC_HOURS_ALARM );
513
- CMOS_WRITE (min , RTC_MINUTES_ALARM );
514
- CMOS_WRITE (sec , RTC_SECONDS_ALARM );
515
-
516
- /* the system may support an "enhanced" alarm */
517
- if (cmos -> day_alrm ) {
518
- CMOS_WRITE (mday , cmos -> day_alrm );
519
- if (cmos -> mon_alrm )
520
- CMOS_WRITE (mon , cmos -> mon_alrm );
521
- }
522
-
523
- if (use_hpet_alarm ()) {
524
- /*
525
- * FIXME the HPET alarm glue currently ignores day_alrm
526
- * and mon_alrm ...
527
- */
528
- hpet_set_alarm_time (t -> time .tm_hour , t -> time .tm_min ,
529
- t -> time .tm_sec );
546
+ p .mon = (p .mon <= 12 ) ? bin2bcd (p .mon ) : 0xff ;
547
+ p .mday = (p .mday >= 1 && p .mday <= 31 ) ? bin2bcd (p .mday ) : 0xff ;
548
+ p .hrs = (p .hrs < 24 ) ? bin2bcd (p .hrs ) : 0xff ;
549
+ p .min = (p .min < 60 ) ? bin2bcd (p .min ) : 0xff ;
550
+ p .sec = (p .sec < 60 ) ? bin2bcd (p .sec ) : 0xff ;
530
551
}
531
552
532
- if (t -> enabled )
533
- cmos_irq_enable (cmos , RTC_AIE );
534
-
535
- spin_unlock_irq (& rtc_lock );
553
+ /*
554
+ * Some Intel chipsets disconnect the alarm registers when the clock
555
+ * update is in progress - during this time writes fail silently.
556
+ *
557
+ * Use mc146818_avoid_UIP() to avoid this.
558
+ */
559
+ if (!mc146818_avoid_UIP (cmos_set_alarm_callback , & p ))
560
+ return - EIO ;
536
561
537
562
cmos -> alarm_expires = rtc_tm_to_time64 (& t -> time );
538
563
0 commit comments