From 9830605d4c070b16ec5c24a75503877cc7698409 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 9 Aug 2012 15:00:15 +1000 Subject: [PATCH] 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 --- drivers/gpu/drm/mgag200/mgag200_mode.c | 12 +++++++----- 1 file 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 -- 2.20.1