aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-tx4939.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2009-12-15 19:46:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:19:59 -0500
commitaf69a180e0675ce95842adb519079204ee5647ea (patch)
tree138b271a928e8715611393fb779251110bc6aa22 /drivers/rtc/rtc-tx4939.c
parentba4f3e47cb9ef72f864f1b5548688e0a195011e9 (diff)
rtc-tx4939: fix races around device registration
* Use its own spinlock instead of rtc->irq_lock * Check pdata->rtc before calling rtc_update_irq * Disable interrupt after rtc_device_unregister Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-tx4939.c')
-rw-r--r--drivers/rtc/rtc-tx4939.c51
1 files changed, 26 insertions, 25 deletions
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 4a6ed1104fbb..9ee81d8aa7c0 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -17,6 +17,7 @@
17struct tx4939rtc_plat_data { 17struct tx4939rtc_plat_data {
18 struct rtc_device *rtc; 18 struct rtc_device *rtc;
19 struct tx4939_rtc_reg __iomem *rtcreg; 19 struct tx4939_rtc_reg __iomem *rtcreg;
20 spinlock_t lock;
20}; 21};
21 22
22static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) 23static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev)
@@ -52,14 +53,14 @@ static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs)
52 buf[3] = secs >> 8; 53 buf[3] = secs >> 8;
53 buf[4] = secs >> 16; 54 buf[4] = secs >> 16;
54 buf[5] = secs >> 24; 55 buf[5] = secs >> 24;
55 spin_lock_irq(&pdata->rtc->irq_lock); 56 spin_lock_irq(&pdata->lock);
56 __raw_writel(0, &rtcreg->adr); 57 __raw_writel(0, &rtcreg->adr);
57 for (i = 0; i < 6; i++) 58 for (i = 0; i < 6; i++)
58 __raw_writel(buf[i], &rtcreg->dat); 59 __raw_writel(buf[i], &rtcreg->dat);
59 ret = tx4939_rtc_cmd(rtcreg, 60 ret = tx4939_rtc_cmd(rtcreg,
60 TX4939_RTCCTL_COMMAND_SETTIME | 61 TX4939_RTCCTL_COMMAND_SETTIME |
61 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); 62 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
62 spin_unlock_irq(&pdata->rtc->irq_lock); 63 spin_unlock_irq(&pdata->lock);
63 return ret; 64 return ret;
64} 65}
65 66
@@ -71,18 +72,18 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm)
71 unsigned long sec; 72 unsigned long sec;
72 unsigned char buf[6]; 73 unsigned char buf[6];
73 74
74 spin_lock_irq(&pdata->rtc->irq_lock); 75 spin_lock_irq(&pdata->lock);
75 ret = tx4939_rtc_cmd(rtcreg, 76 ret = tx4939_rtc_cmd(rtcreg,
76 TX4939_RTCCTL_COMMAND_GETTIME | 77 TX4939_RTCCTL_COMMAND_GETTIME |
77 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); 78 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
78 if (ret) { 79 if (ret) {
79 spin_unlock_irq(&pdata->rtc->irq_lock); 80 spin_unlock_irq(&pdata->lock);
80 return ret; 81 return ret;
81 } 82 }
82 __raw_writel(2, &rtcreg->adr); 83 __raw_writel(2, &rtcreg->adr);
83 for (i = 2; i < 6; i++) 84 for (i = 2; i < 6; i++)
84 buf[i] = __raw_readl(&rtcreg->dat); 85 buf[i] = __raw_readl(&rtcreg->dat);
85 spin_unlock_irq(&pdata->rtc->irq_lock); 86 spin_unlock_irq(&pdata->lock);
86 sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; 87 sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
87 rtc_time_to_tm(sec, tm); 88 rtc_time_to_tm(sec, tm);
88 return rtc_valid_tm(tm); 89 return rtc_valid_tm(tm);
@@ -110,13 +111,13 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
110 buf[3] = sec >> 8; 111 buf[3] = sec >> 8;
111 buf[4] = sec >> 16; 112 buf[4] = sec >> 16;
112 buf[5] = sec >> 24; 113 buf[5] = sec >> 24;
113 spin_lock_irq(&pdata->rtc->irq_lock); 114 spin_lock_irq(&pdata->lock);
114 __raw_writel(0, &rtcreg->adr); 115 __raw_writel(0, &rtcreg->adr);
115 for (i = 0; i < 6; i++) 116 for (i = 0; i < 6; i++)
116 __raw_writel(buf[i], &rtcreg->dat); 117 __raw_writel(buf[i], &rtcreg->dat);
117 ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | 118 ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM |
118 (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); 119 (alrm->enabled ? TX4939_RTCCTL_ALME : 0));
119 spin_unlock_irq(&pdata->rtc->irq_lock); 120 spin_unlock_irq(&pdata->lock);
120 return ret; 121 return ret;
121} 122}
122 123
@@ -129,12 +130,12 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
129 unsigned char buf[6]; 130 unsigned char buf[6];
130 u32 ctl; 131 u32 ctl;
131 132
132 spin_lock_irq(&pdata->rtc->irq_lock); 133 spin_lock_irq(&pdata->lock);
133 ret = tx4939_rtc_cmd(rtcreg, 134 ret = tx4939_rtc_cmd(rtcreg,
134 TX4939_RTCCTL_COMMAND_GETALARM | 135 TX4939_RTCCTL_COMMAND_GETALARM |
135 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); 136 (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
136 if (ret) { 137 if (ret) {
137 spin_unlock_irq(&pdata->rtc->irq_lock); 138 spin_unlock_irq(&pdata->lock);
138 return ret; 139 return ret;
139 } 140 }
140 __raw_writel(2, &rtcreg->adr); 141 __raw_writel(2, &rtcreg->adr);
@@ -143,7 +144,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
143 ctl = __raw_readl(&rtcreg->ctl); 144 ctl = __raw_readl(&rtcreg->ctl);
144 alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; 145 alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0;
145 alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; 146 alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0;
146 spin_unlock_irq(&pdata->rtc->irq_lock); 147 spin_unlock_irq(&pdata->lock);
147 sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; 148 sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
148 rtc_time_to_tm(sec, &alrm->time); 149 rtc_time_to_tm(sec, &alrm->time);
149 return rtc_valid_tm(&alrm->time); 150 return rtc_valid_tm(&alrm->time);
@@ -153,11 +154,11 @@ static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
153{ 154{
154 struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); 155 struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
155 156
156 spin_lock_irq(&pdata->rtc->irq_lock); 157 spin_lock_irq(&pdata->lock);
157 tx4939_rtc_cmd(pdata->rtcreg, 158 tx4939_rtc_cmd(pdata->rtcreg,
158 TX4939_RTCCTL_COMMAND_NOP | 159 TX4939_RTCCTL_COMMAND_NOP |
159 (enabled ? TX4939_RTCCTL_ALME : 0)); 160 (enabled ? TX4939_RTCCTL_ALME : 0));
160 spin_unlock_irq(&pdata->rtc->irq_lock); 161 spin_unlock_irq(&pdata->lock);
161 return 0; 162 return 0;
162} 163}
163 164
@@ -167,13 +168,14 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)
167 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; 168 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
168 unsigned long events = RTC_IRQF; 169 unsigned long events = RTC_IRQF;
169 170
170 spin_lock(&pdata->rtc->irq_lock); 171 spin_lock(&pdata->lock);
171 if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { 172 if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) {
172 events |= RTC_AF; 173 events |= RTC_AF;
173 tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); 174 tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);
174 } 175 }
175 spin_unlock(&pdata->rtc->irq_lock); 176 spin_unlock(&pdata->lock);
176 rtc_update_irq(pdata->rtc, 1, events); 177 if (likely(pdata->rtc))
178 rtc_update_irq(pdata->rtc, 1, events);
177 return IRQ_HANDLED; 179 return IRQ_HANDLED;
178} 180}
179 181
@@ -194,13 +196,13 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
194 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; 196 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
195 ssize_t count; 197 ssize_t count;
196 198
197 spin_lock_irq(&pdata->rtc->irq_lock); 199 spin_lock_irq(&pdata->lock);
198 for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; 200 for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
199 count++, size--) { 201 count++, size--) {
200 __raw_writel(pos++, &rtcreg->adr); 202 __raw_writel(pos++, &rtcreg->adr);
201 *buf++ = __raw_readl(&rtcreg->dat); 203 *buf++ = __raw_readl(&rtcreg->dat);
202 } 204 }
203 spin_unlock_irq(&pdata->rtc->irq_lock); 205 spin_unlock_irq(&pdata->lock);
204 return count; 206 return count;
205} 207}
206 208
@@ -213,13 +215,13 @@ static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj,
213 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; 215 struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
214 ssize_t count; 216 ssize_t count;
215 217
216 spin_lock_irq(&pdata->rtc->irq_lock); 218 spin_lock_irq(&pdata->lock);
217 for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; 219 for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
218 count++, size--) { 220 count++, size--) {
219 __raw_writel(pos++, &rtcreg->adr); 221 __raw_writel(pos++, &rtcreg->adr);
220 __raw_writel(*buf++, &rtcreg->dat); 222 __raw_writel(*buf++, &rtcreg->dat);
221 } 223 }
222 spin_unlock_irq(&pdata->rtc->irq_lock); 224 spin_unlock_irq(&pdata->lock);
223 return count; 225 return count;
224} 226}
225 227
@@ -259,6 +261,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
259 if (!pdata->rtcreg) 261 if (!pdata->rtcreg)
260 return -EBUSY; 262 return -EBUSY;
261 263
264 spin_lock_init(&pdata->lock);
262 tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); 265 tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
263 if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, 266 if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
264 IRQF_DISABLED, pdev->name, &pdev->dev) < 0) 267 IRQF_DISABLED, pdev->name, &pdev->dev) < 0)
@@ -277,14 +280,12 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
277static int __exit tx4939_rtc_remove(struct platform_device *pdev) 280static int __exit tx4939_rtc_remove(struct platform_device *pdev)
278{ 281{
279 struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); 282 struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev);
280 struct rtc_device *rtc = pdata->rtc;
281 283
282 spin_lock_irq(&rtc->irq_lock);
283 tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
284 spin_unlock_irq(&rtc->irq_lock);
285 sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); 284 sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
286 rtc_device_unregister(rtc); 285 rtc_device_unregister(pdata->rtc);
287 platform_set_drvdata(pdev, NULL); 286 spin_lock_irq(&pdata->lock);
287 tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
288 spin_unlock_irq(&pdata->lock);
288 return 0; 289 return 0;
289} 290}
290 291