unsigned long free_reserved_area(void *start, void *end, int poison, const char *s)
{
- void *pos;
- unsigned long pages = 0;
+ phys_addr_t start_pa, end_pa;
+ unsigned long pages = 0, pfn;
- start = (void *)PAGE_ALIGN((unsigned long)start);
- end = (void *)((unsigned long)end & PAGE_MASK);
- for (pos = start; pos < end; pos += PAGE_SIZE, pages++) {
- struct page *page = virt_to_page(pos);
+ /*
+ * end is the first address past the region and it may be beyond what
+ * __pa() or __pa_symbol() can handle.
+ * Use the address included in the range for the conversion and add
+ * back 1 afterwards.
+ */
+ if (__is_kernel((unsigned long)start)) {
+ start_pa = __pa_symbol(start);
+ end_pa = __pa_symbol(end - 1) + 1;
+ } else {
+ start_pa = __pa(start);
+ end_pa = __pa(end - 1) + 1;
+ }
+
+ for_each_valid_pfn(pfn, PFN_UP(start_pa), PFN_DOWN(end_pa)) {
+ struct page *page = pfn_to_page(pfn);
void *direct_map_addr;
/*
- * 'direct_map_addr' might be different from 'pos'
- * because some architectures' virt_to_page()
- * work with aliases. Getting the direct map
- * address ensures that we get a _writeable_
- * alias for the memset().
+ * 'direct_map_addr' might be different from the kernel virtual
+ * address because some architectures use aliases.
+ * Going via physical address, pfn_to_page() and page_address()
+ * ensures that we get a _writeable_ alias for the memset().
*/
direct_map_addr = page_address(page);
/*
memset(direct_map_addr, poison, PAGE_SIZE);
free_reserved_page(page);
+ pages++;
}
if (pages && s)