Commit 79016f64 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-fixes-for-linus' of git://tesla.tglx.de/git/linux-2.6-tip

* 'timers-fixes-for-linus' of git://tesla.tglx.de/git/linux-2.6-tip:
  rtc: twl: Fix registration vs. init order
  rtc: Initialized rtc_time->tm_isdst
  rtc: Fix RTC PIE frequency limit
  rtc: rtc-twl: Remove lockdep related local_irq_enable()
  rtc: rtc-twl: Switch to using threaded irq
  rtc: ep93xx: Fix 'rtc' may be used uninitialized warning
  alarmtimers: Avoid possible denial of service with high freq periodic timers
  alarmtimers: Memset itimerspec passed into alarm_timer_get
  alarmtimers: Avoid possible null pointer traversal
parents e81b693c 48625713
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
*/ */
struct ep93xx_rtc { struct ep93xx_rtc {
void __iomem *mmio_base; void __iomem *mmio_base;
struct rtc_device *rtc;
}; };
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
...@@ -130,7 +131,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) ...@@ -130,7 +131,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
{ {
struct ep93xx_rtc *ep93xx_rtc; struct ep93xx_rtc *ep93xx_rtc;
struct resource *res; struct resource *res;
struct rtc_device *rtc;
int err; int err;
ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL); ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
...@@ -151,12 +151,12 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) ...@@ -151,12 +151,12 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
pdev->dev.platform_data = ep93xx_rtc; pdev->dev.platform_data = ep93xx_rtc;
platform_set_drvdata(pdev, rtc); platform_set_drvdata(pdev, ep93xx_rtc);
rtc = rtc_device_register(pdev->name, ep93xx_rtc->rtc = rtc_device_register(pdev->name,
&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) { if (IS_ERR(ep93xx_rtc->rtc)) {
err = PTR_ERR(rtc); err = PTR_ERR(ep93xx_rtc->rtc);
goto exit; goto exit;
} }
...@@ -167,7 +167,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) ...@@ -167,7 +167,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
return 0; return 0;
fail: fail:
rtc_device_unregister(rtc); rtc_device_unregister(ep93xx_rtc->rtc);
exit: exit:
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
pdev->dev.platform_data = NULL; pdev->dev.platform_data = NULL;
...@@ -176,11 +176,11 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) ...@@ -176,11 +176,11 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
static int __exit ep93xx_rtc_remove(struct platform_device *pdev) static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
{ {
struct rtc_device *rtc = platform_get_drvdata(pdev); struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
rtc_device_unregister(rtc); rtc_device_unregister(ep93xx_rtc->rtc);
pdev->dev.platform_data = NULL; pdev->dev.platform_data = NULL;
return 0; return 0;
......
...@@ -85,6 +85,8 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) ...@@ -85,6 +85,8 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
time -= tm->tm_hour * 3600; time -= tm->tm_hour * 3600;
tm->tm_min = time / 60; tm->tm_min = time / 60;
tm->tm_sec = time - tm->tm_min * 60; tm->tm_sec = time - tm->tm_min * 60;
tm->tm_isdst = 0;
} }
EXPORT_SYMBOL(rtc_time_to_tm); EXPORT_SYMBOL(rtc_time_to_tm);
......
...@@ -362,14 +362,6 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) ...@@ -362,14 +362,6 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
int res; int res;
u8 rd_reg; u8 rd_reg;
#ifdef CONFIG_LOCKDEP
/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
* we don't want and can't tolerate. Although it might be
* friendlier not to borrow this thread context...
*/
local_irq_enable();
#endif
res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (res) if (res)
goto out; goto out;
...@@ -428,24 +420,12 @@ static struct rtc_class_ops twl_rtc_ops = { ...@@ -428,24 +420,12 @@ static struct rtc_class_ops twl_rtc_ops = {
static int __devinit twl_rtc_probe(struct platform_device *pdev) static int __devinit twl_rtc_probe(struct platform_device *pdev)
{ {
struct rtc_device *rtc; struct rtc_device *rtc;
int ret = 0; int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
u8 rd_reg; u8 rd_reg;
if (irq <= 0) if (irq <= 0)
return -EINVAL; goto out1;
rtc = rtc_device_register(pdev->name,
&pdev->dev, &twl_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc));
goto out0;
}
platform_set_drvdata(pdev, rtc);
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (ret < 0) if (ret < 0)
...@@ -462,14 +442,6 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) ...@@ -462,14 +442,6 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto out1; goto out1;
ret = request_irq(irq, twl_rtc_interrupt,
IRQF_TRIGGER_RISING,
dev_name(&rtc->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
goto out1;
}
if (twl_class_is_6030()) { if (twl_class_is_6030()) {
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A); REG_INT_MSK_LINE_A);
...@@ -480,28 +452,44 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev) ...@@ -480,28 +452,44 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
/* Check RTC module status, Enable if it is off */ /* Check RTC module status, Enable if it is off */
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
goto out2; goto out1;
if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
dev_info(&pdev->dev, "Enabling TWL-RTC.\n"); dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
goto out2; goto out1;
} }
/* init cached IRQ enable bits */ /* init cached IRQ enable bits */
ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
if (ret < 0) if (ret < 0)
goto out1;
rtc = rtc_device_register(pdev->name,
&pdev->dev, &twl_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc));
goto out1;
}
ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
IRQF_TRIGGER_RISING,
dev_name(&rtc->dev), rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n");
goto out2; goto out2;
}
return ret; platform_set_drvdata(pdev, rtc);
return 0;
out2: out2:
free_irq(irq, rtc);
out1:
rtc_device_unregister(rtc); rtc_device_unregister(rtc);
out0: out1:
return ret; return ret;
} }
......
...@@ -441,6 +441,8 @@ static int alarm_timer_create(struct k_itimer *new_timer) ...@@ -441,6 +441,8 @@ static int alarm_timer_create(struct k_itimer *new_timer)
static void alarm_timer_get(struct k_itimer *timr, static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting) struct itimerspec *cur_setting)
{ {
memset(cur_setting, 0, sizeof(struct itimerspec));
cur_setting->it_interval = cur_setting->it_interval =
ktime_to_timespec(timr->it.alarmtimer.period); ktime_to_timespec(timr->it.alarmtimer.period);
cur_setting->it_value = cur_setting->it_value =
...@@ -479,11 +481,17 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, ...@@ -479,11 +481,17 @@ static int alarm_timer_set(struct k_itimer *timr, int flags,
if (!rtcdev) if (!rtcdev)
return -ENOTSUPP; return -ENOTSUPP;
/* Save old values */ /*
old_setting->it_interval = * XXX HACK! Currently we can DOS a system if the interval
ktime_to_timespec(timr->it.alarmtimer.period); * period on alarmtimers is too small. Cap the interval here
old_setting->it_value = * to 100us and solve this properly in a future patch! -jstultz
ktime_to_timespec(timr->it.alarmtimer.node.expires); */
if ((new_setting->it_interval.tv_sec == 0) &&
(new_setting->it_interval.tv_nsec < 100000))
new_setting->it_interval.tv_nsec = 100000;
if (old_setting)
alarm_timer_get(timr, old_setting);
/* If the timer was already set, cancel it */ /* If the timer was already set, cancel it */
alarm_cancel(&timr->it.alarmtimer); alarm_cancel(&timr->it.alarmtimer);
......
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