162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014-2016, Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include "test/nfit_test.h" 662306a36Sopenharmony_ci#include <linux/blkdev.h> 762306a36Sopenharmony_ci#include <linux/dax.h> 862306a36Sopenharmony_ci#include <pmem.h> 962306a36Sopenharmony_ci#include <nd.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cilong __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, 1262306a36Sopenharmony_ci long nr_pages, enum dax_access_mode mode, void **kaddr, 1362306a36Sopenharmony_ci pfn_t *pfn) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, 1862306a36Sopenharmony_ci PFN_PHYS(nr_pages)))) 1962306a36Sopenharmony_ci return -EIO; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci /* 2262306a36Sopenharmony_ci * Limit dax to a single page at a time given vmalloc()-backed 2362306a36Sopenharmony_ci * in the nfit_test case. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci if (get_nfit_res(pmem->phys_addr + offset)) { 2662306a36Sopenharmony_ci struct page *page; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (kaddr) 2962306a36Sopenharmony_ci *kaddr = pmem->virt_addr + offset; 3062306a36Sopenharmony_ci page = vmalloc_to_page(pmem->virt_addr + offset); 3162306a36Sopenharmony_ci if (pfn) 3262306a36Sopenharmony_ci *pfn = page_to_pfn_t(page); 3362306a36Sopenharmony_ci pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n", 3462306a36Sopenharmony_ci __func__, pmem, pgoff, page_to_pfn(page)); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return 1; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (kaddr) 4062306a36Sopenharmony_ci *kaddr = pmem->virt_addr + offset; 4162306a36Sopenharmony_ci if (pfn) 4262306a36Sopenharmony_ci *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * If badblocks are present, limit known good range to the 4662306a36Sopenharmony_ci * requested range. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci if (unlikely(pmem->bb.count)) 4962306a36Sopenharmony_ci return nr_pages; 5062306a36Sopenharmony_ci return PHYS_PFN(pmem->size - pmem->pfn_pad - offset); 5162306a36Sopenharmony_ci} 52