aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2006-06-22 03:01:56 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-24 02:15:21 -0400
commitc2a5a46be4a1c682e18e29e67785126b7610b14d (patch)
treeb9101fa7547c9c5d86ff550e6398a8cf7c2f283a
parent486ad10a7e1b2bb61ea9e48c4d9510f50cd74fc5 (diff)
[SPARC64]: Fix for Niagara memory corruption.
On some sun4v systems, after netboot the ethernet controller and it's DMA mappings can be left active. The net result is that the kernel can end up using memory the ethernet controller will continue to DMA into, resulting in corruption. To deal with this, we are more careful about importing IOMMU translations which OBP has left in the IO-TLB. If the mapping maps into an area the firmware claimed was free and available memory for the kernel to use, we demap instead of import that IOMMU entry. This is going to cause the network chip to take a PCI master abort on the next DMA it attempts, if it has been left going like this. All tests show that this is handled properly by the PCI layer and the e1000 drivers. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c15
-rw-r--r--arch/sparc64/mm/init.c28
-rw-r--r--include/asm-sparc64/pgtable.h2
3 files changed, 39 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index b63b2834133f..b275c7df0186 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -988,8 +988,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
988 HV_PCI_TSBID(0, i), 988 HV_PCI_TSBID(0, i),
989 &io_attrs, &ra); 989 &io_attrs, &ra);
990 if (ret == HV_EOK) { 990 if (ret == HV_EOK) {
991 cnt++; 991 if (page_in_phys_avail(ra)) {
992 __set_bit(i, arena->map); 992 pci_sun4v_iommu_demap(devhandle,
993 HV_PCI_TSBID(0, i), 1);
994 } else {
995 cnt++;
996 __set_bit(i, arena->map);
997 }
993 } 998 }
994 } 999 }
995 1000
@@ -1062,9 +1067,9 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
1062 iommu->arena.limit = num_tsb_entries; 1067 iommu->arena.limit = num_tsb_entries;
1063 1068
1064 sz = probe_existing_entries(pbm, iommu); 1069 sz = probe_existing_entries(pbm, iommu);
1065 1070 if (sz)
1066 printk("%s: TSB entries [%lu], existing mapings [%lu]\n", 1071 printk("%s: Imported %lu TSB entries from OBP\n",
1067 pbm->name, num_tsb_entries, sz); 1072 pbm->name, sz);
1068} 1073}
1069 1074
1070static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) 1075static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 9d2b0da590af..513993414747 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1396,7 +1396,7 @@ static void __init taint_real_pages(void)
1396 while (old_start < old_end) { 1396 while (old_start < old_end) {
1397 int n; 1397 int n;
1398 1398
1399 for (n = 0; pavail_rescan_ents; n++) { 1399 for (n = 0; n < pavail_rescan_ents; n++) {
1400 unsigned long new_start, new_end; 1400 unsigned long new_start, new_end;
1401 1401
1402 new_start = pavail_rescan[n].phys_addr; 1402 new_start = pavail_rescan[n].phys_addr;
@@ -1418,6 +1418,32 @@ static void __init taint_real_pages(void)
1418 } 1418 }
1419} 1419}
1420 1420
1421int __init page_in_phys_avail(unsigned long paddr)
1422{
1423 int i;
1424
1425 paddr &= PAGE_MASK;
1426
1427 for (i = 0; i < pavail_rescan_ents; i++) {
1428 unsigned long start, end;
1429
1430 start = pavail_rescan[i].phys_addr;
1431 end = start + pavail_rescan[i].reg_size;
1432
1433 if (paddr >= start && paddr < end)
1434 return 1;
1435 }
1436 if (paddr >= kern_base && paddr < (kern_base + kern_size))
1437 return 1;
1438#ifdef CONFIG_BLK_DEV_INITRD
1439 if (paddr >= __pa(initrd_start) &&
1440 paddr < __pa(PAGE_ALIGN(initrd_end)))
1441 return 1;
1442#endif
1443
1444 return 0;
1445}
1446
1421void __init mem_init(void) 1447void __init mem_init(void)
1422{ 1448{
1423 unsigned long codepages, datapages, initpages; 1449 unsigned long codepages, datapages, initpages;
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 4e218814bb3c..03f5bc9b6bec 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -756,6 +756,8 @@ extern unsigned long *sparc64_valid_addr_bitmap;
756#define kern_addr_valid(addr) \ 756#define kern_addr_valid(addr) \
757 (test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap)) 757 (test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
758 758
759extern int page_in_phys_avail(unsigned long paddr);
760
759extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, 761extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
760 unsigned long pfn, 762 unsigned long pfn,
761 unsigned long size, pgprot_t prot); 763 unsigned long size, pgprot_t prot);