aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/cs5535-mfgpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/cs5535-mfgpt.c')
-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..effd8c6b2b94 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