|
@@ -363,6 +363,37 @@ pte_t *lookup_address(unsigned long address, unsigned int *level)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(lookup_address);
|
|
|
|
|
|
+/*
|
|
|
+ * This is necessary because __pa() does not work on some
|
|
|
+ * kinds of memory, like vmalloc() or the alloc_remap()
|
|
|
+ * areas on 32-bit NUMA systems. The percpu areas can
|
|
|
+ * end up in this kind of memory, for instance.
|
|
|
+ *
|
|
|
+ * This could be optimized, but it is only intended to be
|
|
|
+ * used at inititalization time, and keeping it
|
|
|
+ * unoptimized should increase the testing coverage for
|
|
|
+ * the more obscure platforms.
|
|
|
+ */
|
|
|
+phys_addr_t slow_virt_to_phys(void *__virt_addr)
|
|
|
+{
|
|
|
+ unsigned long virt_addr = (unsigned long)__virt_addr;
|
|
|
+ phys_addr_t phys_addr;
|
|
|
+ unsigned long offset;
|
|
|
+ enum pg_level level;
|
|
|
+ unsigned long psize;
|
|
|
+ unsigned long pmask;
|
|
|
+ pte_t *pte;
|
|
|
+
|
|
|
+ pte = lookup_address(virt_addr, &level);
|
|
|
+ BUG_ON(!pte);
|
|
|
+ psize = page_level_size(level);
|
|
|
+ pmask = page_level_mask(level);
|
|
|
+ offset = virt_addr & ~pmask;
|
|
|
+ phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
|
|
|
+ return (phys_addr | offset);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(slow_virt_to_phys);
|
|
|
+
|
|
|
/*
|
|
|
* Set the new pmd in all the pgds we know about:
|
|
|
*/
|