Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-linus-clk' of git://ftp.arm.linux.org.uk/~rmk/linux-arm

Pull clkdev updates from Russell King:
"This series addresses some breakage in clkdev caused by a previous
patch set from the clk tree which introduced per-user clk structures.
This basically renamed the existing 'struct clk' to 'struct clk_hw',
and introduced a new 'struct clk'.

This change will break anyone using clk_add_alias() with the common
clk code enabled. Thankfully, the intersection of users of
clk_add_alias() and those using the common clk code is practically
zero, but this is something which should be fixed to keep the code
sane.

The problem is that clk_add_alias() does this:

r = clk_get(...);
l = clkdev_alloc(r, ...);
clk_put(...);

which causes the alias to store a pointer to 'r', which has been
freed.

The original patch set tried to work around this problem incorrectly -
at clk_get() time, it tried to convert the struct clk to a struct
clk_hw, and then creating a new struct clk from that. Clearly, if the
original struct clk has been freed, then we have a use-after-free bug.

We have other places in the tree which do something similar, so this
series also addresses those locations too.

This series addresses this problem by converting clkdev to store and
use the clk_hw pointer. This allows clk_get() to only have to create
it's per-user struct clk from the clk_hw. We can also get to the
desired clk_hw at clk_add_alias() or clk lookup creation time, when
the struct clk is "alive".

We also perform some cleanups of the code:

- replacing looped calls to clkdev_add() with clkdev_add_table()

- replacing open-coded lookup allocation (which should have been
using clkdev_alloc()) and subsequent clkdev_add() with
clkdev_create()

- replacing open-coded clk_add_alias() with clk_add_alias()"

* 'for-linus-clk' of git://ftp.arm.linux.org.uk/~rmk/linux-arm:
clk: s2mps11: use clkdev_create()
ASoC: migor: use clkdev_create()
ARM: omap2: use clkdev_add_alias()
ARM: omap2: use clkdev_create()
ARM: orion: use clkdev_create()
ARM: lpc32xx: convert to use clkdev_add_table()
SH: use clkdev_add_table()
clkdev: add clkdev_create() helper
clkdev: const-ify connection id to clk_add_alias()
clkdev: get rid of redundant clk_add_alias() prototype in linux/clk.h
clkdev: drop __init from clkdev_add_table()
clk: update clk API documentation to clarify clk_round_rate()
clkdev: use clk_hw internally

