summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mgag200
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2012-08-09 15:00:15 +1000
committerDave Airlie <airlied@gmail.com>2012-08-10 20:31:37 +1000
commit9830605d4c070b16ec5c24a75503877cc7698409 (patch)
treee99385fa8c9d9c1ab16bcb8a996959de9f4aa05d /drivers/gpu/drm/mgag200
parentf7b83b908fbecadefa73c0d76b9c719d09c1d96d (diff)
downloadlinux-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.c12
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