aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2013-03-30 15:48:16 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-01 15:29:52 -0400
commit945480b159aa0869bf5dadc07fdbae964882820b (patch)
treec17504b13e341abaca738a3ec5b0d4eb3f3d86c0 /drivers/misc
parent974857266aae29c371ac2313ab520616335caec9 (diff)
cs5535-mfgpt: Add another reset method
The CS5535/CS5536 MFGPT has no support to reset the device. The current method uses an undocumented bit but does not work on all devices. At least on my ALIX board it completely freezes the board. This new method tries to soft reset all timers by unconfiguring them. But this does not clear the RO setup register and therefore it has to be ignored while probing. Resetting the timers is not only needed on broken BIOSes also when kexec is used. Otherwise the new kernel will find preconfigured timers and odd things will happen. Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/cs5535-mfgpt.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 9858f36dad8b..6bdb3baf7bcf 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -24,8 +24,11 @@
24 24
25static int mfgpt_reset_timers; 25static int mfgpt_reset_timers;
26module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); 26module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
27MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; " 27MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; "
28 "required by some broken BIOSes (ie, TinyBIOS < 0.99)."); 28 "required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec "
29 "(1 = reset the MFGPT using an undocumented bit, "
30 "2 = perform a soft reset by unconfiguring all timers);
31 use what works best for you.");
29 32
30struct cs5535_mfgpt_timer { 33struct cs5535_mfgpt_timer {
31 struct cs5535_mfgpt_chip *chip; 34 struct cs5535_mfgpt_chip *chip;
@@ -256,6 +259,28 @@ static void reset_all_timers(void)
256} 259}
257 260
258/* 261/*
262 * This is another sledgehammer to reset all MFGPT timers.
263 * Instead of using the undocumented bit method it clears
264 * IRQ, NMI and RESET settings.
265 */
266static void soft_reset(void)
267{
268 int i;
269 struct cs5535_mfgpt_timer t;
270
271 for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
272 t.nr = i;
273
274 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0);
275 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0);
276 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0);
277 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0);
278 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0);
279 cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0);
280 }
281}
282
283/*
259 * Check whether any MFGPTs are available for the kernel to use. In most 284 * Check whether any MFGPTs are available for the kernel to use. In most
260 * cases, firmware that uses AMD's VSA code will claim all timers during 285 * cases, firmware that uses AMD's VSA code will claim all timers during
261 * bootup; we certainly don't want to take them if they're already in use. 286 * bootup; we certainly don't want to take them if they're already in use.
@@ -271,15 +296,17 @@ static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)
271 int i; 296 int i;
272 297
273 /* bios workaround */ 298 /* bios workaround */
274 if (mfgpt_reset_timers) 299 if (mfgpt_reset_timers == 1)
275 reset_all_timers(); 300 reset_all_timers();
301 else if (mfgpt_reset_timers == 2)
302 soft_reset();
276 303
277 /* just to be safe, protect this section w/ lock */ 304 /* just to be safe, protect this section w/ lock */
278 spin_lock_irqsave(&mfgpt->lock, flags); 305 spin_lock_irqsave(&mfgpt->lock, flags);
279 for (i = 0; i < MFGPT_MAX_TIMERS; i++) { 306 for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
280 timer.nr = i; 307 timer.nr = i;
281 val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP); 308 val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
282 if (!(val & MFGPT_SETUP_SETUP)) { 309 if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {
283 __set_bit(i, mfgpt->avail); 310 __set_bit(i, mfgpt->avail);
284 timers++; 311 timers++;
285 } 312 }
@@ -294,6 +321,12 @@ static int cs5535_mfgpt_probe(struct platform_device *pdev)
294 struct resource *res; 321 struct resource *res;
295 int err = -EIO, t; 322 int err = -EIO, t;
296 323
324 if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) {
325 dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n",
326 mfgpt_reset_timers);
327 goto done;
328 }
329
297 /* There are two ways to get the MFGPT base address; one is by 330 /* There are two ways to get the MFGPT base address; one is by
298 * fetching it from MSR_LBAR_MFGPT, the other is by reading the 331 * fetching it from MSR_LBAR_MFGPT, the other is by reading the
299 * PCI BAR info. The latter method is easier (especially across 332 * PCI BAR info. The latter method is easier (especially across