if (copy_from_user(&vtl0_mem, arg, sizeof(vtl0_mem)))
return -EFAULT;
- /* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */
if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) {
dev_err(vtl->module_dev, "range start pfn (%llx) > end pfn (%llx)\n",
vtl0_mem.start_pfn, vtl0_mem.last_pfn);
if (!pgmap)
return -ENOMEM;
+ /*
+ * vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design.
+ * last_pfn is not reserved or wasted, and reflects 'start_pfn + size' of pagemap range.
+ */
pgmap->ranges[0].start = PFN_PHYS(vtl0_mem.start_pfn);
pgmap->ranges[0].end = PFN_PHYS(vtl0_mem.last_pfn) - 1;
pgmap->nr_range = 1;
/*
* Determine the highest page order that can be used for the given memory range.
* This works best when the range is aligned; i.e. both the start and the length.
+ * Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range
+ * alignment exceeds the maximum supported folio order for this kernel config.
*/
- pgmap->vmemmap_shift = count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn);
+ pgmap->vmemmap_shift = min(count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn),
+ MAX_FOLIO_ORDER);
dev_dbg(vtl->module_dev,
"Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n",
vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift);
if (IS_ERR(addr)) {
dev_err(vtl->module_dev, "devm_memremap_pages error: %ld\n", PTR_ERR(addr));
kfree(pgmap);
- return -EFAULT;
+ return PTR_ERR(addr);
}
/* Don't free pgmap, since it has to stick around until the memory