+108 -87
+1
arch/arm/mach-davinci/da850.c
··· 11 11 * is licensed "as is" without any warranty of any kind, whether express 12 12 * or implied. 13 13 */ 14 + #include <linux/clkdev.h> 14 15 #include <linux/gpio.h> 15 16 #include <linux/init.h> 16 17 #include <linux/clk.h>
+1 -4
arch/arm/mach-lpc32xx/clock.c
··· 1238 1238 1239 1239 static int __init clk_init(void) 1240 1240 { 1241 - int i; 1242 - 1243 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 1244 - clkdev_add(&lookups[i]); 1241 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 1245 1242 1246 1243 /* 1247 1244 * Setup muxed SYSCLK for HCLK PLL base -this selects the
+1 -1
arch/arm/mach-omap1/board-nokia770.c
··· 7 7 * it under the terms of the GNU General Public License version 2 as 8 8 * published by the Free Software Foundation. 9 9 */ 10 + #include <linux/clkdev.h> 10 11 #include <linux/irq.h> 11 12 #include <linux/gpio.h> 12 13 #include <linux/kernel.h> ··· 15 14 #include <linux/mutex.h> 16 15 #include <linux/platform_device.h> 17 16 #include <linux/input.h> 18 - #include <linux/clk.h> 19 17 #include <linux/omapfb.h> 20 18 21 19 #include <linux/spi/spi.h>
+2 -10
arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
··· 232 232 struct clk_hw_omap *hw = NULL; 233 233 struct clk *clk; 234 234 const char *parent_name = "mpu_ck"; 235 - struct clk_lookup *lookup = NULL; 236 235 237 236 omap2xxx_clkt_vps_late_init(); 238 237 omap2xxx_clkt_vps_check_bootloader_rates(); 239 238 240 239 hw = kzalloc(sizeof(*hw), GFP_KERNEL); 241 - lookup = kzalloc(sizeof(*lookup), GFP_KERNEL); 242 - if (!hw || !lookup) 240 + if (!hw) 243 241 goto cleanup; 244 242 init.name = "virt_prcm_set"; 245 243 init.ops = &virt_prcm_set_ops; ··· 247 249 hw->hw.init = &init; 248 250 249 251 clk = clk_register(NULL, &hw->hw); 250 - 251 - lookup->dev_id = NULL; 252 - lookup->con_id = "cpufreq_ck"; 253 - lookup->clk = clk; 254 - 255 - clkdev_add(lookup); 252 + clkdev_create(clk, "cpufreq_ck", NULL); 256 253 return; 257 254 cleanup: 258 255 kfree(hw); 259 - kfree(lookup); 260 256 } 261 257 #endif
+9 -15
arch/arm/mach-omap2/omap_device.c
··· 47 47 const char *clk_name) 48 48 { 49 49 struct clk *r; 50 - struct clk_lookup *l; 50 + int rc; 51 51 52 52 if (!clk_alias || !clk_name) 53 53 return; ··· 62 62 return; 63 63 } 64 64 65 - r = clk_get(NULL, clk_name); 66 - if (IS_ERR(r)) { 67 - dev_err(&od->pdev->dev, 68 - "clk_get for %s failed\n", clk_name); 69 - return; 65 + rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev), clk_name, NULL); 66 + if (rc) { 67 + if (rc == -ENODEV || rc == -ENOMEM) 68 + dev_err(&od->pdev->dev, 69 + "clkdev_alloc for %s failed\n", clk_alias); 70 + else 71 + dev_err(&od->pdev->dev, 72 + "clk_get for %s failed\n", clk_name); 70 73 } 71 - 72 - l = clkdev_alloc(r, clk_alias, dev_name(&od->pdev->dev)); 73 - if (!l) { 74 - dev_err(&od->pdev->dev, 75 - "clkdev_alloc for %s failed\n", clk_alias); 76 - return; 77 - } 78 - 79 - clkdev_add(l); 80 74 } 81 75 82 76 /**
+1
arch/arm/mach-pxa/eseries.c
··· 10 10 * 11 11 */ 12 12 13 + #include <linux/clkdev.h> 13 14 #include <linux/kernel.h> 14 15 #include <linux/init.h> 15 16 #include <linux/gpio.h>
+1
arch/arm/mach-pxa/lubbock.c
··· 11 11 * it under the terms of the GNU General Public License version 2 as 12 12 * published by the Free Software Foundation. 13 13 */ 14 + #include <linux/clkdev.h> 14 15 #include <linux/gpio.h> 15 16 #include <linux/gpio/machine.h> 16 17 #include <linux/module.h>
+1
arch/arm/mach-pxa/tosa.c
··· 12 12 * 13 13 */ 14 14 15 + #include <linux/clkdev.h> 15 16 #include <linux/kernel.h> 16 17 #include <linux/init.h> 17 18 #include <linux/platform_device.h>
+1 -5
arch/arm/plat-orion/common.c
··· 28 28 void __init orion_clkdev_add(const char *con_id, const char *dev_id, 29 29 struct clk *clk) 30 30 { 31 - struct clk_lookup *cl; 32 - 33 - cl = clkdev_alloc(clk, con_id, dev_id); 34 - if (cl) 35 - clkdev_add(cl); 31 + clkdev_create(clk, con_id, "%s", dev_id); 36 32 } 37 33 38 34 /* Create clkdev entries for all orion platforms except kirkwood.
+1 -2
arch/sh/kernel/cpu/sh4a/clock-sh7734.c
··· 246 246 for (i = 0; i < ARRAY_SIZE(main_clks); i++) 247 247 ret |= clk_register(main_clks[i]); 248 248 249 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 250 - clkdev_add(&lookups[i]); 249 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 251 250 252 251 if (!ret) 253 252 ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+2 -2
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
··· 141 141 142 142 for (i = 0; i < ARRAY_SIZE(clks); i++) 143 143 ret |= clk_register(clks[i]); 144 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 145 - clkdev_add(&lookups[i]); 144 + 145 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 146 146 147 147 if (!ret) 148 148 ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+2 -2
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
··· 164 164 165 165 for (i = 0; i < ARRAY_SIZE(clks); i++) 166 166 ret |= clk_register(clks[i]); 167 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 168 - clkdev_add(&lookups[i]); 167 + 168 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 169 169 170 170 if (!ret) 171 171 ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+2 -2
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
··· 179 179 180 180 for (i = 0; i < ARRAY_SIZE(clks); i++) 181 181 ret |= clk_register(clks[i]); 182 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 183 - clkdev_add(&lookups[i]); 182 + 183 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 184 184 185 185 if (!ret) 186 186 ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+2 -2
arch/sh/kernel/cpu/sh4a/clock-shx3.c
··· 138 138 139 139 for (i = 0; i < ARRAY_SIZE(clks); i++) 140 140 ret |= clk_register(clks[i]); 141 - for (i = 0; i < ARRAY_SIZE(lookups); i++) 142 - clkdev_add(&lookups[i]); 141 + 142 + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 143 143 144 144 if (!ret) 145 145 ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+1 -3
drivers/clk/clk-s2mps11.c
··· 242 242 goto err_reg; 243 243 } 244 244 245 - s2mps11_clk->lookup = clkdev_alloc(s2mps11_clk->clk, 245 + s2mps11_clk->lookup = clkdev_create(s2mps11_clk->clk, 246 246 s2mps11_name(s2mps11_clk), NULL); 247 247 if (!s2mps11_clk->lookup) { 248 248 ret = -ENOMEM; 249 249 goto err_lup; 250 250 } 251 - 252 - clkdev_add(s2mps11_clk->lookup); 253 251 } 254 252 255 253 for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
+60 -23
drivers/clk/clkdev.c
··· 177 177 if (!cl) 178 178 goto out; 179 179 180 - clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id); 180 + clk = __clk_create_clk(cl->clk_hw, dev_id, con_id); 181 181 if (IS_ERR(clk)) 182 182 goto out; 183 183 ··· 215 215 } 216 216 EXPORT_SYMBOL(clk_put); 217 217 218 - void clkdev_add(struct clk_lookup *cl) 218 + static void __clkdev_add(struct clk_lookup *cl) 219 219 { 220 220 mutex_lock(&clocks_mutex); 221 221 list_add_tail(&cl->node, &clocks); 222 222 mutex_unlock(&clocks_mutex); 223 223 } 224 + 225 + void clkdev_add(struct clk_lookup *cl) 226 + { 227 + if (!cl->clk_hw) 228 + cl->clk_hw = __clk_get_hw(cl->clk); 229 + __clkdev_add(cl); 230 + } 224 231 EXPORT_SYMBOL(clkdev_add); 225 232 226 - void __init clkdev_add_table(struct clk_lookup *cl, size_t num) 233 + void clkdev_add_table(struct clk_lookup *cl, size_t num) 227 234 { 228 235 mutex_lock(&clocks_mutex); 229 236 while (num--) { 237 + cl->clk_hw = __clk_get_hw(cl->clk); 230 238 list_add_tail(&cl->node, &clocks); 231 239 cl++; 232 240 } ··· 251 243 }; 252 244 253 245 static struct clk_lookup * __init_refok 254 - vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, 246 + vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, 255 247 va_list ap) 256 248 { 257 249 struct clk_lookup_alloc *cla; ··· 260 252 if (!cla) 261 253 return NULL; 262 254 263 - cla->cl.clk = clk; 255 + cla->cl.clk_hw = hw; 264 256 if (con_id) { 265 257 strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); 266 258 cla->cl.con_id = cla->con_id; ··· 274 266 return &cla->cl; 275 267 } 276 268 269 + static struct clk_lookup * 270 + vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt, 271 + va_list ap) 272 + { 273 + struct clk_lookup *cl; 274 + 275 + cl = vclkdev_alloc(hw, con_id, dev_fmt, ap); 276 + if (cl) 277 + __clkdev_add(cl); 278 + 279 + return cl; 280 + } 281 + 277 282 struct clk_lookup * __init_refok 278 283 clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 279 284 { ··· 294 273 va_list ap; 295 274 296 275 va_start(ap, dev_fmt); 297 - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); 276 + cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap); 298 277 va_end(ap); 299 278 300 279 return cl; 301 280 } 302 281 EXPORT_SYMBOL(clkdev_alloc); 303 282 304 - int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, 305 - struct device *dev) 283 + /** 284 + * clkdev_create - allocate and add a clkdev lookup structure 285 + * @clk: struct clk to associate with all clk_lookups 286 + * @con_id: connection ID string on device 287 + * @dev_fmt: format string describing device name 288 + * 289 + * Returns a clk_lookup structure, which can be later unregistered and 290 + * freed. 291 + */ 292 + struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id, 293 + const char *dev_fmt, ...) 306 294 { 307 - struct clk *r = clk_get(dev, id); 295 + struct clk_lookup *cl; 296 + va_list ap; 297 + 298 + va_start(ap, dev_fmt); 299 + cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap); 300 + va_end(ap); 301 + 302 + return cl; 303 + } 304 + EXPORT_SYMBOL_GPL(clkdev_create); 305 + 306 + int clk_add_alias(const char *alias, const char *alias_dev_name, 307 + const char *con_id, struct device *dev) 308 + { 309 + struct clk *r = clk_get(dev, con_id); 308 310 struct clk_lookup *l; 309 311 310 312 if (IS_ERR(r)) 311 313 return PTR_ERR(r); 312 314 313 - l = clkdev_alloc(r, alias, alias_dev_name); 315 + l = clkdev_create(r, alias, "%s", alias_dev_name); 314 316 clk_put(r); 315 - if (!l) 316 - return -ENODEV; 317 - clkdev_add(l); 318 - return 0; 317 + 318 + return l ? 0 : -ENODEV; 319 319 } 320 320 EXPORT_SYMBOL(clk_add_alias); 321 321 ··· 376 334 return PTR_ERR(clk); 377 335 378 336 va_start(ap, dev_fmt); 379 - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); 337 + cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap); 380 338 va_end(ap); 381 339 382 - if (!cl) 383 - return -ENOMEM; 384 - 385 - clkdev_add(cl); 386 - 387 - return 0; 340 + return cl ? 0 : -ENOMEM; 388 341 } 389 342 EXPORT_SYMBOL(clk_register_clkdev); 390 343 ··· 402 365 return PTR_ERR(clk); 403 366 404 367 for (i = 0; i < num; i++, cl++) { 405 - cl->clk = clk; 406 - clkdev_add(cl); 368 + cl->clk_hw = __clk_get_hw(clk); 369 + __clkdev_add(cl); 407 370 } 408 371 409 372 return 0;
+14 -13
include/linux/clk.h
··· 306 306 * @clk: clock source 307 307 * @rate: desired clock rate in Hz 308 308 * 309 + * This answers the question "if I were to pass @rate to clk_set_rate(), 310 + * what clock rate would I end up with?" without changing the hardware 311 + * in any way. In other words: 312 + * 313 + * rate = clk_round_rate(clk, r); 314 + * 315 + * and: 316 + * 317 + * clk_set_rate(clk, r); 318 + * rate = clk_get_rate(clk); 319 + * 320 + * are equivalent except the former does not modify the clock hardware 321 + * in any way. 322 + * 309 323 * Returns rounded clock rate in Hz, or negative errno. 310 324 */ 311 325 long clk_round_rate(struct clk *clk, unsigned long rate); ··· 484 470 clk_disable(clk); 485 471 clk_unprepare(clk); 486 472 } 487 - 488 - /** 489 - * clk_add_alias - add a new clock alias 490 - * @alias: name for clock alias 491 - * @alias_dev_name: device name 492 - * @id: platform specific clock name 493 - * @dev: device 494 - * 495 - * Allows using generic clock names for drivers by adding a new alias. 496 - * Assumes clkdev, see clkdev.h for more info. 497 - */ 498 - int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, 499 - struct device *dev); 500 473 501 474 struct device_node; 502 475 struct of_phandle_args;
+5 -1
include/linux/clkdev.h
··· 22 22 const char *dev_id; 23 23 const char *con_id; 24 24 struct clk *clk; 25 + struct clk_hw *clk_hw; 25 26 }; 26 27 27 28 #define CLKDEV_INIT(d, n, c) \ ··· 38 37 void clkdev_add(struct clk_lookup *cl); 39 38 void clkdev_drop(struct clk_lookup *cl); 40 39 40 + struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id, 41 + const char *dev_fmt, ...); 42 + 41 43 void clkdev_add_table(struct clk_lookup *, size_t); 42 - int clk_add_alias(const char *, const char *, char *, struct device *); 44 + int clk_add_alias(const char *, const char *, const char *, struct device *); 43 45 44 46 int clk_register_clkdev(struct clk *, const char *, const char *, ...); 45 47 int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t);
+1 -2
sound/soc/sh/migor.c
··· 162 162 if (ret < 0) 163 163 return ret; 164 164 165 - siumckb_lookup = clkdev_alloc(&siumckb_clk, "siumckb_clk", NULL); 165 + siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL); 166 166 if (!siumckb_lookup) { 167 167 ret = -ENOMEM; 168 168 goto eclkdevalloc; 169 169 } 170 - clkdev_add(siumckb_lookup); 171 170 172 171 /* Port number used on this machine: port B */ 173 172 migor_snd_device = platform_device_alloc("soc-audio", 1);