diff options
author | Dave Airlie <airlied@gmail.com> | 2012-08-09 15:00:15 +1000 |
---|---|---|
committer | Dave Airlie <airlied@gmail.com> | 2012-08-10 20:31:37 +1000 |
commit | 9830605d4c070b16ec5c24a75503877cc7698409 (patch) | |
tree | e99385fa8c9d9c1ab16bcb8a996959de9f4aa05d /drivers/gpu/drm/mgag200 | |
parent | f7b83b908fbecadefa73c0d76b9c719d09c1d96d (diff) | |
download | linux-9830605d4c070b16ec5c24a75503877cc7698409.tar.gz linux-9830605d4c070b16ec5c24a75503877cc7698409.tar.bz2 linux-9830605d4c070b16ec5c24a75503877cc7698409.zip |
drm/mgag200: fix G200ER pll picking algorithm
The original code was misported from the X driver,
a) an int went to unsigned int, breaking the downward counting testm code
b) the port did the vco/computed clock bits completely wrong.
This fixes an infinite loop on modprobe on some Dell servers with the G200ER
chipset variant.
Found in internal testing.
Cc: stable@vger.kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/mgag200')
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mode.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index a4d7c500c97b..b69642d5d850 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -468,10 +468,11 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; - unsigned int testr, testn, testm, testo; + int testr, testn, testm, testo; unsigned int p, m, n; - unsigned int computed; + unsigned int computed, vco; int tmp; + const unsigned int m_div_val[] = { 1, 2, 4, 8 }; m = n = p = 0; vcomax = 1488000; @@ -490,12 +491,13 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) if (delta == 0) break; for (testo = 5; testo < 33; testo++) { - computed = pllreffreq * (testn + 1) / + vco = pllreffreq * (testn + 1) / (testr + 1); - if (computed < vcomin) + if (vco < vcomin) continue; - if (computed > vcomax) + if (vco > vcomax) continue; + computed = vco / (m_div_val[testm] * (testo + 1)); if (computed > clock) tmpdelta = computed - clock; else |