clk: at91: usb: rate calculation fixes
Subsystems (2)
cover clk: at91: usb: rate calculation fixes
Hello,
Here are a few more fixes for the at91 usb clk driver.
These bugs are related to rate calculation, and have been reported by Andreas.
As this is not my first mistake in this rate calculation algorithm, I'd really like to have reviews/feedback on this fixes to avoid potential regressions.
Mike, when/if we agree on these fixes, can we make them go into one of the 3.18-rc cycle ?
Thanks,
Boris
Boris Brezillon (2):
clk: at91: usb: fix at91rm9200 round and set rate
clk: at91: usb: fix at91sam9x5 recalc, round and set rate
drivers/clk/at91/clk-usb.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-)
Signature · 1 line
1.9.1
PATCH 1/2 clk: at91: usb: fix at91rm9200 round and set rate
at91rm9200_clk_usb_set_rate might fail depending on the requested rate, because the parent_rate / rate remainder is not necessarily zero. Moreover, when rounding down the calculated rate we might alter the divisor calculation and end up with an invalid divisor.
To solve those problems, accept a non zero remainder, and always round division to the closest result.
--- drivers/clk/at91/clk-usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/clk/at91/clk-usb.c +3 -3
@@ -253,7 +253,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, tmp_parent_rate = rate * usb->divisors[i]; tmp_parent_rate =__clk_round_rate (parent, tmp_parent_rate); - tmprate = tmp_parent_rate / usb->divisors[i]; + tmprate =DIV_ROUND_CLOSEST (tmp_parent_rate, usb->divisors[i]);if (tmprate < rate) tmpdiff = rate - tmprate;else
@@ -281,10 +281,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,struct at91_pmc *pmc = usb->pmc;unsigned long div; -if (!rate || parent_rate % rate) +if (!rate)return -EINVAL ; - div = parent_rate / rate; + div =DIV_ROUND_CLOSEST (parent_rate, rate);for (i =0 ; i <RM9200_USB_DIV_TAB_SIZE ; i++) {if (usb->divisors[i] == div) {
Signature · 1 line
1.9.1
PATCH 1/2 clk: at91: usb: fix at91rm9200 round and set rate
Hello!
Just confirming this exact patch fixes the problem I was running into.
Quoted 10 lines · Boris Brezillon
at91rm9200_clk_usb_set_ratemight fail depending on the requested rate, because theparent_rate/ rate remainder is not necessarily zero. Moreover, when rounding down the calculated rate we might alter the divisor calculation and end up with an invalid divisor.To solve those problems, accept a non zero remainder, and always round division to the closest result.
Signed-off-by Boris Brezillon <[email protected]>Reported-by Andreas Henriksson <[email protected]>
Quoted 33 lines
--- drivers/clk/at91/clk-usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)drivers/clk/at91/clk-usb.c +3
-3@@ -253,7 +253,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, tmp_parent_rate = rate * usb->divisors[i]; tmp_parent_rate =__clk_round_rate (parent, tmp_parent_rate); - tmprate = tmp_parent_rate / usb->divisors[i]; + tmprate =DIV_ROUND_CLOSEST (tmp_parent_rate, usb->divisors[i]);if (tmprate < rate) tmpdiff = rate - tmprate;else @@ -281,10 +281,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,struct at91_pmc *pmc = usb->pmc;unsigned long div; -if (!rate || parent_rate % rate) +if (!rate)return -EINVAL ; - div = parent_rate / rate; + div =DIV_ROUND_CLOSEST (parent_rate, rate);for (i =0 ; i <RM9200_USB_DIV_TAB_SIZE ; i++) {if (usb->divisors[i] == div) {Signature · 1 line
1.9.1
PATCH 2/2 clk: at91: usb: fix at91sam9x5 recalc, round and set rate
In reply to Boris BrezillonFirst check for rate == 0 in set_rate and round_rate to avoid div by zero. Then, in order to get the closest rate, round all divisions to the closest result instead of rounding them down.
--- drivers/clk/at91/clk-usb.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
drivers/clk/at91/clk-usb.c +17 -12
@@ -52,7 +52,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, tmp =pmc_read (pmc,AT91_PMC_USB ); usbdiv = (tmp &AT91_PMC_OHCIUSBDIV ) >>SAM9X5_USB_DIV_SHIFT ; -return parent_rate / (usbdiv +1 ); + +return DIV_ROUND_CLOSEST (parent_rate, (usbdiv +1 )); } static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -62,19 +63,19 @@ static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,unsigned long bestrate;unsigned long tmp; +if (!rate) +return DIV_ROUND_CLOSEST (*parent_rate,SAM9X5_USB_MAX_DIV +1 ); +if (rate >= *parent_rate)return *parent_rate; - div = *parent_rate / rate; -if (div >=SAM9X5_USB_MAX_DIV ) -return *parent_rate / (SAM9X5_USB_MAX_DIV +1 ); + div =DIV_ROUND_CLOSEST (*parent_rate, rate); +if (div >SAM9X5_USB_MAX_DIV +1 ) + div =SAM9X5_USB_MAX_DIV +1 ; +else if (!div) + div =1 ; - bestrate = *parent_rate / div; - tmp = *parent_rate / (div +1 ); -if (bestrate - rate > rate - tmp) - bestrate = tmp; - -return bestrate; +return DIV_ROUND_CLOSEST (*parent_rate, div); }static int at91sam9x5_clk_usb_set_parent (struct clk_hw *hw,u8 index)
@@ -106,9 +107,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,u32 tmp;struct at91sam9x5_clk_usb *usb =to_at91sam9x5_clk_usb (hw);struct at91_pmc *pmc = usb->pmc; -unsigned long div = parent_rate / rate; +unsigned long div; -if (parent_rate % rate || div <1 || div >=SAM9X5_USB_MAX_DIV ) +if (!rate) +return -EINVAL ; + + div =DIV_ROUND_CLOSEST (parent_rate, rate); +if (div >SAM9X5_USB_MAX_DIV +1 || !div)return -EINVAL ; tmp =pmc_read (pmc,AT91_PMC_USB ) & ~AT91_PMC_OHCIUSBDIV ;
Signature · 1 line
1.9.1
PATCH 2/2 clk: at91: usb: fix at91sam9x5 recalc, round and set rate
Quoted 24 lines · Boris Brezillon
First check for rate == 0 in
set_rateandround_rateto avoid div by zero. Then, in order to get the closest rate, round all divisions to the closest result instead of rounding them down.Signed-off-by Boris Brezillon <[email protected]>--- drivers/clk/at91/clk-usb.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)drivers/clk/at91/clk-usb.c +2
-1@@ -52,7 +52,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, tmp =pmc_read (pmc,AT91_PMC_USB ); usbdiv = (tmp &AT91_PMC_OHCIUSBDIV ) >>SAM9X5_USB_DIV_SHIFT ; -return parent_rate / (usbdiv +1 ); + +return DIV_ROUND_CLOSEST (parent_rate, (usbdiv +1 )); } static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
drivers/clk/at91/clk-usb.c static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, · line 68
Quoted 6 lines
drivers/clk/at91/clk-usb.c +3
-0@@ -62,19 +63,19 @@ static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,unsigned long bestrate;unsigned long tmp; +if (!rate) +return DIV_ROUND_CLOSEST (*parent_rate,SAM9X5_USB_MAX_DIV +1 ); +
Maybe I'm missing something but I would return -EINVAL here.
drivers/clk/at91/clk-usb.c static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, · line 76
Quoted 11 lines
drivers/clk/at91/clk-usb.c +5
-3if (rate >= *parent_rate)return *parent_rate; - div = *parent_rate / rate; -if (div >=SAM9X5_USB_MAX_DIV ) -return *parent_rate / (SAM9X5_USB_MAX_DIV +1 ); + div =DIV_ROUND_CLOSEST (*parent_rate, rate); +if (div >SAM9X5_USB_MAX_DIV +1 ) + div =SAM9X5_USB_MAX_DIV +1 ; +else if (!div) + div =1 ;
In that case, you are also screwed, I would return -EINVAL.
Quoted 30 lines
drivers/clk/at91/clk-usb.c +7
-8- bestrate = *parent_rate / div; - tmp = *parent_rate / (div +1 ); -if (bestrate - rate > rate - tmp) - bestrate = tmp; - -return bestrate; +return DIV_ROUND_CLOSEST (*parent_rate, div); }static int at91sam9x5_clk_usb_set_parent (struct clk_hw *hw,u8 index)@@ -106,9 +107,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,u32 tmp;struct at91sam9x5_clk_usb *usb =to_at91sam9x5_clk_usb (hw);struct at91_pmc *pmc = usb->pmc; -unsigned long div = parent_rate / rate; +unsigned long div; -if (parent_rate % rate || div <1 || div >=SAM9X5_USB_MAX_DIV ) +if (!rate) +return -EINVAL ; + + div =DIV_ROUND_CLOSEST (parent_rate, rate); +if (div >SAM9X5_USB_MAX_DIV +1 || !div)return -EINVAL ; tmp =pmc_read (pmc,AT91_PMC_USB ) & ~AT91_PMC_OHCIUSBDIV ;Signature · 1 line
1.9.1
Signature · 3 lines
Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com
PATCH 2/2 clk: at91: usb: fix at91sam9x5 recalc, round and set rate
Quoted 28 lines · On Fri, 7 Nov 2014 18:51:39 +0100 Alexandre Belloni…
Quoted 27 lines · Boris Brezillon
First check for rate == 0 in
set_rateandround_rateto avoid div by zero. Then, in order to get the closest rate, round all divisions to the closest result instead of rounding them down.Signed-off-by Boris Brezillon <[email protected]>--- drivers/clk/at91/clk-usb.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)drivers/clk/at91/clk-usb.c +2
-1@@ -52,7 +52,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, tmp =pmc_read (pmc,AT91_PMC_USB ); usbdiv = (tmp &AT91_PMC_OHCIUSBDIV ) >>SAM9X5_USB_DIV_SHIFT ; -return parent_rate / (usbdiv +1 ); + +return DIV_ROUND_CLOSEST (parent_rate, (usbdiv +1 )); } static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,@@ -62,19 +63,19 @@ static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,unsigned long bestrate;unsigned long tmp;
Quoted 5 lines
drivers/clk/at91/clk-usb.c static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, · line 68
Quoted 3 lines
drivers/clk/at91/clk-usb.c +3
-0+if (!rate) +return DIV_ROUND_CLOSEST (*parent_rate,SAM9X5_USB_MAX_DIV +1 ); +Maybe I'm missing something but I would return
-EINVALhere.
That's what I did at first, but just realized maybe 0 is a valid request and we should try to be as close as possible to 0.
Anyway, I'm not really convinced we need that, so I can drop it.
Quoted 4 lines
Quoted 4 lines
drivers/clk/at91/clk-usb.c +0
-0if (rate >= *parent_rate)return *parent_rate;
Quoted 10 lines
drivers/clk/at91/clk-usb.c static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, · line 76
Quoted 8 lines
drivers/clk/at91/clk-usb.c +5
-3- div = *parent_rate / rate; -if (div >=SAM9X5_USB_MAX_DIV ) -return *parent_rate / (SAM9X5_USB_MAX_DIV +1 ); + div =DIV_ROUND_CLOSEST (*parent_rate, rate); +if (div >SAM9X5_USB_MAX_DIV +1 ) + div =SAM9X5_USB_MAX_DIV +1 ; +else if (!div) + div =1 ;In that case, you are also screwed, I would return
-EINVAL.
Well, actually that cannot happen, because I already tested rate >= *parent_rate.
I'll remove that line.
Signature · 3 lines
Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
cover clk: at91: usb: rate calculation fixes
In reply to Boris BrezillonOn 05/11/2014 10:33, Boris Brezillon :
Quoted 7 lines
Hello,
Here are a few more fixes for the at91 usb clk driver.
These bugs are related to rate calculation, and have been reported by Andreas.
Quoted 6 lines
As this is not my first mistake in this rate calculation algorithm, I'd really like to have reviews/feedback on this fixes to avoid potential regressions.
Mike, when/if we agree on these fixes, can we make them go into one of the 3.18-rc cycle ?
Can you give us a hint about the "stable tag" that would be good to add?
Bye,
Quoted 7 lines
Boris Brezillon (2):
clk: at91: usb: fix at91rm9200 round and set rate
clk: at91: usb: fix at91sam9x5 recalc, round and set ratedrivers/clk/at91/clk-usb.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-)
Signature · 1 line
Nicolas Ferre
cover clk: at91: usb: rate calculation fixes
Hi Nicolas,
Quoted 8 lines · On Wed, 5 Nov 2014 18:13:25 +0100 Nicolas Ferre <[email protected]> wrote:
On 05/11/2014 10:33, Boris Brezillon :
Quoted 7 lines
Hello,
Here are a few more fixes for the at91 usb clk driver.
These bugs are related to rate calculation, and have been reported by Andreas.
Quoted 8 lines
Quoted 6 lines
As this is not my first mistake in this rate calculation algorithm, I'd really like to have reviews/feedback on this fixes to avoid potential regressions.
Mike, when/if we agree on these fixes, can we make them go into one of the 3.18-rc cycle ?
Can you give us a hint about the "stable tag" that would be good to add?
None for the moment: these 2 patches apply on top of other patches that were merge in 3.18.
What we should do though is backport the set of usb fixes merged in 3.18 to 3.16/3.17 once 3.18 is out...
Regards,
Boris
Signature · 3 lines
Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
cover clk: at91: usb: rate calculation fixes
In reply to Boris BrezillonOn 05/11/2014 10:33, Boris Brezillon :
Quoted 7 lines
Hello,
Here are a few more fixes for the at91 usb clk driver.
These bugs are related to rate calculation, and have been reported by Andreas.
Quoted 6 lines
As this is not my first mistake in this rate calculation algorithm, I'd really like to have reviews/feedback on this fixes to avoid potential regressions.
Mike, when/if we agree on these fixes, can we make them go into one of the 3.18-rc cycle ?
With Alex modifications, you can add my:
To your next series.
Bye,
Quoted 7 lines
Boris Brezillon (2):
clk: at91: usb: fix at91rm9200 round and set rate
clk: at91: usb: fix at91sam9x5 recalc, round and set ratedrivers/clk/at91/clk-usb.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-)
Signature · 1 line
Nicolas Ferre
cover clk: at91: usb: rate calculation fixes
Quoting Nicolas Ferre (2014-11-13 02:59:35)
Quoted 12 lines
On 05/11/2014 10:33, Boris Brezillon :
Quoted 11 lines
Hello,
Here are a few more fixes for the at91 usb clk driver.
These bugs are related to rate calculation, and have been reported by Andreas.
As this is not my first mistake in this rate calculation algorithm, I'd really like to have reviews/feedback on this fixes to avoid potential regressions.
Quoted 6 lines
Quoted 2 lines
Mike, when/if we agree on these fixes, can we make them go into one of the 3.18-rc cycle ?
With Alex modifications, you can add my:
Acked-by Nicolas Ferre <[email protected]>
Yes, I'll take them in for the next -rc once V2 comes out.
Regards,
Mike
Quoted 17 lines
To your next series.
Bye,
Quoted 7 lines
Boris Brezillon (2):
clk: at91: usb: fix at91rm9200 round and set rate
clk: at91: usb: fix at91sam9x5 recalc, round and set ratedrivers/clk/at91/clk-usb.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-)Signature · 1 line
Nicolas Ferre