diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-28 12:15:31 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-28 12:15:31 -0500 |
| commit | d5a74afd08738af84d51c353ac3ac200b06c51d7 (patch) | |
| tree | 1586e0f21fbd2bbbff42c6ff99837bf8ff4cf313 | |
| parent | 586c6e7013c8cbb8c91aaa6568ec349b1dc2c691 (diff) | |
| parent | 435792d93410f008120c4dbab148019a3cc31dbc (diff) | |
Merge tag 'iommu-fixes-v3.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
IOMMU fixes for Linux 3.3-rc5
All the fixes are for the OMAP IOMMU driver. The first patch is the
biggest one. It fixes the calls of the function omap_find_iovm_area() in
the omap-iommu-debug module which expects a 'struct device' parameter
since commit fabdbca instead of an omap_iommu handle. The
omap-iommu-debug code still passed the handle to the function which
caused a crash.
The second patch fixes a NULL pointer dereference in the OMAP code and
the third patch makes sure that the omap-iommu is initialized before the
omap-isp driver, which relies on the iommu. The last patch is only a
workaround until defered probing is implemented.
* tag 'iommu-fixes-v3.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
ARM: OMAP: make iommu subsys_initcall to fix builtin omap3isp
iommu/omap: fix NULL pointer dereference
iommu/omap: fix erroneous omap-iommu-debug API calls
| -rw-r--r-- | arch/arm/mach-omap2/mailbox.c | 3 | ||||
| -rw-r--r-- | drivers/iommu/omap-iommu-debug.c | 59 | ||||
| -rw-r--r-- | drivers/iommu/omap-iommu.c | 3 |
3 files changed, 49 insertions, 16 deletions
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 609ea2ded7e3..a6db1e4f7b6e 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c | |||
| @@ -412,7 +412,8 @@ static void __exit omap2_mbox_exit(void) | |||
| 412 | platform_driver_unregister(&omap2_mbox_driver); | 412 | platform_driver_unregister(&omap2_mbox_driver); |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | module_init(omap2_mbox_init); | 415 | /* must be ready before omap3isp is probed */ |
| 416 | subsys_initcall(omap2_mbox_init); | ||
| 416 | module_exit(omap2_mbox_exit); | 417 | module_exit(omap2_mbox_exit); |
| 417 | 418 | ||
| 418 | MODULE_LICENSE("GPL v2"); | 419 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index 288da5c1499d..103dbd92e256 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c | |||
| @@ -44,7 +44,8 @@ static ssize_t debug_read_ver(struct file *file, char __user *userbuf, | |||
| 44 | static ssize_t debug_read_regs(struct file *file, char __user *userbuf, | 44 | static ssize_t debug_read_regs(struct file *file, char __user *userbuf, |
| 45 | size_t count, loff_t *ppos) | 45 | size_t count, loff_t *ppos) |
| 46 | { | 46 | { |
| 47 | struct omap_iommu *obj = file->private_data; | 47 | struct device *dev = file->private_data; |
| 48 | struct omap_iommu *obj = dev_to_omap_iommu(dev); | ||
| 48 | char *p, *buf; | 49 | char *p, *buf; |
| 49 | ssize_t bytes; | 50 | ssize_t bytes; |
| 50 | 51 | ||
| @@ -67,7 +68,8 @@ static ssize_t debug_read_regs(struct file *file, char __user *userbuf, | |||
| 67 | static ssize_t debug_read_tlb(struct file *file, char __user *userbuf, | 68 | static ssize_t debug_read_tlb(struct file *file, char __user *userbuf, |
| 68 | size_t count, loff_t *ppos) | 69 | size_t count, loff_t *ppos) |
| 69 | { | 70 | { |
| 70 | struct omap_iommu *obj = file->private_data; | 71 | struct device *dev = file->private_data; |
| 72 | struct omap_iommu *obj = dev_to_omap_iommu(dev); | ||
| 71 | char *p, *buf; | 73 | char *p, *buf; |
| 72 | ssize_t bytes, rest; | 74 | ssize_t bytes, rest; |
| 73 | 75 | ||
| @@ -97,7 +99,8 @@ static ssize_t debug_write_pagetable(struct file *file, | |||
| 97 | struct iotlb_entry e; | 99 | struct iotlb_entry e; |
| 98 | struct cr_regs cr; | 100 | struct cr_regs cr; |
| 99 | int err; | 101 | int err; |
| 100 | struct omap_iommu *obj = file->private_data; | 102 | struct device *dev = file->private_data; |
| 103 | struct omap_iommu *obj = dev_to_omap_iommu(dev); | ||
| 101 | char buf[MAXCOLUMN], *p = buf; | 104 | char buf[MAXCOLUMN], *p = buf; |
| 102 | 105 | ||
| 103 | count = min(count, sizeof(buf)); | 106 | count = min(count, sizeof(buf)); |
| @@ -184,7 +187,8 @@ out: | |||
| 184 | static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf, | 187 | static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf, |
| 185 | size_t count, loff_t *ppos) | 188 | size_t count, loff_t *ppos) |
| 186 | { | 189 | { |
| 187 | struct omap_iommu *obj = file->private_data; | 190 | struct device *dev = file->private_data; |
| 191 | struct omap_iommu *obj = dev_to_omap_iommu(dev); | ||
| 188 | char *p, *buf; | 192 | char *p, *buf; |
| 189 | size_t bytes; | 193 | size_t bytes; |
| 190 | 194 | ||
| @@ -212,7 +216,8 @@ static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf, | |||
| 212 | static ssize_t debug_read_mmap(struct file *file, char __user *userbuf, | 216 | static ssize_t debug_read_mmap(struct file *file, char __user *userbuf, |
| 213 | size_t count, loff_t *ppos) | 217 | size_t count, loff_t *ppos) |
| 214 | { | 218 | { |
| 215 | struct omap_iommu *obj = file->private_data; | 219 | struct device *dev = file->private_data; |
| 220 | struct omap_iommu *obj = dev_to_omap_iommu(dev); | ||
| 216 | char *p, *buf; | 221 | char *p, *buf; |
| 217 | struct iovm_struct *tmp; | 222 | struct iovm_struct *tmp; |
| 218 | int uninitialized_var(i); | 223 | int uninitialized_var(i); |
| @@ -254,7 +259,7 @@ static ssize_t debug_read_mmap(struct file *file, char __user *userbuf, | |||
| 254 | static ssize_t debug_read_mem(struct file *file, char __user *userbuf, | 259 | static ssize_t debug_read_mem(struct file *file, char __user *userbuf, |
| 255 | size_t count, loff_t *ppos) | 260 | size_t count, loff_t *ppos) |
| 256 | { | 261 | { |
| 257 | struct omap_iommu *obj = file->private_data; | 262 | struct device *dev = file->private_data; |
| 258 | char *p, *buf; | 263 | char *p, *buf; |
| 259 | struct iovm_struct *area; | 264 | struct iovm_struct *area; |
| 260 | ssize_t bytes; | 265 | ssize_t bytes; |
| @@ -268,8 +273,8 @@ static ssize_t debug_read_mem(struct file *file, char __user *userbuf, | |||
| 268 | 273 | ||
| 269 | mutex_lock(&iommu_debug_lock); | 274 | mutex_lock(&iommu_debug_lock); |
| 270 | 275 | ||
| 271 | area = omap_find_iovm_area(obj, (u32)ppos); | 276 | area = omap_find_iovm_area(dev, (u32)ppos); |
| 272 | if (IS_ERR(area)) { | 277 | if (!area) { |
| 273 | bytes = -EINVAL; | 278 | bytes = -EINVAL; |
| 274 | goto err_out; | 279 | goto err_out; |
| 275 | } | 280 | } |
| @@ -287,7 +292,7 @@ err_out: | |||
| 287 | static ssize_t debug_write_mem(struct file *file, const char __user *userbuf, | 292 | static ssize_t debug_write_mem(struct file *file, const char __user *userbuf, |
| 288 | size_t count, loff_t *ppos) | 293 | size_t count, loff_t *ppos) |
| 289 | { | 294 | { |
| 290 | struct omap_iommu *obj = file->private_data; | 295 | struct device *dev = file->private_data; |
| 291 | struct iovm_struct *area; | 296 | struct iovm_struct *area; |
| 292 | char *p, *buf; | 297 | char *p, *buf; |
| 293 | 298 | ||
| @@ -305,8 +310,8 @@ static ssize_t debug_write_mem(struct file *file, const char __user *userbuf, | |||
| 305 | goto err_out; | 310 | goto err_out; |
| 306 | } | 311 | } |
| 307 | 312 | ||
| 308 | area = omap_find_iovm_area(obj, (u32)ppos); | 313 | area = omap_find_iovm_area(dev, (u32)ppos); |
| 309 | if (IS_ERR(area)) { | 314 | if (!area) { |
| 310 | count = -EINVAL; | 315 | count = -EINVAL; |
| 311 | goto err_out; | 316 | goto err_out; |
| 312 | } | 317 | } |
| @@ -350,7 +355,7 @@ DEBUG_FOPS(mem); | |||
| 350 | { \ | 355 | { \ |
| 351 | struct dentry *dent; \ | 356 | struct dentry *dent; \ |
| 352 | dent = debugfs_create_file(#attr, mode, parent, \ | 357 | dent = debugfs_create_file(#attr, mode, parent, \ |
| 353 | obj, &debug_##attr##_fops); \ | 358 | dev, &debug_##attr##_fops); \ |
| 354 | if (!dent) \ | 359 | if (!dent) \ |
| 355 | return -ENOMEM; \ | 360 | return -ENOMEM; \ |
| 356 | } | 361 | } |
| @@ -362,20 +367,29 @@ static int iommu_debug_register(struct device *dev, void *data) | |||
| 362 | { | 367 | { |
| 363 | struct platform_device *pdev = to_platform_device(dev); | 368 | struct platform_device *pdev = to_platform_device(dev); |
| 364 | struct omap_iommu *obj = platform_get_drvdata(pdev); | 369 | struct omap_iommu *obj = platform_get_drvdata(pdev); |
| 370 | struct omap_iommu_arch_data *arch_data; | ||
| 365 | struct dentry *d, *parent; | 371 | struct dentry *d, *parent; |
| 366 | 372 | ||
| 367 | if (!obj || !obj->dev) | 373 | if (!obj || !obj->dev) |
| 368 | return -EINVAL; | 374 | return -EINVAL; |
| 369 | 375 | ||
| 376 | arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL); | ||
| 377 | if (!arch_data) | ||
| 378 | return -ENOMEM; | ||
| 379 | |||
| 380 | arch_data->iommu_dev = obj; | ||
| 381 | |||
| 382 | dev->archdata.iommu = arch_data; | ||
| 383 | |||
| 370 | d = debugfs_create_dir(obj->name, iommu_debug_root); | 384 | d = debugfs_create_dir(obj->name, iommu_debug_root); |
| 371 | if (!d) | 385 | if (!d) |
| 372 | return -ENOMEM; | 386 | goto nomem; |
| 373 | parent = d; | 387 | parent = d; |
| 374 | 388 | ||
| 375 | d = debugfs_create_u8("nr_tlb_entries", 400, parent, | 389 | d = debugfs_create_u8("nr_tlb_entries", 400, parent, |
| 376 | (u8 *)&obj->nr_tlb_entries); | 390 | (u8 *)&obj->nr_tlb_entries); |
| 377 | if (!d) | 391 | if (!d) |
| 378 | return -ENOMEM; | 392 | goto nomem; |
| 379 | 393 | ||
| 380 | DEBUG_ADD_FILE_RO(ver); | 394 | DEBUG_ADD_FILE_RO(ver); |
| 381 | DEBUG_ADD_FILE_RO(regs); | 395 | DEBUG_ADD_FILE_RO(regs); |
| @@ -385,6 +399,22 @@ static int iommu_debug_register(struct device *dev, void *data) | |||
| 385 | DEBUG_ADD_FILE(mem); | 399 | DEBUG_ADD_FILE(mem); |
| 386 | 400 | ||
| 387 | return 0; | 401 | return 0; |
| 402 | |||
| 403 | nomem: | ||
| 404 | kfree(arch_data); | ||
| 405 | return -ENOMEM; | ||
| 406 | } | ||
| 407 | |||
| 408 | static int iommu_debug_unregister(struct device *dev, void *data) | ||
| 409 | { | ||
| 410 | if (!dev->archdata.iommu) | ||
| 411 | return 0; | ||
| 412 | |||
| 413 | kfree(dev->archdata.iommu); | ||
| 414 | |||
| 415 | dev->archdata.iommu = NULL; | ||
| 416 | |||
| 417 | return 0; | ||
| 388 | } | 418 | } |
| 389 | 419 | ||
| 390 | static int __init iommu_debug_init(void) | 420 | static int __init iommu_debug_init(void) |
| @@ -411,6 +441,7 @@ module_init(iommu_debug_init) | |||
| 411 | static void __exit iommu_debugfs_exit(void) | 441 | static void __exit iommu_debugfs_exit(void) |
| 412 | { | 442 | { |
| 413 | debugfs_remove_recursive(iommu_debug_root); | 443 | debugfs_remove_recursive(iommu_debug_root); |
| 444 | omap_foreach_iommu_device(NULL, iommu_debug_unregister); | ||
| 414 | } | 445 | } |
| 415 | module_exit(iommu_debugfs_exit) | 446 | module_exit(iommu_debugfs_exit) |
| 416 | 447 | ||
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index d8edd979d01b..6899dcd02dfa 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c | |||
| @@ -1223,7 +1223,8 @@ static int __init omap_iommu_init(void) | |||
| 1223 | 1223 | ||
| 1224 | return platform_driver_register(&omap_iommu_driver); | 1224 | return platform_driver_register(&omap_iommu_driver); |
| 1225 | } | 1225 | } |
| 1226 | module_init(omap_iommu_init); | 1226 | /* must be ready before omap3isp is probed */ |
| 1227 | subsys_initcall(omap_iommu_init); | ||
| 1227 | 1228 | ||
| 1228 | static void __exit omap_iommu_exit(void) | 1229 | static void __exit omap_iommu_exit(void) |
| 1229 | { | 1230 | { |
