aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/iommu.c')
-rw-r--r--arch/powerpc/kernel/iommu.c35
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;
47static int novmerge = 1; 47static int novmerge = 1;
48#endif 48#endif
49 49
50static int protect4gb = 1;
51
50static inline unsigned long iommu_num_pages(unsigned long vaddr, 52static 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
63static 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
61static int __init setup_iommu(char *str) 73static 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
72static unsigned long iommu_range_alloc(struct iommu_table *tbl, 85static unsigned long iommu_range_alloc(struct iommu_table *tbl,
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
429struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) 442struct 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");