return ret;
}
+/**
+ * drm_pagemap_cpages() - Count collected pages
+ * @migrate_pfn: Array of migrate_pfn entries to account
+ * @npages: Number of entries in @migrate_pfn
+ *
+ * Compute the total number of minimum-sized pages represented by the
+ * collected entries in @migrate_pfn. The total is derived from the
+ * order encoded in each entry.
+ *
+ * Return: Total number of minimum-sized pages.
+ */
+static int drm_pagemap_cpages(unsigned long *migrate_pfn, unsigned long npages)
+{
+ unsigned long i, cpages = 0;
+
+ for (i = 0; i < npages;) {
+ struct page *page = migrate_pfn_to_page(migrate_pfn[i]);
+ struct folio *folio;
+ unsigned int order = 0;
+
+ if (page) {
+ folio = page_folio(page);
+ order = folio_order(folio);
+ cpages += NR_PAGES(order);
+ } else if (migrate_pfn[i] & MIGRATE_PFN_COMPOUND) {
+ order = HPAGE_PMD_ORDER;
+ cpages += NR_PAGES(order);
+ }
+
+ i += NR_PAGES(order);
+ }
+
+ return cpages;
+}
+
/**
* drm_pagemap_migrate_to_devmem() - Migrate a struct mm_struct range to device memory
* @devmem_allocation: The device memory allocation to migrate to.
goto err_free;
}
- if (migrate.cpages != npages) {
+ if (migrate.cpages != npages &&
+ drm_pagemap_cpages(migrate.src, npages) != npages) {
/*
* Some pages to migrate. But we want to migrate all or
* nothing. Raced or unknown device pages.