Skip to content

Commit

Permalink
Revert "Revert "rtc: alarm: Add power-on alarm feature""
Browse files Browse the repository at this point in the history
We still need this on OP3. Fixes problem where the system continuously
rebooted.

This reverts commit fee632961fba7353d035e73a3eb524aa79fac2b7.

Signed-off-by: Josh Choo <[email protected]>
  • Loading branch information
joshchoo committed Oct 22, 2018
1 parent 4d18211 commit 6597ff9
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 15 deletions.
32 changes: 19 additions & 13 deletions fs/timerfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ static DEFINE_SPINLOCK(cancel_lock);
static inline bool isalarm(struct timerfd_ctx *ctx)
{
return ctx->clockid == CLOCK_REALTIME_ALARM ||
ctx->clockid == CLOCK_BOOTTIME_ALARM;
ctx->clockid == CLOCK_BOOTTIME_ALARM ||
ctx->clockid == CLOCK_POWEROFF_ALARM;
}

/*
Expand Down Expand Up @@ -142,7 +143,8 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
{
spin_lock(&ctx->cancel_lock);
if ((ctx->clockid == CLOCK_REALTIME ||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
ctx->clockid == CLOCK_REALTIME_ALARM ||
ctx->clockid == CLOCK_POWEROFF_ALARM) &&
(flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
if (!ctx->might_cancel) {
ctx->might_cancel = true;
Expand Down Expand Up @@ -174,6 +176,7 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
enum hrtimer_mode htmode;
ktime_t texp;
int clockid = ctx->clockid;
enum alarmtimer_type type;

htmode = (flags & TFD_TIMER_ABSTIME) ?
HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
Expand All @@ -184,10 +187,8 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
ctx->tintv = timespec_to_ktime(ktmr->it_interval);

if (isalarm(ctx)) {
alarm_init(&ctx->t.alarm,
ctx->clockid == CLOCK_REALTIME_ALARM ?
ALARM_REALTIME : ALARM_BOOTTIME,
timerfd_alarmproc);
type = clock2alarm(ctx->clockid);
alarm_init(&ctx->t.alarm, type, timerfd_alarmproc);
} else {
hrtimer_init(&ctx->t.tmr, clockid, htmode);
hrtimer_set_expires(&ctx->t.tmr, texp);
Expand Down Expand Up @@ -386,6 +387,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
{
int ufd;
struct timerfd_ctx *ctx;
enum alarmtimer_type type;

/* Check the TFD_* constants for consistency. */
BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
Expand All @@ -396,7 +398,8 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
clockid != CLOCK_REALTIME &&
clockid != CLOCK_REALTIME_ALARM &&
clockid != CLOCK_BOOTTIME &&
clockid != CLOCK_BOOTTIME_ALARM))
clockid != CLOCK_BOOTTIME_ALARM &&
clockid != CLOCK_POWEROFF_ALARM))
return -EINVAL;

ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
Expand All @@ -407,13 +410,12 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
spin_lock_init(&ctx->cancel_lock);
ctx->clockid = clockid;

if (isalarm(ctx))
alarm_init(&ctx->t.alarm,
ctx->clockid == CLOCK_REALTIME_ALARM ?
ALARM_REALTIME : ALARM_BOOTTIME,
timerfd_alarmproc);
else
if (isalarm(ctx)) {
type = clock2alarm(ctx->clockid);
alarm_init(&ctx->t.alarm, type, timerfd_alarmproc);
} else {
hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
}

ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 });

Expand Down Expand Up @@ -485,6 +487,10 @@ static int do_timerfd_settime(int ufd, int flags,
ret = timerfd_setup(ctx, flags, new);

spin_unlock_irq(&ctx->wqh.lock);

if (ctx->clockid == CLOCK_POWEROFF_ALARM)
set_power_on_alarm();

fdput(f);
return ret;
}
Expand Down
4 changes: 4 additions & 0 deletions include/linux/alarmtimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
#include <linux/hrtimer.h>
#include <linux/timerqueue.h>
#include <linux/rtc.h>
#include <linux/types.h>

