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