| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * libnvdimm - Non-volatile-memory Devices Subsystem |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of version 2 of the GNU General Public License as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 11 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | | - * General Public License for more details. |
|---|
| 14 | 6 | */ |
|---|
| 15 | 7 | #ifndef __LIBNVDIMM_H__ |
|---|
| 16 | 8 | #define __LIBNVDIMM_H__ |
|---|
| .. | .. |
|---|
| 39 | 31 | NDD_UNARMED = 1, |
|---|
| 40 | 32 | /* locked memory devices should not be accessed */ |
|---|
| 41 | 33 | NDD_LOCKED = 2, |
|---|
| 34 | + /* memory under security wipes should not be accessed */ |
|---|
| 35 | + NDD_SECURITY_OVERWRITE = 3, |
|---|
| 36 | + /* tracking whether or not there is a pending device reference */ |
|---|
| 37 | + NDD_WORK_PENDING = 4, |
|---|
| 38 | + /* ignore / filter NSLABEL_FLAG_LOCAL for this DIMM, i.e. no aliasing */ |
|---|
| 39 | + NDD_NOBLK = 5, |
|---|
| 40 | + /* dimm supports namespace labels */ |
|---|
| 41 | + NDD_LABELING = 6, |
|---|
| 42 | 42 | |
|---|
| 43 | 43 | /* need to set a limit somewhere, but yes, this is likely overkill */ |
|---|
| 44 | 44 | ND_IOCTL_MAX_BUFLEN = SZ_4M, |
|---|
| .. | .. |
|---|
| 67 | 67 | DPA_RESOURCE_ADJUSTED = 1 << 0, |
|---|
| 68 | 68 | }; |
|---|
| 69 | 69 | |
|---|
| 70 | | -extern struct attribute_group nvdimm_bus_attribute_group; |
|---|
| 71 | | -extern struct attribute_group nvdimm_attribute_group; |
|---|
| 72 | | -extern struct attribute_group nd_device_attribute_group; |
|---|
| 73 | | -extern struct attribute_group nd_numa_attribute_group; |
|---|
| 74 | | -extern struct attribute_group nd_region_attribute_group; |
|---|
| 75 | | -extern struct attribute_group nd_mapping_attribute_group; |
|---|
| 76 | | - |
|---|
| 77 | 70 | struct nvdimm; |
|---|
| 78 | 71 | struct nvdimm_bus_descriptor; |
|---|
| 79 | 72 | typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc, |
|---|
| .. | .. |
|---|
| 83 | 76 | struct device_node; |
|---|
| 84 | 77 | struct nvdimm_bus_descriptor { |
|---|
| 85 | 78 | const struct attribute_group **attr_groups; |
|---|
| 86 | | - unsigned long bus_dsm_mask; |
|---|
| 87 | 79 | unsigned long cmd_mask; |
|---|
| 80 | + unsigned long dimm_family_mask; |
|---|
| 81 | + unsigned long bus_family_mask; |
|---|
| 88 | 82 | struct module *module; |
|---|
| 89 | 83 | char *provider_name; |
|---|
| 90 | 84 | struct device_node *of_node; |
|---|
| 91 | 85 | ndctl_fn ndctl; |
|---|
| 92 | 86 | int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); |
|---|
| 93 | 87 | int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, |
|---|
| 94 | | - struct nvdimm *nvdimm, unsigned int cmd); |
|---|
| 88 | + struct nvdimm *nvdimm, unsigned int cmd, void *data); |
|---|
| 89 | + const struct nvdimm_bus_fw_ops *fw_ops; |
|---|
| 95 | 90 | }; |
|---|
| 96 | 91 | |
|---|
| 97 | 92 | struct nd_cmd_desc { |
|---|
| .. | .. |
|---|
| 129 | 124 | void *provider_data; |
|---|
| 130 | 125 | int num_lanes; |
|---|
| 131 | 126 | int numa_node; |
|---|
| 127 | + int target_node; |
|---|
| 132 | 128 | unsigned long flags; |
|---|
| 133 | 129 | struct device_node *of_node; |
|---|
| 134 | 130 | int (*flush)(struct nd_region *nd_region, struct bio *bio); |
|---|
| .. | .. |
|---|
| 161 | 157 | |
|---|
| 162 | 158 | } |
|---|
| 163 | 159 | |
|---|
| 160 | +/* |
|---|
| 161 | + * Note that separate bits for locked + unlocked are defined so that |
|---|
| 162 | + * 'flags == 0' corresponds to an error / not-supported state. |
|---|
| 163 | + */ |
|---|
| 164 | +enum nvdimm_security_bits { |
|---|
| 165 | + NVDIMM_SECURITY_DISABLED, |
|---|
| 166 | + NVDIMM_SECURITY_UNLOCKED, |
|---|
| 167 | + NVDIMM_SECURITY_LOCKED, |
|---|
| 168 | + NVDIMM_SECURITY_FROZEN, |
|---|
| 169 | + NVDIMM_SECURITY_OVERWRITE, |
|---|
| 170 | +}; |
|---|
| 171 | + |
|---|
| 172 | +#define NVDIMM_PASSPHRASE_LEN 32 |
|---|
| 173 | +#define NVDIMM_KEY_DESC_LEN 22 |
|---|
| 174 | + |
|---|
| 175 | +struct nvdimm_key_data { |
|---|
| 176 | + u8 data[NVDIMM_PASSPHRASE_LEN]; |
|---|
| 177 | +}; |
|---|
| 178 | + |
|---|
| 179 | +enum nvdimm_passphrase_type { |
|---|
| 180 | + NVDIMM_USER, |
|---|
| 181 | + NVDIMM_MASTER, |
|---|
| 182 | +}; |
|---|
| 183 | + |
|---|
| 184 | +struct nvdimm_security_ops { |
|---|
| 185 | + unsigned long (*get_flags)(struct nvdimm *nvdimm, |
|---|
| 186 | + enum nvdimm_passphrase_type pass_type); |
|---|
| 187 | + int (*freeze)(struct nvdimm *nvdimm); |
|---|
| 188 | + int (*change_key)(struct nvdimm *nvdimm, |
|---|
| 189 | + const struct nvdimm_key_data *old_data, |
|---|
| 190 | + const struct nvdimm_key_data *new_data, |
|---|
| 191 | + enum nvdimm_passphrase_type pass_type); |
|---|
| 192 | + int (*unlock)(struct nvdimm *nvdimm, |
|---|
| 193 | + const struct nvdimm_key_data *key_data); |
|---|
| 194 | + int (*disable)(struct nvdimm *nvdimm, |
|---|
| 195 | + const struct nvdimm_key_data *key_data); |
|---|
| 196 | + int (*erase)(struct nvdimm *nvdimm, |
|---|
| 197 | + const struct nvdimm_key_data *key_data, |
|---|
| 198 | + enum nvdimm_passphrase_type pass_type); |
|---|
| 199 | + int (*overwrite)(struct nvdimm *nvdimm, |
|---|
| 200 | + const struct nvdimm_key_data *key_data); |
|---|
| 201 | + int (*query_overwrite)(struct nvdimm *nvdimm); |
|---|
| 202 | +}; |
|---|
| 203 | + |
|---|
| 204 | +enum nvdimm_fwa_state { |
|---|
| 205 | + NVDIMM_FWA_INVALID, |
|---|
| 206 | + NVDIMM_FWA_IDLE, |
|---|
| 207 | + NVDIMM_FWA_ARMED, |
|---|
| 208 | + NVDIMM_FWA_BUSY, |
|---|
| 209 | + NVDIMM_FWA_ARM_OVERFLOW, |
|---|
| 210 | +}; |
|---|
| 211 | + |
|---|
| 212 | +enum nvdimm_fwa_trigger { |
|---|
| 213 | + NVDIMM_FWA_ARM, |
|---|
| 214 | + NVDIMM_FWA_DISARM, |
|---|
| 215 | +}; |
|---|
| 216 | + |
|---|
| 217 | +enum nvdimm_fwa_capability { |
|---|
| 218 | + NVDIMM_FWA_CAP_INVALID, |
|---|
| 219 | + NVDIMM_FWA_CAP_NONE, |
|---|
| 220 | + NVDIMM_FWA_CAP_QUIESCE, |
|---|
| 221 | + NVDIMM_FWA_CAP_LIVE, |
|---|
| 222 | +}; |
|---|
| 223 | + |
|---|
| 224 | +enum nvdimm_fwa_result { |
|---|
| 225 | + NVDIMM_FWA_RESULT_INVALID, |
|---|
| 226 | + NVDIMM_FWA_RESULT_NONE, |
|---|
| 227 | + NVDIMM_FWA_RESULT_SUCCESS, |
|---|
| 228 | + NVDIMM_FWA_RESULT_NOTSTAGED, |
|---|
| 229 | + NVDIMM_FWA_RESULT_NEEDRESET, |
|---|
| 230 | + NVDIMM_FWA_RESULT_FAIL, |
|---|
| 231 | +}; |
|---|
| 232 | + |
|---|
| 233 | +struct nvdimm_bus_fw_ops { |
|---|
| 234 | + enum nvdimm_fwa_state (*activate_state) |
|---|
| 235 | + (struct nvdimm_bus_descriptor *nd_desc); |
|---|
| 236 | + enum nvdimm_fwa_capability (*capability) |
|---|
| 237 | + (struct nvdimm_bus_descriptor *nd_desc); |
|---|
| 238 | + int (*activate)(struct nvdimm_bus_descriptor *nd_desc); |
|---|
| 239 | +}; |
|---|
| 240 | + |
|---|
| 241 | +struct nvdimm_fw_ops { |
|---|
| 242 | + enum nvdimm_fwa_state (*activate_state)(struct nvdimm *nvdimm); |
|---|
| 243 | + enum nvdimm_fwa_result (*activate_result)(struct nvdimm *nvdimm); |
|---|
| 244 | + int (*arm)(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arg); |
|---|
| 245 | +}; |
|---|
| 246 | + |
|---|
| 164 | 247 | void badrange_init(struct badrange *badrange); |
|---|
| 165 | 248 | int badrange_add(struct badrange *badrange, u64 addr, u64 length); |
|---|
| 166 | 249 | void badrange_forget(struct badrange *badrange, phys_addr_t start, |
|---|
| .. | .. |
|---|
| 171 | 254 | struct nvdimm_bus_descriptor *nfit_desc); |
|---|
| 172 | 255 | void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus); |
|---|
| 173 | 256 | struct nvdimm_bus *to_nvdimm_bus(struct device *dev); |
|---|
| 257 | +struct nvdimm_bus *nvdimm_to_bus(struct nvdimm *nvdimm); |
|---|
| 174 | 258 | struct nvdimm *to_nvdimm(struct device *dev); |
|---|
| 175 | 259 | struct nd_region *to_nd_region(struct device *dev); |
|---|
| 176 | 260 | struct device *nd_region_dev(struct nd_region *nd_region); |
|---|
| .. | .. |
|---|
| 181 | 265 | struct kobject *nvdimm_kobj(struct nvdimm *nvdimm); |
|---|
| 182 | 266 | unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm); |
|---|
| 183 | 267 | void *nvdimm_provider_data(struct nvdimm *nvdimm); |
|---|
| 184 | | -struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, |
|---|
| 185 | | - const struct attribute_group **groups, unsigned long flags, |
|---|
| 186 | | - unsigned long cmd_mask, int num_flush, |
|---|
| 187 | | - struct resource *flush_wpq); |
|---|
| 268 | +struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, |
|---|
| 269 | + void *provider_data, const struct attribute_group **groups, |
|---|
| 270 | + unsigned long flags, unsigned long cmd_mask, int num_flush, |
|---|
| 271 | + struct resource *flush_wpq, const char *dimm_id, |
|---|
| 272 | + const struct nvdimm_security_ops *sec_ops, |
|---|
| 273 | + const struct nvdimm_fw_ops *fw_ops); |
|---|
| 274 | +static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, |
|---|
| 275 | + void *provider_data, const struct attribute_group **groups, |
|---|
| 276 | + unsigned long flags, unsigned long cmd_mask, int num_flush, |
|---|
| 277 | + struct resource *flush_wpq) |
|---|
| 278 | +{ |
|---|
| 279 | + return __nvdimm_create(nvdimm_bus, provider_data, groups, flags, |
|---|
| 280 | + cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL); |
|---|
| 281 | +} |
|---|
| 282 | + |
|---|
| 188 | 283 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); |
|---|
| 189 | 284 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); |
|---|
| 190 | 285 | u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, |
|---|
| .. | .. |
|---|
| 211 | 306 | int generic_nvdimm_flush(struct nd_region *nd_region); |
|---|
| 212 | 307 | int nvdimm_has_flush(struct nd_region *nd_region); |
|---|
| 213 | 308 | int nvdimm_has_cache(struct nd_region *nd_region); |
|---|
| 309 | +int nvdimm_in_overwrite(struct nvdimm *nvdimm); |
|---|
| 310 | +bool is_nvdimm_sync(struct nd_region *nd_region); |
|---|
| 311 | + |
|---|
| 312 | +static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
|---|
| 313 | + unsigned int buf_len, int *cmd_rc) |
|---|
| 314 | +{ |
|---|
| 315 | + struct nvdimm_bus *nvdimm_bus = nvdimm_to_bus(nvdimm); |
|---|
| 316 | + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); |
|---|
| 317 | + |
|---|
| 318 | + return nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, cmd_rc); |
|---|
| 319 | +} |
|---|
| 214 | 320 | |
|---|
| 215 | 321 | #ifdef CONFIG_ARCH_HAS_PMEM_API |
|---|
| 216 | 322 | #define ARCH_MEMREMAP_PMEM MEMREMAP_WB |
|---|