diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2017-12-21 11:30:54 -0500 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2017-12-28 18:16:04 -0500 |
commit | 12a26c298d2a8b1cab498533fa65198e49e3afd3 (patch) | |
tree | 131818a7e5b13dbb5d8556017ff06354415d097e /drivers | |
parent | 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff) |
clk: divider: fix incorrect usage of container_of
divider_recalc_rate() is an helper function used by clock divider of
different types, so the structure containing the 'hw' pointer is not
always a 'struct clk_divider'
At the following line:
> div = _get_div(table, val, flags, divider->width);
in several cases, the value of 'divider->width' is garbage as the actual
structure behind this memory is not a 'struct clk_divider'
Fortunately, this width value is used by _get_val() only when
CLK_DIVIDER_MAX_AT_ZERO flag is set. This has never been the case so
far when the structure is not a 'struct clk_divider'. This is probably
why we did not notice this bug before
Fixes: afe76c8fd030 ("clk: allow a clk divider with max divisor when zero")
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Sylvain Lemieux <slemieux.tyco@gmail.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk-divider.c | 7 | ||||
-rw-r--r-- | drivers/clk/hisilicon/clkdivider-hi6220.c | 2 | ||||
-rw-r--r-- | drivers/clk/nxp/clk-lpc32xx.c | 2 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-regmap-divider.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_div.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ac100.c | 6 |
7 files changed, 12 insertions, 11 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 4ed516cb7276..b49942b9fe50 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -118,12 +118,11 @@ static unsigned int _get_val(const struct clk_div_table *table, | |||
118 | unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, | 118 | unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, |
119 | unsigned int val, | 119 | unsigned int val, |
120 | const struct clk_div_table *table, | 120 | const struct clk_div_table *table, |
121 | unsigned long flags) | 121 | unsigned long flags, unsigned long width) |
122 | { | 122 | { |
123 | struct clk_divider *divider = to_clk_divider(hw); | ||
124 | unsigned int div; | 123 | unsigned int div; |
125 | 124 | ||
126 | div = _get_div(table, val, flags, divider->width); | 125 | div = _get_div(table, val, flags, width); |
127 | if (!div) { | 126 | if (!div) { |
128 | WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), | 127 | WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), |
129 | "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", | 128 | "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", |
@@ -145,7 +144,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
145 | val &= div_mask(divider->width); | 144 | val &= div_mask(divider->width); |
146 | 145 | ||
147 | return divider_recalc_rate(hw, parent_rate, val, divider->table, | 146 | return divider_recalc_rate(hw, parent_rate, val, divider->table, |
148 | divider->flags); | 147 | divider->flags, divider->width); |
149 | } | 148 | } |
150 | 149 | ||
151 | static bool _is_valid_table_div(const struct clk_div_table *table, | 150 | static bool _is_valid_table_div(const struct clk_div_table *table, |
diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index a1c1f684ad58..9f46cf9dcc65 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c | |||
@@ -56,7 +56,7 @@ static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw, | |||
56 | val &= div_mask(dclk->width); | 56 | val &= div_mask(dclk->width); |
57 | 57 | ||
58 | return divider_recalc_rate(hw, parent_rate, val, dclk->table, | 58 | return divider_recalc_rate(hw, parent_rate, val, dclk->table, |
59 | CLK_DIVIDER_ROUND_CLOSEST); | 59 | CLK_DIVIDER_ROUND_CLOSEST, dclk->width); |
60 | } | 60 | } |
61 | 61 | ||
62 | static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, | 62 | static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, |
diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 7b359afd620e..a6438f50e6db 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c | |||
@@ -956,7 +956,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | |||
956 | val &= div_mask(divider->width); | 956 | val &= div_mask(divider->width); |
957 | 957 | ||
958 | return divider_recalc_rate(hw, parent_rate, val, divider->table, | 958 | return divider_recalc_rate(hw, parent_rate, val, divider->table, |
959 | divider->flags); | 959 | divider->flags, divider->width); |
960 | } | 960 | } |
961 | 961 | ||
962 | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | 962 | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 53484912301e..928fcc16ee27 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c | |||
@@ -59,7 +59,7 @@ static unsigned long div_recalc_rate(struct clk_hw *hw, | |||
59 | div &= BIT(divider->width) - 1; | 59 | div &= BIT(divider->width) - 1; |
60 | 60 | ||
61 | return divider_recalc_rate(hw, parent_rate, div, NULL, | 61 | return divider_recalc_rate(hw, parent_rate, div, NULL, |
62 | CLK_DIVIDER_ROUND_CLOSEST); | 62 | CLK_DIVIDER_ROUND_CLOSEST, divider->width); |
63 | } | 63 | } |
64 | 64 | ||
65 | const struct clk_ops clk_regmap_div_ops = { | 65 | const struct clk_ops clk_regmap_div_ops = { |
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index baa3cf96507b..302a18efd39f 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c | |||
@@ -71,7 +71,7 @@ static unsigned long ccu_div_recalc_rate(struct clk_hw *hw, | |||
71 | parent_rate); | 71 | parent_rate); |
72 | 72 | ||
73 | val = divider_recalc_rate(hw, parent_rate, val, cd->div.table, | 73 | val = divider_recalc_rate(hw, parent_rate, val, cd->div.table, |
74 | cd->div.flags); | 74 | cd->div.flags, cd->div.width); |
75 | 75 | ||
76 | if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) | 76 | if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) |
77 | val /= cd->fixed_post_div; | 77 | val /= cd->fixed_post_div; |
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c index fe15aa64086f..71fe60e5f01f 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c | |||
@@ -698,7 +698,7 @@ static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw *hw, | |||
698 | val &= div_mask(width); | 698 | val &= div_mask(width); |
699 | 699 | ||
700 | return divider_recalc_rate(hw, parent_rate, val, NULL, | 700 | return divider_recalc_rate(hw, parent_rate, val, NULL, |
701 | postdiv->flags); | 701 | postdiv->flags, width); |
702 | } | 702 | } |
703 | 703 | ||
704 | static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw, | 704 | static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw, |
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 9e336184491c..0282ccc6181c 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c | |||
@@ -137,13 +137,15 @@ static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw, | |||
137 | div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) & | 137 | div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) & |
138 | ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1); | 138 | ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1); |
139 | prate = divider_recalc_rate(hw, prate, div, | 139 | prate = divider_recalc_rate(hw, prate, div, |
140 | ac100_clkout_prediv, 0); | 140 | ac100_clkout_prediv, 0, |
141 | AC100_CLKOUT_PRE_DIV_WIDTH); | ||
141 | } | 142 | } |
142 | 143 | ||
143 | div = (reg >> AC100_CLKOUT_DIV_SHIFT) & | 144 | div = (reg >> AC100_CLKOUT_DIV_SHIFT) & |
144 | (BIT(AC100_CLKOUT_DIV_WIDTH) - 1); | 145 | (BIT(AC100_CLKOUT_DIV_WIDTH) - 1); |
145 | return divider_recalc_rate(hw, prate, div, NULL, | 146 | return divider_recalc_rate(hw, prate, div, NULL, |
146 | CLK_DIVIDER_POWER_OF_TWO); | 147 | CLK_DIVIDER_POWER_OF_TWO, |
148 | AC100_CLKOUT_DIV_WIDTH); | ||
147 | } | 149 | } |
148 | 150 | ||
149 | static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate, | 151 | static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate, |