at v4.7 6.5 kB view raw
1/* 2 * Copyright(c) 2015 Intel Corporation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 */ 13#ifndef __PMEM_H__ 14#define __PMEM_H__ 15 16#include <linux/io.h> 17#include <linux/uio.h> 18 19#ifdef CONFIG_ARCH_HAS_PMEM_API 20#define ARCH_MEMREMAP_PMEM MEMREMAP_WB 21#include <asm/pmem.h> 22#else 23#define ARCH_MEMREMAP_PMEM MEMREMAP_WT 24/* 25 * These are simply here to enable compilation, all call sites gate 26 * calling these symbols with arch_has_pmem_api() and redirect to the 27 * implementation in asm/pmem.h. 28 */ 29static inline bool __arch_has_wmb_pmem(void) 30{ 31 return false; 32} 33 34static inline void arch_wmb_pmem(void) 35{ 36 BUG(); 37} 38 39static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src, 40 size_t n) 41{ 42 BUG(); 43} 44 45static inline int arch_memcpy_from_pmem(void *dst, const void __pmem *src, 46 size_t n) 47{ 48 BUG(); 49 return -EFAULT; 50} 51 52static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes, 53 struct iov_iter *i) 54{ 55 BUG(); 56 return 0; 57} 58 59static inline void arch_clear_pmem(void __pmem *addr, size_t size) 60{ 61 BUG(); 62} 63 64static inline void arch_wb_cache_pmem(void __pmem *addr, size_t size) 65{ 66 BUG(); 67} 68 69static inline void arch_invalidate_pmem(void __pmem *addr, size_t size) 70{ 71 BUG(); 72} 73#endif 74 75static inline bool arch_has_pmem_api(void) 76{ 77 return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API); 78} 79 80static inline int default_memcpy_from_pmem(void *dst, void __pmem const *src, 81 size_t size) 82{ 83 memcpy(dst, (void __force *) src, size); 84 return 0; 85} 86 87/* 88 * memcpy_from_pmem - read from persistent memory with error handling 89 * @dst: destination buffer 90 * @src: source buffer 91 * @size: transfer length 92 * 93 * Returns 0 on success negative error code on failure. 94 */ 95static inline int memcpy_from_pmem(void *dst, void __pmem const *src, 96 size_t size) 97{ 98 if (arch_has_pmem_api()) 99 return arch_memcpy_from_pmem(dst, src, size); 100 else 101 return default_memcpy_from_pmem(dst, src, size); 102} 103 104/** 105 * arch_has_wmb_pmem - true if wmb_pmem() ensures durability 106 * 107 * For a given cpu implementation within an architecture it is possible 108 * that wmb_pmem() resolves to a nop. In the case this returns 109 * false, pmem api users are unable to ensure durability and may want to 110 * fall back to a different data consistency model, or otherwise notify 111 * the user. 112 */ 113static inline bool arch_has_wmb_pmem(void) 114{ 115 return arch_has_pmem_api() && __arch_has_wmb_pmem(); 116} 117 118/* 119 * These defaults seek to offer decent performance and minimize the 120 * window between i/o completion and writes being durable on media. 121 * However, it is undefined / architecture specific whether 122 * ARCH_MEMREMAP_PMEM + default_memcpy_to_pmem is sufficient for 123 * making data durable relative to i/o completion. 124 */ 125static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src, 126 size_t size) 127{ 128 memcpy((void __force *) dst, src, size); 129} 130 131static inline size_t default_copy_from_iter_pmem(void __pmem *addr, 132 size_t bytes, struct iov_iter *i) 133{ 134 return copy_from_iter_nocache((void __force *)addr, bytes, i); 135} 136 137static inline void default_clear_pmem(void __pmem *addr, size_t size) 138{ 139 if (size == PAGE_SIZE && ((unsigned long)addr & ~PAGE_MASK) == 0) 140 clear_page((void __force *)addr); 141 else 142 memset((void __force *)addr, 0, size); 143} 144 145/** 146 * memcpy_to_pmem - copy data to persistent memory 147 * @dst: destination buffer for the copy 148 * @src: source buffer for the copy 149 * @n: length of the copy in bytes 150 * 151 * Perform a memory copy that results in the destination of the copy 152 * being effectively evicted from, or never written to, the processor 153 * cache hierarchy after the copy completes. After memcpy_to_pmem() 154 * data may still reside in cpu or platform buffers, so this operation 155 * must be followed by a wmb_pmem(). 156 */ 157static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n) 158{ 159 if (arch_has_pmem_api()) 160 arch_memcpy_to_pmem(dst, src, n); 161 else 162 default_memcpy_to_pmem(dst, src, n); 163} 164 165/** 166 * wmb_pmem - synchronize writes to persistent memory 167 * 168 * After a series of memcpy_to_pmem() operations this drains data from 169 * cpu write buffers and any platform (memory controller) buffers to 170 * ensure that written data is durable on persistent memory media. 171 */ 172static inline void wmb_pmem(void) 173{ 174 if (arch_has_wmb_pmem()) 175 arch_wmb_pmem(); 176 else 177 wmb(); 178} 179 180/** 181 * copy_from_iter_pmem - copy data from an iterator to PMEM 182 * @addr: PMEM destination address 183 * @bytes: number of bytes to copy 184 * @i: iterator with source data 185 * 186 * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'. 187 * This function requires explicit ordering with a wmb_pmem() call. 188 */ 189static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes, 190 struct iov_iter *i) 191{ 192 if (arch_has_pmem_api()) 193 return arch_copy_from_iter_pmem(addr, bytes, i); 194 return default_copy_from_iter_pmem(addr, bytes, i); 195} 196 197/** 198 * clear_pmem - zero a PMEM memory range 199 * @addr: virtual start address 200 * @size: number of bytes to zero 201 * 202 * Write zeros into the memory range starting at 'addr' for 'size' bytes. 203 * This function requires explicit ordering with a wmb_pmem() call. 204 */ 205static inline void clear_pmem(void __pmem *addr, size_t size) 206{ 207 if (arch_has_pmem_api()) 208 arch_clear_pmem(addr, size); 209 else 210 default_clear_pmem(addr, size); 211} 212 213/** 214 * invalidate_pmem - flush a pmem range from the cache hierarchy 215 * @addr: virtual start address 216 * @size: bytes to invalidate (internally aligned to cache line size) 217 * 218 * For platforms that support clearing poison this flushes any poisoned 219 * ranges out of the cache 220 */ 221static inline void invalidate_pmem(void __pmem *addr, size_t size) 222{ 223 if (arch_has_pmem_api()) 224 arch_invalidate_pmem(addr, size); 225} 226 227/** 228 * wb_cache_pmem - write back processor cache for PMEM memory range 229 * @addr: virtual start address 230 * @size: number of bytes to write back 231 * 232 * Write back the processor cache range starting at 'addr' for 'size' bytes. 233 * This function requires explicit ordering with a wmb_pmem() call. 234 */ 235static inline void wb_cache_pmem(void __pmem *addr, size_t size) 236{ 237 if (arch_has_pmem_api()) 238 arch_wb_cache_pmem(addr, size); 239} 240#endif /* __PMEM_H__ */