at v4.3 6.0 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 size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes, 46 struct iov_iter *i) 47{ 48 BUG(); 49 return 0; 50} 51 52static inline void arch_clear_pmem(void __pmem *addr, size_t size) 53{ 54 BUG(); 55} 56#endif 57 58/* 59 * Architectures that define ARCH_HAS_PMEM_API must provide 60 * implementations for arch_memcpy_to_pmem(), arch_wmb_pmem(), 61 * arch_copy_from_iter_pmem(), arch_clear_pmem() and arch_has_wmb_pmem(). 62 */ 63static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t size) 64{ 65 memcpy(dst, (void __force const *) src, size); 66} 67 68static inline void memunmap_pmem(struct device *dev, void __pmem *addr) 69{ 70 devm_memunmap(dev, (void __force *) addr); 71} 72 73static inline bool arch_has_pmem_api(void) 74{ 75 return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API); 76} 77 78/** 79 * arch_has_wmb_pmem - true if wmb_pmem() ensures durability 80 * 81 * For a given cpu implementation within an architecture it is possible 82 * that wmb_pmem() resolves to a nop. In the case this returns 83 * false, pmem api users are unable to ensure durability and may want to 84 * fall back to a different data consistency model, or otherwise notify 85 * the user. 86 */ 87static inline bool arch_has_wmb_pmem(void) 88{ 89 return arch_has_pmem_api() && __arch_has_wmb_pmem(); 90} 91 92/* 93 * These defaults seek to offer decent performance and minimize the 94 * window between i/o completion and writes being durable on media. 95 * However, it is undefined / architecture specific whether 96 * default_memremap_pmem + default_memcpy_to_pmem is sufficient for 97 * making data durable relative to i/o completion. 98 */ 99static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src, 100 size_t size) 101{ 102 memcpy((void __force *) dst, src, size); 103} 104 105static inline size_t default_copy_from_iter_pmem(void __pmem *addr, 106 size_t bytes, struct iov_iter *i) 107{ 108 return copy_from_iter_nocache((void __force *)addr, bytes, i); 109} 110 111static inline void default_clear_pmem(void __pmem *addr, size_t size) 112{ 113 if (size == PAGE_SIZE && ((unsigned long)addr & ~PAGE_MASK) == 0) 114 clear_page((void __force *)addr); 115 else 116 memset((void __force *)addr, 0, size); 117} 118 119/** 120 * memremap_pmem - map physical persistent memory for pmem api 121 * @offset: physical address of persistent memory 122 * @size: size of the mapping 123 * 124 * Establish a mapping of the architecture specific memory type expected 125 * by memcpy_to_pmem() and wmb_pmem(). For example, it may be 126 * the case that an uncacheable or writethrough mapping is sufficient, 127 * or a writeback mapping provided memcpy_to_pmem() and 128 * wmb_pmem() arrange for the data to be written through the 129 * cache to persistent media. 130 */ 131static inline void __pmem *memremap_pmem(struct device *dev, 132 resource_size_t offset, unsigned long size) 133{ 134 return (void __pmem *) devm_memremap(dev, offset, size, 135 ARCH_MEMREMAP_PMEM); 136} 137 138/** 139 * memcpy_to_pmem - copy data to persistent memory 140 * @dst: destination buffer for the copy 141 * @src: source buffer for the copy 142 * @n: length of the copy in bytes 143 * 144 * Perform a memory copy that results in the destination of the copy 145 * being effectively evicted from, or never written to, the processor 146 * cache hierarchy after the copy completes. After memcpy_to_pmem() 147 * data may still reside in cpu or platform buffers, so this operation 148 * must be followed by a wmb_pmem(). 149 */ 150static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n) 151{ 152 if (arch_has_pmem_api()) 153 arch_memcpy_to_pmem(dst, src, n); 154 else 155 default_memcpy_to_pmem(dst, src, n); 156} 157 158/** 159 * wmb_pmem - synchronize writes to persistent memory 160 * 161 * After a series of memcpy_to_pmem() operations this drains data from 162 * cpu write buffers and any platform (memory controller) buffers to 163 * ensure that written data is durable on persistent memory media. 164 */ 165static inline void wmb_pmem(void) 166{ 167 if (arch_has_wmb_pmem()) 168 arch_wmb_pmem(); 169 else 170 wmb(); 171} 172 173/** 174 * copy_from_iter_pmem - copy data from an iterator to PMEM 175 * @addr: PMEM destination address 176 * @bytes: number of bytes to copy 177 * @i: iterator with source data 178 * 179 * Copy data from the iterator 'i' to the PMEM buffer starting at 'addr'. 180 * This function requires explicit ordering with a wmb_pmem() call. 181 */ 182static inline size_t copy_from_iter_pmem(void __pmem *addr, size_t bytes, 183 struct iov_iter *i) 184{ 185 if (arch_has_pmem_api()) 186 return arch_copy_from_iter_pmem(addr, bytes, i); 187 return default_copy_from_iter_pmem(addr, bytes, i); 188} 189 190/** 191 * clear_pmem - zero a PMEM memory range 192 * @addr: virtual start address 193 * @size: number of bytes to zero 194 * 195 * Write zeros into the memory range starting at 'addr' for 'size' bytes. 196 * This function requires explicit ordering with a wmb_pmem() call. 197 */ 198static inline void clear_pmem(void __pmem *addr, size_t size) 199{ 200 if (arch_has_pmem_api()) 201 arch_clear_pmem(addr, size); 202 else 203 default_clear_pmem(addr, size); 204} 205#endif /* __PMEM_H__ */