Commit a14fa8ec authored by Matthew Brost's avatar Matthew Brost
Browse files

mm/migrate: Add migrate_device_pfns



Add migrate_device_pfns which prepares an array of pre-populated device
pages for migration. This is needed for eviction of known set of
non-contiguous devices pages to cpu pages which is a common case for SVM
in DRM drivers using TTM.

v2:
 - s/migrate_device_vma_range/migrate_device_prepopulated_range
 - Drop extra mmu invalidation (Vetter)
v3:
 - s/migrate_device_prepopulated_range/migrate_device_pfns (Alistar)
 - Use helper to lock device pages (Alistar)
 - Update commit message with why this is required (Alistar)

Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarMatthew Brost <matthew.brost@intel.com>
Reviewed-by: default avatarAlistair Popple <apopple@nvidia.com>
Reviewed-by: default avatarGwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250306012657.3505757-3-matthew.brost@intel.com
parent 1d724a2f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -227,6 +227,7 @@ void migrate_vma_pages(struct migrate_vma *migrate);
void migrate_vma_finalize(struct migrate_vma *migrate);
int migrate_device_range(unsigned long *src_pfns, unsigned long start,
			unsigned long npages);
int migrate_device_pfns(unsigned long *src_pfns, unsigned long npages);
void migrate_device_pages(unsigned long *src_pfns, unsigned long *dst_pfns,
			unsigned long npages);
void migrate_device_finalize(unsigned long *src_pfns,
+37 −15
Original line number Diff line number Diff line
@@ -871,6 +871,22 @@ void migrate_vma_finalize(struct migrate_vma *migrate)
}
EXPORT_SYMBOL(migrate_vma_finalize);

static unsigned long migrate_device_pfn_lock(unsigned long pfn)
{
	struct folio *folio;

	folio = folio_get_nontail_page(pfn_to_page(pfn));
	if (!folio)
		return 0;

	if (!folio_trylock(folio)) {
		folio_put(folio);
		return 0;
	}

	return migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
}

/**
 * migrate_device_range() - migrate device private pfns to normal memory.
 * @src_pfns: array large enough to hold migrating source device private pfns.
@@ -895,29 +911,35 @@ int migrate_device_range(unsigned long *src_pfns, unsigned long start,
{
	unsigned long i, pfn;

	for (pfn = start, i = 0; i < npages; pfn++, i++) {
		struct folio *folio;
	for (pfn = start, i = 0; i < npages; pfn++, i++)
		src_pfns[i] = migrate_device_pfn_lock(pfn);

		folio = folio_get_nontail_page(pfn_to_page(pfn));
		if (!folio) {
			src_pfns[i] = 0;
			continue;
		}
	migrate_device_unmap(src_pfns, npages, NULL);

		if (!folio_trylock(folio)) {
			src_pfns[i] = 0;
			folio_put(folio);
			continue;
	return 0;
}
EXPORT_SYMBOL(migrate_device_range);

		src_pfns[i] = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
	}
/**
 * migrate_device_pfns() - migrate device private pfns to normal memory.
 * @src_pfns: pre-popluated array of source device private pfns to migrate.
 * @npages: number of pages to migrate.
 *
 * Similar to migrate_device_range() but supports non-contiguous pre-popluated
 * array of device pages to migrate.
 */
int migrate_device_pfns(unsigned long *src_pfns, unsigned long npages)
{
	unsigned long i;

	for (i = 0; i < npages; i++)
		src_pfns[i] = migrate_device_pfn_lock(src_pfns[i]);

	migrate_device_unmap(src_pfns, npages, NULL);

	return 0;
}
EXPORT_SYMBOL(migrate_device_range);
EXPORT_SYMBOL(migrate_device_pfns);

/*
 * Migrate a device coherent folio back to normal memory. The caller should have