enum alarmtimer_type {
ALARM_REALTIME,
ALARM_BOOTTIME,
ALARM_POWEROFF_REALTIME,

ALARM_NUMTYPE,
};
Expand Down Expand Up @@ -48,6 +50,8 @@ int alarm_start_relative(struct alarm *alarm, ktime_t start);
void alarm_restart(struct alarm *alarm);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
void set_power_on_alarm(void);
enum alarmtimer_type clock2alarm(clockid_t clockid);

u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
u64 alarm_forward_now(struct alarm *alarm, ktime_t interval);
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct itimerval {
#define CLOCK_BOOTTIME_ALARM 9
#define CLOCK_SGI_CYCLE 10 /* Hardware specific */
#define CLOCK_TAI 11
#define CLOCK_POWEROFF_ALARM 12

#define MAX_CLOCKS 16
#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
Expand Down
116 changes: 114 additions & 2 deletions kernel/time/alarmtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#ifdef CONFIG_MSM_PM
#include "lpm-levels.h"
#endif
#include <linux/workqueue.h>

/**
* struct alarm_base - Alarm timer bases
Expand All @@ -50,12 +51,86 @@ static ktime_t freezer_delta;
static DEFINE_SPINLOCK(freezer_delta_lock);

static struct wakeup_source *ws;
static struct delayed_work work;
static struct workqueue_struct *power_off_alarm_workqueue;

#ifdef CONFIG_RTC_CLASS
/* rtc timer and device for setting alarm wakeups at suspend */
static struct rtc_timer rtctimer;
static struct rtc_device *rtcdev;
static DEFINE_SPINLOCK(rtcdev_lock);
static struct mutex power_on_alarm_lock;

/**
* set_power_on_alarm - set power on alarm value into rtc register
*
* Get the soonest power off alarm timer and set the alarm value into rtc
* register.
*/
void set_power_on_alarm(void)
{
int rc;
struct timespec wall_time, alarm_ts;
long alarm_secs = 0l;
long rtc_secs, alarm_time, alarm_delta;
struct rtc_time rtc_time;
struct rtc_wkalrm alarm;
struct rtc_device *rtc;
struct timerqueue_node *next;
unsigned long flags;
struct alarm_base *base = &alarm_bases[ALARM_POWEROFF_REALTIME];

rc = mutex_lock_interruptible(&power_on_alarm_lock);
if (rc != 0)
return;

spin_lock_irqsave(&base->lock, flags);
next = timerqueue_getnext(&base->timerqueue);
spin_unlock_irqrestore(&base->lock, flags);

rtc = alarmtimer_get_rtcdev();
if (!rtc)
goto exit;

if (next) {
alarm_ts = ktime_to_timespec(next->expires);
alarm_secs = alarm_ts.tv_sec;
}

if (!alarm_secs)
goto disable_alarm;

getnstimeofday(&wall_time);

/*
* alarm_secs have to be bigger than "wall_time +1".
* It is to make sure that alarm time will be always
* bigger than wall time.
*/
printk("alarm set_power_on_alarm time = %ld\n",alarm_secs);
if (alarm_secs <= wall_time.tv_sec + 1)
goto disable_alarm;

rtc_read_time(rtc, &rtc_time);
rtc_tm_to_time(&rtc_time, &rtc_secs);
alarm_delta = wall_time.tv_sec - rtc_secs;
alarm_time = alarm_secs - alarm_delta;

rtc_time_to_tm(alarm_time, &alarm.time);
alarm.enabled = 1;
rc = rtc_set_alarm(rtc, &alarm);
if (rc)
goto disable_alarm;

mutex_unlock(&power_on_alarm_lock);
return;

disable_alarm:
// rtc_timer_cancel(rtc, &rtc->aie_timer);
rtc_alarm_irq_enable(rtc, 0);
exit:
mutex_unlock(&power_on_alarm_lock);
}

static void alarmtimer_triggered_func(void *p)
{
Expand Down Expand Up @@ -127,6 +202,8 @@ static void alarmtimer_rtc_remove_device(struct device *dev,

static inline void alarmtimer_rtc_timer_init(void)
{
mutex_init(&power_on_alarm_lock);

rtc_timer_init(&rtctimer, NULL, NULL);
}

Expand All @@ -153,8 +230,14 @@ struct rtc_device *alarmtimer_get_rtcdev(void)
static inline int alarmtimer_rtc_interface_setup(void) { return 0; }
static inline void alarmtimer_rtc_interface_remove(void) { }
static inline void alarmtimer_rtc_timer_init(void) { }
void set_power_on_alarm(void) { }
#endif

static void alarm_work_func(struct work_struct *unused)
{
set_power_on_alarm();
}

/**
* alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue
* @base: pointer to the base where the timer is being run
Expand Down Expand Up @@ -224,6 +307,10 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
}
spin_unlock_irqrestore(&base->lock, flags);

/* set next power off alarm */
if (alarm->type == ALARM_POWEROFF_REALTIME)
queue_delayed_work(power_off_alarm_workqueue, &work, 0);

return ret;

}
Expand Down Expand Up @@ -256,6 +343,8 @@ static int alarmtimer_suspend(struct device *dev)
int i;
int ret = 0;

cancel_delayed_work_sync(&work);

spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta;
freezer_delta = ktime_set(0, 0);
Expand Down Expand Up @@ -319,6 +408,8 @@ static int alarmtimer_suspend(struct device *dev)
int i;
int ret;

cancel_delayed_work_sync(&work);

spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta;
freezer_delta = ktime_set(0, 0);
Expand Down Expand Up @@ -558,12 +649,14 @@ EXPORT_SYMBOL_GPL(alarm_forward_now);
* clock2alarm - helper that converts from clockid to alarmtypes
* @clockid: clockid.
*/
static enum alarmtimer_type clock2alarm(clockid_t clockid)
enum alarmtimer_type clock2alarm(clockid_t clockid)
{
if (clockid == CLOCK_REALTIME_ALARM)
return ALARM_REALTIME;
if (clockid == CLOCK_BOOTTIME_ALARM)
return ALARM_BOOTTIME;
if (clockid == CLOCK_POWEROFF_ALARM)
return ALARM_POWEROFF_REALTIME;
return -1;
}

Expand Down Expand Up @@ -960,10 +1053,13 @@ static int __init alarmtimer_init(void)

posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);
posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock);
posix_timers_register_clock(CLOCK_POWEROFF_ALARM, &alarm_clock);

/* Initialize alarm bases */
alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real;
alarm_bases[ALARM_POWEROFF_REALTIME].base_clockid = CLOCK_REALTIME;
alarm_bases[ALARM_POWEROFF_REALTIME].gettime = &ktime_get_real;
alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME;
alarm_bases[ALARM_BOOTTIME].gettime = &ktime_get_boottime;
for (i = 0; i < ALARM_NUMTYPE; i++) {
Expand All @@ -985,8 +1081,24 @@ static int __init alarmtimer_init(void)
goto out_drv;
}
ws = wakeup_source_register("alarmtimer");
return 0;
if (!ws) {
error = -ENOMEM;
goto out_ws;
}

INIT_DELAYED_WORK(&work, alarm_work_func);
power_off_alarm_workqueue =
create_singlethread_workqueue("power_off_alarm");
if (!power_off_alarm_workqueue) {
error = -ENOMEM;
goto out_wq;
}

return 0;
out_wq:
wakeup_source_unregister(ws);
out_ws:
platform_device_unregister(pdev);
out_drv:
platform_driver_unregister(&alarmtimer_driver);
out_if:
Expand Down

0 comments on commit 6597ff9

Please sign in to comment.