15b497af4SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2b94d5230SDan Williams /*
3b94d5230SDan Williams * libnvdimm - Non-volatile-memory Devices Subsystem
4b94d5230SDan Williams *
5b94d5230SDan Williams * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
6b94d5230SDan Williams */
7b94d5230SDan Williams #ifndef __LIBNVDIMM_H__
8b94d5230SDan Williams #define __LIBNVDIMM_H__
9047fc8a1SRoss Zwisler #include <linux/kernel.h>
1062232e45SDan Williams #include <linux/sizes.h>
1162232e45SDan Williams #include <linux/types.h>
12faec6f8aSDan Williams #include <linux/uuid.h>
13aa9ad44aSDave Jiang #include <linux/spinlock.h>
14c5d4355dSPankaj Gupta #include <linux/bio.h>
15aa9ad44aSDave Jiang
16aa9ad44aSDave Jiang struct badrange_entry {
17aa9ad44aSDave Jiang u64 start;
18aa9ad44aSDave Jiang u64 length;
19aa9ad44aSDave Jiang struct list_head list;
20aa9ad44aSDave Jiang };
21aa9ad44aSDave Jiang
22aa9ad44aSDave Jiang struct badrange {
23aa9ad44aSDave Jiang struct list_head list;
24aa9ad44aSDave Jiang spinlock_t lock;
25aa9ad44aSDave Jiang };
26e6dfb2deSDan Williams
27e6dfb2deSDan Williams enum {
2858138820SDan Williams /* unarmed memory devices may not persist writes */
298f078b38SDan Williams NDD_UNARMED = 1,
308f078b38SDan Williams /* locked memory devices should not be accessed */
318f078b38SDan Williams NDD_LOCKED = 2,
327d988097SDave Jiang /* memory under security wipes should not be accessed */
337d988097SDave Jiang NDD_SECURITY_OVERWRITE = 3,
347d988097SDave Jiang /* tracking whether or not there is a pending device reference */
357d988097SDave Jiang NDD_WORK_PENDING = 4,
36a0e37452SDan Williams /* dimm supports namespace labels */
37a0e37452SDan Williams NDD_LABELING = 6,
38dc370b28SDan Williams /*
39dc370b28SDan Williams * dimm contents have changed requiring invalidation of CPU caches prior
40dc370b28SDan Williams * to activation of a region that includes this device
41dc370b28SDan Williams */
42dc370b28SDan Williams NDD_INCOHERENT = 7,
4362232e45SDan Williams
44*f57aec44SDan Williams /* dimm provider wants synchronous registration by __nvdimm_create() */
45*f57aec44SDan Williams NDD_REGISTER_SYNC = 8,
46*f57aec44SDan Williams
4762232e45SDan Williams /* need to set a limit somewhere, but yes, this is likely overkill */
4862232e45SDan Williams ND_IOCTL_MAX_BUFLEN = SZ_4M,
494577b066SDan Williams ND_CMD_MAX_ELEM = 5,
5040abf9beSJerry Hoemann ND_CMD_MAX_ENVELOPE = 256,
511f7df6f8SDan Williams ND_MAX_MAPPINGS = 32,
521b40e09aSDan Williams
53004f1afbSDan Williams /* region flag indicating to direct-map persistent memory by default */
54004f1afbSDan Williams ND_REGION_PAGEMAP = 0,
5506e8ccdaSDave Jiang /*
5606e8ccdaSDave Jiang * Platform ensures entire CPU store data path is flushed to pmem on
5706e8ccdaSDave Jiang * system power loss.
5806e8ccdaSDave Jiang */
5906e8ccdaSDave Jiang ND_REGION_PERSIST_CACHE = 1,
6030e6d7bfSDave Jiang /*
6130e6d7bfSDave Jiang * Platform provides mechanisms to automatically flush outstanding
6230e6d7bfSDave Jiang * write data from memory controler to pmem on system power loss.
6330e6d7bfSDave Jiang * (ADR)
6430e6d7bfSDave Jiang */
6530e6d7bfSDave Jiang ND_REGION_PERSIST_MEMCTRL = 2,
66004f1afbSDan Williams
67c5d4355dSPankaj Gupta /* Platform provides asynchronous flush mechanism */
68c5d4355dSPankaj Gupta ND_REGION_ASYNC = 3,
69c5d4355dSPankaj Gupta
7004ad63f0SDan Williams /* Region was created by CXL subsystem */
7104ad63f0SDan Williams ND_REGION_CXL = 4,
7204ad63f0SDan Williams
731b40e09aSDan Williams /* mark newly adjusted resources as requiring a label update */
741b40e09aSDan Williams DPA_RESOURCE_ADJUSTED = 1 << 0,
75e6dfb2deSDan Williams };
76e6dfb2deSDan Williams
77b94d5230SDan Williams struct nvdimm;
78b94d5230SDan Williams struct nvdimm_bus_descriptor;
79b94d5230SDan Williams typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
80b94d5230SDan Williams struct nvdimm *nvdimm, unsigned int cmd, void *buf,
81aef25338SDan Williams unsigned int buf_len, int *cmd_rc);
82b94d5230SDan Williams
831ff19f48SOliver O'Halloran struct device_node;
84b94d5230SDan Williams struct nvdimm_bus_descriptor {
8545def22cSDan Williams const struct attribute_group **attr_groups;
86e3654ecaSDan Williams unsigned long cmd_mask;
8792fe2aa8SDan Williams unsigned long dimm_family_mask;
8892fe2aa8SDan Williams unsigned long bus_family_mask;
89bc9775d8SDan Williams struct module *module;
90b94d5230SDan Williams char *provider_name;
911ff19f48SOliver O'Halloran struct device_node *of_node;
92b94d5230SDan Williams ndctl_fn ndctl;
937ae0fa43SDan Williams int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc);
9487bf572eSDan Williams int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc,
95b3ed2ce0SDave Jiang struct nvdimm *nvdimm, unsigned int cmd, void *data);
9648001ea5SDan Williams const struct nvdimm_bus_fw_ops *fw_ops;
97b94d5230SDan Williams };
98b94d5230SDan Williams
9962232e45SDan Williams struct nd_cmd_desc {
10062232e45SDan Williams int in_num;
10162232e45SDan Williams int out_num;
10262232e45SDan Williams u32 in_sizes[ND_CMD_MAX_ELEM];
10362232e45SDan Williams int out_sizes[ND_CMD_MAX_ELEM];
10462232e45SDan Williams };
10562232e45SDan Williams
106eaf96153SDan Williams struct nd_interleave_set {
107c12c48ceSDan Williams /* v1.1 definition of the interleave-set-cookie algorithm */
108c12c48ceSDan Williams u64 cookie1;
109c12c48ceSDan Williams /* v1.2 definition of the interleave-set-cookie algorithm */
110c12c48ceSDan Williams u64 cookie2;
11186ef58a4SDan Williams /* compatibility with initial buggy Linux implementation */
11286ef58a4SDan Williams u64 altcookie;
113faec6f8aSDan Williams
114faec6f8aSDan Williams guid_t type_guid;
115eaf96153SDan Williams };
116eaf96153SDan Williams
11744c462ebSDan Williams struct nd_mapping_desc {
11844c462ebSDan Williams struct nvdimm *nvdimm;
11944c462ebSDan Williams u64 start;
12044c462ebSDan Williams u64 size;
121401c0a19SDan Williams int position;
12244c462ebSDan Williams };
12344c462ebSDan Williams
124c5d4355dSPankaj Gupta struct nd_region;
1251f7df6f8SDan Williams struct nd_region_desc {
1261f7df6f8SDan Williams struct resource *res;
12744c462ebSDan Williams struct nd_mapping_desc *mapping;
1281f7df6f8SDan Williams u16 num_mappings;
1291f7df6f8SDan Williams const struct attribute_group **attr_groups;
130eaf96153SDan Williams struct nd_interleave_set *nd_set;
1311f7df6f8SDan Williams void *provider_data;
1325212e11fSVishal Verma int num_lanes;
13341d7a6d6SToshi Kani int numa_node;
1348fc5c735SDan Williams int target_node;
135004f1afbSDan Williams unsigned long flags;
13604ad63f0SDan Williams int memregion;
1371ff19f48SOliver O'Halloran struct device_node *of_node;
138c5d4355dSPankaj Gupta int (*flush)(struct nd_region *nd_region, struct bio *bio);
1391f7df6f8SDan Williams };
1401f7df6f8SDan Williams
14129b9aa0aSDan Williams struct device;
14229b9aa0aSDan Williams void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset,
14329b9aa0aSDan Williams size_t size, unsigned long flags);
devm_nvdimm_ioremap(struct device * dev,resource_size_t offset,size_t size)14429b9aa0aSDan Williams static inline void __iomem *devm_nvdimm_ioremap(struct device *dev,
14529b9aa0aSDan Williams resource_size_t offset, size_t size)
14629b9aa0aSDan Williams {
14729b9aa0aSDan Williams return (void __iomem *) devm_nvdimm_memremap(dev, offset, size, 0);
14829b9aa0aSDan Williams }
14929b9aa0aSDan Williams
15062232e45SDan Williams struct nvdimm_bus;
151047fc8a1SRoss Zwisler
152d78c620aSDan Williams /*
153d78c620aSDan Williams * Note that separate bits for locked + unlocked are defined so that
154d78c620aSDan Williams * 'flags == 0' corresponds to an error / not-supported state.
155d78c620aSDan Williams */
156d78c620aSDan Williams enum nvdimm_security_bits {
157f2989396SDave Jiang NVDIMM_SECURITY_DISABLED,
158f2989396SDave Jiang NVDIMM_SECURITY_UNLOCKED,
159f2989396SDave Jiang NVDIMM_SECURITY_LOCKED,
160f2989396SDave Jiang NVDIMM_SECURITY_FROZEN,
161f2989396SDave Jiang NVDIMM_SECURITY_OVERWRITE,
162f2989396SDave Jiang };
163f2989396SDave Jiang
1644c6926a2SDave Jiang #define NVDIMM_PASSPHRASE_LEN 32
1654c6926a2SDave Jiang #define NVDIMM_KEY_DESC_LEN 22
1664c6926a2SDave Jiang
1674c6926a2SDave Jiang struct nvdimm_key_data {
1684c6926a2SDave Jiang u8 data[NVDIMM_PASSPHRASE_LEN];
1694c6926a2SDave Jiang };
1704c6926a2SDave Jiang
17189fa9d8eSDave Jiang enum nvdimm_passphrase_type {
17289fa9d8eSDave Jiang NVDIMM_USER,
17389fa9d8eSDave Jiang NVDIMM_MASTER,
17489fa9d8eSDave Jiang };
17589fa9d8eSDave Jiang
176f2989396SDave Jiang struct nvdimm_security_ops {
177d78c620aSDan Williams unsigned long (*get_flags)(struct nvdimm *nvdimm,
17889fa9d8eSDave Jiang enum nvdimm_passphrase_type pass_type);
17937833fb7SDave Jiang int (*freeze)(struct nvdimm *nvdimm);
1804c6926a2SDave Jiang int (*change_key)(struct nvdimm *nvdimm,
1814c6926a2SDave Jiang const struct nvdimm_key_data *old_data,
18289fa9d8eSDave Jiang const struct nvdimm_key_data *new_data,
18389fa9d8eSDave Jiang enum nvdimm_passphrase_type pass_type);
1844c6926a2SDave Jiang int (*unlock)(struct nvdimm *nvdimm,
1854c6926a2SDave Jiang const struct nvdimm_key_data *key_data);
18603b65b22SDave Jiang int (*disable)(struct nvdimm *nvdimm,
18703b65b22SDave Jiang const struct nvdimm_key_data *key_data);
18864e77c8cSDave Jiang int (*erase)(struct nvdimm *nvdimm,
18989fa9d8eSDave Jiang const struct nvdimm_key_data *key_data,
19089fa9d8eSDave Jiang enum nvdimm_passphrase_type pass_type);
1917d988097SDave Jiang int (*overwrite)(struct nvdimm *nvdimm,
1927d988097SDave Jiang const struct nvdimm_key_data *key_data);
1937d988097SDave Jiang int (*query_overwrite)(struct nvdimm *nvdimm);
194dcedadfaSDave Jiang int (*disable_master)(struct nvdimm *nvdimm,
195dcedadfaSDave Jiang const struct nvdimm_key_data *key_data);
196f2989396SDave Jiang };
197f2989396SDave Jiang
19848001ea5SDan Williams enum nvdimm_fwa_state {
19948001ea5SDan Williams NVDIMM_FWA_INVALID,
20048001ea5SDan Williams NVDIMM_FWA_IDLE,
20148001ea5SDan Williams NVDIMM_FWA_ARMED,
20248001ea5SDan Williams NVDIMM_FWA_BUSY,
20348001ea5SDan Williams NVDIMM_FWA_ARM_OVERFLOW,
20448001ea5SDan Williams };
20548001ea5SDan Williams
20648001ea5SDan Williams enum nvdimm_fwa_trigger {
20748001ea5SDan Williams NVDIMM_FWA_ARM,
20848001ea5SDan Williams NVDIMM_FWA_DISARM,
20948001ea5SDan Williams };
21048001ea5SDan Williams
21148001ea5SDan Williams enum nvdimm_fwa_capability {
21248001ea5SDan Williams NVDIMM_FWA_CAP_INVALID,
21348001ea5SDan Williams NVDIMM_FWA_CAP_NONE,
21448001ea5SDan Williams NVDIMM_FWA_CAP_QUIESCE,
21548001ea5SDan Williams NVDIMM_FWA_CAP_LIVE,
21648001ea5SDan Williams };
21748001ea5SDan Williams
21848001ea5SDan Williams enum nvdimm_fwa_result {
21948001ea5SDan Williams NVDIMM_FWA_RESULT_INVALID,
22048001ea5SDan Williams NVDIMM_FWA_RESULT_NONE,
22148001ea5SDan Williams NVDIMM_FWA_RESULT_SUCCESS,
22248001ea5SDan Williams NVDIMM_FWA_RESULT_NOTSTAGED,
22348001ea5SDan Williams NVDIMM_FWA_RESULT_NEEDRESET,
22448001ea5SDan Williams NVDIMM_FWA_RESULT_FAIL,
22548001ea5SDan Williams };
22648001ea5SDan Williams
22748001ea5SDan Williams struct nvdimm_bus_fw_ops {
22848001ea5SDan Williams enum nvdimm_fwa_state (*activate_state)
22948001ea5SDan Williams (struct nvdimm_bus_descriptor *nd_desc);
23048001ea5SDan Williams enum nvdimm_fwa_capability (*capability)
23148001ea5SDan Williams (struct nvdimm_bus_descriptor *nd_desc);
23248001ea5SDan Williams int (*activate)(struct nvdimm_bus_descriptor *nd_desc);
23348001ea5SDan Williams };
23448001ea5SDan Williams
23548001ea5SDan Williams struct nvdimm_fw_ops {
23648001ea5SDan Williams enum nvdimm_fwa_state (*activate_state)(struct nvdimm *nvdimm);
23748001ea5SDan Williams enum nvdimm_fwa_result (*activate_result)(struct nvdimm *nvdimm);
23848001ea5SDan Williams int (*arm)(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arg);
23948001ea5SDan Williams };
24048001ea5SDan Williams
241aa9ad44aSDave Jiang void badrange_init(struct badrange *badrange);
242aa9ad44aSDave Jiang int badrange_add(struct badrange *badrange, u64 addr, u64 length);
243aa9ad44aSDave Jiang void badrange_forget(struct badrange *badrange, phys_addr_t start,
244aa9ad44aSDave Jiang unsigned int len);
245aa9ad44aSDave Jiang int nvdimm_bus_add_badrange(struct nvdimm_bus *nvdimm_bus, u64 addr,
246aa9ad44aSDave Jiang u64 length);
247bc9775d8SDan Williams struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
248bc9775d8SDan Williams struct nvdimm_bus_descriptor *nfit_desc);
249b94d5230SDan Williams void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
25045def22cSDan Williams struct nvdimm_bus *to_nvdimm_bus(struct device *dev);
251f2989396SDave Jiang struct nvdimm_bus *nvdimm_to_bus(struct nvdimm *nvdimm);
252e6dfb2deSDan Williams struct nvdimm *to_nvdimm(struct device *dev);
2531f7df6f8SDan Williams struct nd_region *to_nd_region(struct device *dev);
254243f29feSDan Williams struct device *nd_region_dev(struct nd_region *nd_region);
25545def22cSDan Williams struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus);
25637b137ffSVishal Verma struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus);
257e6dfb2deSDan Williams const char *nvdimm_name(struct nvdimm *nvdimm);
258ba9c8dd3SDan Williams struct kobject *nvdimm_kobj(struct nvdimm *nvdimm);
259e3654ecaSDan Williams unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm);
260e6dfb2deSDan Williams void *nvdimm_provider_data(struct nvdimm *nvdimm);
261d6548ae4SDave Jiang struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
262d6548ae4SDave Jiang void *provider_data, const struct attribute_group **groups,
263d6548ae4SDave Jiang unsigned long flags, unsigned long cmd_mask, int num_flush,
264f2989396SDave Jiang struct resource *flush_wpq, const char *dimm_id,
265a1facc1fSDan Williams const struct nvdimm_security_ops *sec_ops,
266a1facc1fSDan Williams const struct nvdimm_fw_ops *fw_ops);
nvdimm_create(struct nvdimm_bus * nvdimm_bus,void * provider_data,const struct attribute_group ** groups,unsigned long flags,unsigned long cmd_mask,int num_flush,struct resource * flush_wpq)267d6548ae4SDave Jiang static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
268d6548ae4SDave Jiang void *provider_data, const struct attribute_group **groups,
269d6548ae4SDave Jiang unsigned long flags, unsigned long cmd_mask, int num_flush,
270d6548ae4SDave Jiang struct resource *flush_wpq)
271d6548ae4SDave Jiang {
272d6548ae4SDave Jiang return __nvdimm_create(nvdimm_bus, provider_data, groups, flags,
273a1facc1fSDan Williams cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL);
274d6548ae4SDave Jiang }
275fd14602dSDan Williams void nvdimm_delete(struct nvdimm *nvdimm);
27604ad63f0SDan Williams void nvdimm_region_delete(struct nd_region *nd_region);
277d6548ae4SDave Jiang
27862232e45SDan Williams const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
27962232e45SDan Williams const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
28062232e45SDan Williams u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
28162232e45SDan Williams const struct nd_cmd_desc *desc, int idx, void *buf);
28262232e45SDan Williams u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
28362232e45SDan Williams const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
284efda1b5dSDan Williams const u32 *out_field, unsigned long remainder);
2854d88a97aSDan Williams int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count);
2861f7df6f8SDan Williams struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
2871f7df6f8SDan Williams struct nd_region_desc *ndr_desc);
2881f7df6f8SDan Williams struct nd_region *nvdimm_blk_region_create(struct nvdimm_bus *nvdimm_bus,
2891f7df6f8SDan Williams struct nd_region_desc *ndr_desc);
2901f7df6f8SDan Williams struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
2911f7df6f8SDan Williams struct nd_region_desc *ndr_desc);
292047fc8a1SRoss Zwisler void *nd_region_provider_data(struct nd_region *nd_region);
293047fc8a1SRoss Zwisler unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
294047fc8a1SRoss Zwisler void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
295eaf96153SDan Williams u64 nd_fletcher64(void *addr, size_t len, bool le);
296c5d4355dSPankaj Gupta int nvdimm_flush(struct nd_region *nd_region, struct bio *bio);
297c5d4355dSPankaj Gupta int generic_nvdimm_flush(struct nd_region *nd_region);
298f284a4f2SDan Williams int nvdimm_has_flush(struct nd_region *nd_region);
2990b277961SDan Williams int nvdimm_has_cache(struct nd_region *nd_region);
3007d988097SDave Jiang int nvdimm_in_overwrite(struct nvdimm *nvdimm);
301fefc1d97SPankaj Gupta bool is_nvdimm_sync(struct nd_region *nd_region);
3025deb67f7SRobin Murphy
nvdimm_ctl(struct nvdimm * nvdimm,unsigned int cmd,void * buf,unsigned int buf_len,int * cmd_rc)303f2989396SDave Jiang static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
304f2989396SDave Jiang unsigned int buf_len, int *cmd_rc)
305f2989396SDave Jiang {
306f2989396SDave Jiang struct nvdimm_bus *nvdimm_bus = nvdimm_to_bus(nvdimm);
307f2989396SDave Jiang struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
308f2989396SDave Jiang
309f2989396SDave Jiang return nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, cmd_rc);
310f2989396SDave Jiang }
311f2989396SDave Jiang
3125deb67f7SRobin Murphy #ifdef CONFIG_ARCH_HAS_PMEM_API
3135deb67f7SRobin Murphy #define ARCH_MEMREMAP_PMEM MEMREMAP_WB
3145deb67f7SRobin Murphy void arch_wb_cache_pmem(void *addr, size_t size);
3155deb67f7SRobin Murphy void arch_invalidate_pmem(void *addr, size_t size);
3165deb67f7SRobin Murphy #else
3175deb67f7SRobin Murphy #define ARCH_MEMREMAP_PMEM MEMREMAP_WT
arch_wb_cache_pmem(void * addr,size_t size)3185deb67f7SRobin Murphy static inline void arch_wb_cache_pmem(void *addr, size_t size)
3195deb67f7SRobin Murphy {
3205deb67f7SRobin Murphy }
arch_invalidate_pmem(void * addr,size_t size)3215deb67f7SRobin Murphy static inline void arch_invalidate_pmem(void *addr, size_t size)
3225deb67f7SRobin Murphy {
3235deb67f7SRobin Murphy }
3245deb67f7SRobin Murphy #endif
3255deb67f7SRobin Murphy
326b94d5230SDan Williams #endif /* __LIBNVDIMM_H__ */
327