diff options
Diffstat (limited to 'arch/powerpc/kernel/iommu.c')
-rw-r--r-- | arch/powerpc/kernel/iommu.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 95edad4faf26..c08ceca6277d 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
@@ -47,6 +47,8 @@ static int novmerge = 0; | |||
47 | static int novmerge = 1; | 47 | static int novmerge = 1; |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | static int protect4gb = 1; | ||
51 | |||
50 | static inline unsigned long iommu_num_pages(unsigned long vaddr, | 52 | static inline unsigned long iommu_num_pages(unsigned long vaddr, |
51 | unsigned long slen) | 53 | unsigned long slen) |
52 | { | 54 | { |
@@ -58,6 +60,16 @@ static inline unsigned long iommu_num_pages(unsigned long vaddr, | |||
58 | return npages; | 60 | return npages; |
59 | } | 61 | } |
60 | 62 | ||
63 | static int __init setup_protect4gb(char *str) | ||
64 | { | ||
65 | if (strcmp(str, "on") == 0) | ||
66 | protect4gb = 1; | ||
67 | else if (strcmp(str, "off") == 0) | ||
68 | protect4gb = 0; | ||
69 | |||
70 | return 1; | ||
71 | } | ||
72 | |||
61 | static int __init setup_iommu(char *str) | 73 | static int __init setup_iommu(char *str) |
62 | { | 74 | { |
63 | if (!strcmp(str, "novmerge")) | 75 | if (!strcmp(str, "novmerge")) |
@@ -67,6 +79,7 @@ static int __init setup_iommu(char *str) | |||
67 | return 1; | 79 | return 1; |
68 | } | 80 | } |
69 | 81 | ||
82 | __setup("protect4gb=", setup_protect4gb); | ||
70 | __setup("iommu=", setup_iommu); | 83 | __setup("iommu=", setup_iommu); |
71 | 84 | ||
72 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, | 85 | static unsigned long iommu_range_alloc(struct iommu_table *tbl, |
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
429 | struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) | 442 | struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) |
430 | { | 443 | { |
431 | unsigned long sz; | 444 | unsigned long sz; |
445 | unsigned long start_index, end_index; | ||
446 | unsigned long entries_per_4g; | ||
447 | unsigned long index; | ||
432 | static int welcomed = 0; | 448 | static int welcomed = 0; |
433 | struct page *page; | 449 | struct page *page; |
434 | 450 | ||
@@ -450,7 +466,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) | |||
450 | 466 | ||
451 | #ifdef CONFIG_CRASH_DUMP | 467 | #ifdef CONFIG_CRASH_DUMP |
452 | if (ppc_md.tce_get) { | 468 | if (ppc_md.tce_get) { |
453 | unsigned long index, tceval; | 469 | unsigned long tceval; |
454 | unsigned long tcecount = 0; | 470 | unsigned long tcecount = 0; |
455 | 471 | ||
456 | /* | 472 | /* |
@@ -480,6 +496,23 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) | |||
480 | ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); | 496 | ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); |
481 | #endif | 497 | #endif |
482 | 498 | ||
499 | /* | ||
500 | * DMA cannot cross 4 GB boundary. Mark last entry of each 4 | ||
501 | * GB chunk as reserved. | ||
502 | */ | ||
503 | if (protect4gb) { | ||
504 | entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT; | ||
505 | |||
506 | /* Mark the last bit before a 4GB boundary as used */ | ||
507 | start_index = tbl->it_offset | (entries_per_4g - 1); | ||
508 | start_index -= tbl->it_offset; | ||
509 | |||
510 | end_index = tbl->it_size; | ||
511 | |||
512 | for (index = start_index; index < end_index - 1; index += entries_per_4g) | ||
513 | __set_bit(index, tbl->it_map); | ||
514 | } | ||
515 | |||
483 | if (!welcomed) { | 516 | if (!welcomed) { |
484 | printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", | 517 | printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", |
485 | novmerge ? "disabled" : "enabled"); | 518 | novmerge ? "disabled" : "enabled"); |