Commit | Line | Data |
---|---|---|
61031952 RZ |
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 | ||
18 | #ifdef CONFIG_ARCH_HAS_PMEM_API | |
19 | #include <asm/cacheflush.h> | |
20 | #else | |
21 | static inline void arch_wmb_pmem(void) | |
22 | { | |
23 | BUG(); | |
24 | } | |
25 | ||
26 | static inline bool __arch_has_wmb_pmem(void) | |
27 | { | |
28 | return false; | |
29 | } | |
30 | ||
31 | static inline void __pmem *arch_memremap_pmem(resource_size_t offset, | |
32 | unsigned long size) | |
33 | { | |
34 | return NULL; | |
35 | } | |
36 | ||
37 | static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src, | |
38 | size_t n) | |
39 | { | |
40 | BUG(); | |
41 | } | |
42 | #endif | |
43 | ||
44 | /* | |
45 | * Architectures that define ARCH_HAS_PMEM_API must provide | |
46 | * implementations for arch_memremap_pmem(), arch_memcpy_to_pmem(), | |
47 | * arch_wmb_pmem(), and __arch_has_wmb_pmem(). | |
48 | */ | |
49 | ||
50 | static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t size) | |
51 | { | |
52 | memcpy(dst, (void __force const *) src, size); | |
53 | } | |
54 | ||
55 | static inline void memunmap_pmem(void __pmem *addr) | |
56 | { | |
57 | iounmap((void __force __iomem *) addr); | |
58 | } | |
59 | ||
60 | /** | |
61 | * arch_has_wmb_pmem - true if wmb_pmem() ensures durability | |
62 | * | |
63 | * For a given cpu implementation within an architecture it is possible | |
64 | * that wmb_pmem() resolves to a nop. In the case this returns | |
65 | * false, pmem api users are unable to ensure durability and may want to | |
66 | * fall back to a different data consistency model, or otherwise notify | |
67 | * the user. | |
68 | */ | |
69 | static inline bool arch_has_wmb_pmem(void) | |
70 | { | |
71 | if (IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API)) | |
72 | return __arch_has_wmb_pmem(); | |
73 | return false; | |
74 | } | |
75 | ||
76 | static inline bool arch_has_pmem_api(void) | |
77 | { | |
78 | return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API) && arch_has_wmb_pmem(); | |
79 | } | |
80 | ||
81 | /* | |
82 | * These defaults seek to offer decent performance and minimize the | |
83 | * window between i/o completion and writes being durable on media. | |
84 | * However, it is undefined / architecture specific whether | |
85 | * default_memremap_pmem + default_memcpy_to_pmem is sufficient for | |
86 | * making data durable relative to i/o completion. | |
87 | */ | |
88 | static void default_memcpy_to_pmem(void __pmem *dst, const void *src, | |
89 | size_t size) | |
90 | { | |
91 | memcpy((void __force *) dst, src, size); | |
92 | } | |
93 | ||
94 | static void __pmem *default_memremap_pmem(resource_size_t offset, | |
95 | unsigned long size) | |
96 | { | |
88793e5c | 97 | return (void __pmem __force *)ioremap_wt(offset, size); |
61031952 RZ |
98 | } |
99 | ||
100 | /** | |
101 | * memremap_pmem - map physical persistent memory for pmem api | |
102 | * @offset: physical address of persistent memory | |
103 | * @size: size of the mapping | |
104 | * | |
105 | * Establish a mapping of the architecture specific memory type expected | |
106 | * by memcpy_to_pmem() and wmb_pmem(). For example, it may be | |
107 | * the case that an uncacheable or writethrough mapping is sufficient, | |
108 | * or a writeback mapping provided memcpy_to_pmem() and | |
109 | * wmb_pmem() arrange for the data to be written through the | |
110 | * cache to persistent media. | |
111 | */ | |
112 | static inline void __pmem *memremap_pmem(resource_size_t offset, | |
113 | unsigned long size) | |
114 | { | |
115 | if (arch_has_pmem_api()) | |
116 | return arch_memremap_pmem(offset, size); | |
117 | return default_memremap_pmem(offset, size); | |
118 | } | |
119 | ||
120 | /** | |
121 | * memcpy_to_pmem - copy data to persistent memory | |
122 | * @dst: destination buffer for the copy | |
123 | * @src: source buffer for the copy | |
124 | * @n: length of the copy in bytes | |
125 | * | |
126 | * Perform a memory copy that results in the destination of the copy | |
127 | * being effectively evicted from, or never written to, the processor | |
128 | * cache hierarchy after the copy completes. After memcpy_to_pmem() | |
129 | * data may still reside in cpu or platform buffers, so this operation | |
130 | * must be followed by a wmb_pmem(). | |
131 | */ | |
132 | static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n) | |
133 | { | |
134 | if (arch_has_pmem_api()) | |
135 | arch_memcpy_to_pmem(dst, src, n); | |
136 | else | |
137 | default_memcpy_to_pmem(dst, src, n); | |
138 | } | |
139 | ||
140 | /** | |
141 | * wmb_pmem - synchronize writes to persistent memory | |
142 | * | |
143 | * After a series of memcpy_to_pmem() operations this drains data from | |
144 | * cpu write buffers and any platform (memory controller) buffers to | |
145 | * ensure that written data is durable on persistent memory media. | |
146 | */ | |
147 | static inline void wmb_pmem(void) | |
148 | { | |
149 | if (arch_has_pmem_api()) | |
150 | arch_wmb_pmem(); | |
151 | } | |
152 | #endif /* __PMEM_H__ */ |