From ce205541fb55d49fb7e97f61ac6c3bb0c7666a69 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 30 Mar 2013 20:48:16 +0100 Subject: [PATCH] --- yaml --- r: 363175 b: refs/heads/master c: 945480b159aa0869bf5dadc07fdbae964882820b h: refs/heads/master i: 363173: 706f2f40589c57326892ac8f8aa2f000b622589e 363171: 807bf8c89b08a58324c067da05da74bc404d5389 363167: 0a24984b0ba04febc6fc2181417bbc6ae275b6b1 v: v3 --- [refs] | 2 +- trunk/drivers/misc/cs5535-mfgpt.c | 41 ++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/[refs] b/[refs] index 3b0e5d009357..38fda193a98f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 974857266aae29c371ac2313ab520616335caec9 +refs/heads/master: 945480b159aa0869bf5dadc07fdbae964882820b diff --git a/trunk/drivers/misc/cs5535-mfgpt.c b/trunk/drivers/misc/cs5535-mfgpt.c index 9858f36dad8b..6bdb3baf7bcf 100644 --- a/trunk/drivers/misc/cs5535-mfgpt.c +++ b/trunk/drivers/misc/cs5535-mfgpt.c @@ -24,8 +24,11 @@ static int mfgpt_reset_timers; module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); -MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; " - "required by some broken BIOSes (ie, TinyBIOS < 0.99)."); +MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; " + "required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec " + "(1 = reset the MFGPT using an undocumented bit, " + "2 = perform a soft reset by unconfiguring all timers); + use what works best for you."); struct cs5535_mfgpt_timer { struct cs5535_mfgpt_chip *chip; @@ -255,6 +258,28 @@ static void reset_all_timers(void) wrmsr(MSR_MFGPT_SETUP, val, dummy); } +/* + * This is another sledgehammer to reset all MFGPT timers. + * Instead of using the undocumented bit method it clears + * IRQ, NMI and RESET settings. + */ +static void soft_reset(void) +{ + int i; + struct cs5535_mfgpt_timer t; + + for (i = 0; i < MFGPT_MAX_TIMERS; i++) { + t.nr = i; + + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0); + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0); + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0); + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0); + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0); + cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0); + } +} + /* * Check whether any MFGPTs are available for the kernel to use. In most * cases, firmware that uses AMD's VSA code will claim all timers during @@ -271,15 +296,17 @@ static int scan_timers(struct cs5535_mfgpt_chip *mfgpt) int i; /* bios workaround */ - if (mfgpt_reset_timers) + if (mfgpt_reset_timers == 1) reset_all_timers(); + else if (mfgpt_reset_timers == 2) + soft_reset(); /* just to be safe, protect this section w/ lock */ spin_lock_irqsave(&mfgpt->lock, flags); for (i = 0; i < MFGPT_MAX_TIMERS; i++) { timer.nr = i; val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP); - if (!(val & MFGPT_SETUP_SETUP)) { + if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) { __set_bit(i, mfgpt->avail); timers++; } @@ -294,6 +321,12 @@ static int cs5535_mfgpt_probe(struct platform_device *pdev) struct resource *res; int err = -EIO, t; + if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) { + dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n", + mfgpt_reset_timers); + goto done; + } + /* There are two ways to get the MFGPT base address; one is by * fetching it from MSR_LBAR_MFGPT, the other is by reading the * PCI BAR info. The latter method is easier (especially across