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
This commit is contained in:
commit
79016f6488
@ -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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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 @@ exit:
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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 out2;
|
goto out1;
|
||||||
|
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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,
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user