Commit 5943a268 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  rtc: Namespace fixup
  RTC: Remove UIE emulation
  RTC: Rework RTC code to use timerqueue for events

Fix up trivial conflict in drivers/rtc/rtc-dev.c
parents 42776163 96c8f06a
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h>
#include "rtc-core.h" #include "rtc-core.h"
...@@ -152,6 +153,18 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, ...@@ -152,6 +153,18 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
spin_lock_init(&rtc->irq_task_lock); spin_lock_init(&rtc->irq_task_lock);
init_waitqueue_head(&rtc->irq_queue); init_waitqueue_head(&rtc->irq_queue);
/* Init timerqueue */
timerqueue_init_head(&rtc->timerqueue);
INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
/* Init aie timer */
rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);
/* Init uie timer */
rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);
/* Init pie timer */
hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
rtc->pie_timer.function = rtc_pie_update_irq;
rtc->pie_enabled = 0;
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
dev_set_name(&rtc->dev, "rtc%d", id); dev_set_name(&rtc->dev, "rtc%d", id);
......
This diff is collapsed.
...@@ -46,105 +46,6 @@ static int rtc_dev_open(struct inode *inode, struct file *file) ...@@ -46,105 +46,6 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
return err; return err;
} }
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
/*
* Routine to poll RTC seconds field for change as often as possible,
* after first RTC_UIE use timer to reduce polling
*/
static void rtc_uie_task(struct work_struct *work)
{
struct rtc_device *rtc =
container_of(work, struct rtc_device, uie_task);
struct rtc_time tm;
int num = 0;
int err;
err = rtc_read_time(rtc, &tm);
spin_lock_irq(&rtc->irq_lock);
if (rtc->stop_uie_polling || err) {
rtc->uie_task_active = 0;
} else if (rtc->oldsecs != tm.tm_sec) {
num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
rtc->oldsecs = tm.tm_sec;
rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
rtc->uie_timer_active = 1;
rtc->uie_task_active = 0;
add_timer(&rtc->uie_timer);
} else if (schedule_work(&rtc->uie_task) == 0) {
rtc->uie_task_active = 0;
}
spin_unlock_irq(&rtc->irq_lock);
if (num)
rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
}
static void rtc_uie_timer(unsigned long data)
{
struct rtc_device *rtc = (struct rtc_device *)data;
unsigned long flags;
spin_lock_irqsave(&rtc->irq_lock, flags);
rtc->uie_timer_active = 0;
rtc->uie_task_active = 1;
if ((schedule_work(&rtc->uie_task) == 0))
rtc->uie_task_active = 0;
spin_unlock_irqrestore(&rtc->irq_lock, flags);
}
static int clear_uie(struct rtc_device *rtc)
{
spin_lock_irq(&rtc->irq_lock);
if (rtc->uie_irq_active) {
rtc->stop_uie_polling = 1;
if (rtc->uie_timer_active) {
spin_unlock_irq(&rtc->irq_lock);
del_timer_sync(&rtc->uie_timer);
spin_lock_irq(&rtc->irq_lock);
rtc->uie_timer_active = 0;
}
if (rtc->uie_task_active) {
spin_unlock_irq(&rtc->irq_lock);
flush_work_sync(&rtc->uie_task);
spin_lock_irq(&rtc->irq_lock);
}
rtc->uie_irq_active = 0;
}
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
static int set_uie(struct rtc_device *rtc)
{
struct rtc_time tm;
int err;
err = rtc_read_time(rtc, &tm);
if (err)
return err;
spin_lock_irq(&rtc->irq_lock);
if (!rtc->uie_irq_active) {
rtc->uie_irq_active = 1;
rtc->stop_uie_polling = 0;
rtc->oldsecs = tm.tm_sec;
rtc->uie_task_active = 1;
if (schedule_work(&rtc->uie_task) == 0)
rtc->uie_task_active = 0;
}
rtc->irq_data = 0;
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
{
if (enabled)
return set_uie(rtc);
else
return clear_uie(rtc);
}
EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
static ssize_t static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
...@@ -493,11 +394,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) ...@@ -493,11 +394,6 @@ void rtc_dev_prepare(struct rtc_device *rtc)
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
INIT_WORK(&rtc->uie_task, rtc_uie_task);
setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
#endif
cdev_init(&rtc->char_dev, &rtc_dev_fops); cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner; rtc->char_dev.owner = rtc->owner;
} }
......
...@@ -117,4 +117,32 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) ...@@ -117,4 +117,32 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
} }
EXPORT_SYMBOL(rtc_tm_to_time); EXPORT_SYMBOL(rtc_tm_to_time);
/*
* Convert rtc_time to ktime
*/
ktime_t rtc_tm_to_ktime(struct rtc_time tm)
{
time_t time;
rtc_tm_to_time(&tm, &time);
return ktime_set(time, 0);
}
EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
/*
* Convert ktime to rtc_time
*/
struct rtc_time rtc_ktime_to_tm(ktime_t kt)
{
struct timespec ts;
struct rtc_time ret;
ts = ktime_to_timespec(kt);
/* Round up any ns */
if (ts.tv_nsec)
ts.tv_sec++;
rtc_time_to_tm(ts.tv_sec, &ret);
return ret;
}
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -107,12 +107,17 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year ...@@ -107,12 +107,17 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
extern int rtc_valid_tm(struct rtc_time *tm); extern int rtc_valid_tm(struct rtc_time *tm);
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
ktime_t rtc_tm_to_ktime(struct rtc_time tm);
struct rtc_time rtc_ktime_to_tm(ktime_t kt);
#include <linux/device.h> #include <linux/device.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/timerqueue.h>
#include <linux/workqueue.h>
extern struct class *rtc_class; extern struct class *rtc_class;
...@@ -151,7 +156,19 @@ struct rtc_class_ops { ...@@ -151,7 +156,19 @@ struct rtc_class_ops {
}; };
#define RTC_DEVICE_NAME_SIZE 20 #define RTC_DEVICE_NAME_SIZE 20
struct rtc_task; typedef struct rtc_task {
void (*func)(void *private_data);
void *private_data;
} rtc_task_t;
struct rtc_timer {
struct rtc_task task;
struct timerqueue_node node;
ktime_t period;
int enabled;
};
/* flags */ /* flags */
#define RTC_DEV_BUSY 0 #define RTC_DEV_BUSY 0
...@@ -179,16 +196,13 @@ struct rtc_device ...@@ -179,16 +196,13 @@ struct rtc_device
spinlock_t irq_task_lock; spinlock_t irq_task_lock;
int irq_freq; int irq_freq;
int max_user_freq; int max_user_freq;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task; struct timerqueue_head timerqueue;
struct timer_list uie_timer; struct rtc_timer aie_timer;
/* Those fields are protected by rtc->irq_lock */ struct rtc_timer uie_rtctimer;
unsigned int oldsecs; struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
unsigned int uie_irq_active:1; int pie_enabled;
unsigned int stop_uie_polling:1; struct work_struct irqwork;
unsigned int uie_task_active:1;
unsigned int uie_timer_active:1;
#endif
}; };
#define to_rtc_device(d) container_of(d, struct rtc_device, dev) #define to_rtc_device(d) container_of(d, struct rtc_device, dev)
...@@ -224,15 +238,22 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); ...@@ -224,15 +238,22 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
unsigned int enabled); unsigned int enabled);
typedef struct rtc_task { void rtc_aie_update_irq(void *private);
void (*func)(void *private_data); void rtc_uie_update_irq(void *private);
void *private_data; enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
} rtc_task_t;
int rtc_register(rtc_task_t *task); int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task); int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
ktime_t expires, ktime_t period);
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer);
void rtc_timer_do_work(struct work_struct *work);
static inline bool is_leap_year(unsigned int year) static inline bool is_leap_year(unsigned int year)
{ {
return (!(year % 4) && (year % 100)) || !(year % 400); return (!(year % 4) && (year % 100)) || !(year % 400);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment