Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 363175
b: refs/heads/master
c: 945480b
h: refs/heads/master
i:
  363173: 706f2f4
  363171: 807bf8c
  363167: 0a24984
v: v3
  • Loading branch information
Richard Weinberger authored and Greg Kroah-Hartman committed Apr 1, 2013
1 parent ce30dfc commit ce20554
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 974857266aae29c371ac2313ab520616335caec9
refs/heads/master: 945480b159aa0869bf5dadc07fdbae964882820b
41 changes: 37 additions & 4 deletions trunk/drivers/misc/cs5535-mfgpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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++;
}
Expand All @@ -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
Expand Down

0 comments on commit ce20554

Please sign in to comment.