18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016, Intel Corporation.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include "test/nfit_test.h"
68c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
78c2ecf20Sopenharmony_ci#include <pmem.h>
88c2ecf20Sopenharmony_ci#include <nd.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cilong __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
118c2ecf20Sopenharmony_ci		long nr_pages, void **kaddr, pfn_t *pfn)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512,
168c2ecf20Sopenharmony_ci					PFN_PHYS(nr_pages))))
178c2ecf20Sopenharmony_ci		return -EIO;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/*
208c2ecf20Sopenharmony_ci	 * Limit dax to a single page at a time given vmalloc()-backed
218c2ecf20Sopenharmony_ci	 * in the nfit_test case.
228c2ecf20Sopenharmony_ci	 */
238c2ecf20Sopenharmony_ci	if (get_nfit_res(pmem->phys_addr + offset)) {
248c2ecf20Sopenharmony_ci		struct page *page;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci		if (kaddr)
278c2ecf20Sopenharmony_ci			*kaddr = pmem->virt_addr + offset;
288c2ecf20Sopenharmony_ci		page = vmalloc_to_page(pmem->virt_addr + offset);
298c2ecf20Sopenharmony_ci		if (pfn)
308c2ecf20Sopenharmony_ci			*pfn = page_to_pfn_t(page);
318c2ecf20Sopenharmony_ci		pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n",
328c2ecf20Sopenharmony_ci				__func__, pmem, pgoff, page_to_pfn(page));
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci		return 1;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (kaddr)
388c2ecf20Sopenharmony_ci		*kaddr = pmem->virt_addr + offset;
398c2ecf20Sopenharmony_ci	if (pfn)
408c2ecf20Sopenharmony_ci		*pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/*
438c2ecf20Sopenharmony_ci	 * If badblocks are present, limit known good range to the
448c2ecf20Sopenharmony_ci	 * requested range.
458c2ecf20Sopenharmony_ci	 */
468c2ecf20Sopenharmony_ci	if (unlikely(pmem->bb.count))
478c2ecf20Sopenharmony_ci		return nr_pages;
488c2ecf20Sopenharmony_ci	return PHYS_PFN(pmem->size - pmem->pfn_pad - offset);
498c2ecf20Sopenharmony_ci}
50