18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 68c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 88c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 98c2ecf20Sopenharmony_ci#include <linux/libnvdimm.h> 108c2ecf20Sopenharmony_ci#include <linux/genalloc.h> 118c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/mutex.h> 158c2ecf20Sopenharmony_ci#include <linux/ndctl.h> 168c2ecf20Sopenharmony_ci#include <linux/sizes.h> 178c2ecf20Sopenharmony_ci#include <linux/list.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <nd-core.h> 208c2ecf20Sopenharmony_ci#include <intel.h> 218c2ecf20Sopenharmony_ci#include <nfit.h> 228c2ecf20Sopenharmony_ci#include <nd.h> 238c2ecf20Sopenharmony_ci#include "nfit_test.h" 248c2ecf20Sopenharmony_ci#include "../watermark.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/copy_mc_test.h> 278c2ecf20Sopenharmony_ci#include <asm/mce.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Generate an NFIT table to describe the following topology: 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * BUS0: Interleaved PMEM regions, and aliasing with BLK regions 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * (a) (b) DIMM BLK-REGION 358c2ecf20Sopenharmony_ci * +----------+--------------+----------+---------+ 368c2ecf20Sopenharmony_ci * +------+ | blk2.0 | pm0.0 | blk2.1 | pm1.0 | 0 region2 378c2ecf20Sopenharmony_ci * | imc0 +--+- - - - - region0 - - - -+----------+ + 388c2ecf20Sopenharmony_ci * +--+---+ | blk3.0 | pm0.0 | blk3.1 | pm1.0 | 1 region3 398c2ecf20Sopenharmony_ci * | +----------+--------------v----------v v 408c2ecf20Sopenharmony_ci * +--+---+ | | 418c2ecf20Sopenharmony_ci * | cpu0 | region1 428c2ecf20Sopenharmony_ci * +--+---+ | | 438c2ecf20Sopenharmony_ci * | +-------------------------^----------^ ^ 448c2ecf20Sopenharmony_ci * +--+---+ | blk4.0 | pm1.0 | 2 region4 458c2ecf20Sopenharmony_ci * | imc1 +--+-------------------------+----------+ + 468c2ecf20Sopenharmony_ci * +------+ | blk5.0 | pm1.0 | 3 region5 478c2ecf20Sopenharmony_ci * +-------------------------+----------+-+-------+ 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * +--+---+ 508c2ecf20Sopenharmony_ci * | cpu1 | 518c2ecf20Sopenharmony_ci * +--+---+ (Hotplug DIMM) 528c2ecf20Sopenharmony_ci * | +----------------------------------------------+ 538c2ecf20Sopenharmony_ci * +--+---+ | blk6.0/pm7.0 | 4 region6/7 548c2ecf20Sopenharmony_ci * | imc0 +--+----------------------------------------------+ 558c2ecf20Sopenharmony_ci * +------+ 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * *) In this layout we have four dimms and two memory controllers in one 598c2ecf20Sopenharmony_ci * socket. Each unique interface (BLK or PMEM) to DPA space 608c2ecf20Sopenharmony_ci * is identified by a region device with a dynamically assigned id. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * *) The first portion of dimm0 and dimm1 are interleaved as REGION0. 638c2ecf20Sopenharmony_ci * A single PMEM namespace "pm0.0" is created using half of the 648c2ecf20Sopenharmony_ci * REGION0 SPA-range. REGION0 spans dimm0 and dimm1. PMEM namespace 658c2ecf20Sopenharmony_ci * allocate from from the bottom of a region. The unallocated 668c2ecf20Sopenharmony_ci * portion of REGION0 aliases with REGION2 and REGION3. That 678c2ecf20Sopenharmony_ci * unallacted capacity is reclaimed as BLK namespaces ("blk2.0" and 688c2ecf20Sopenharmony_ci * "blk3.0") starting at the base of each DIMM to offset (a) in those 698c2ecf20Sopenharmony_ci * DIMMs. "pm0.0", "blk2.0" and "blk3.0" are free-form readable 708c2ecf20Sopenharmony_ci * names that can be assigned to a namespace. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * *) In the last portion of dimm0 and dimm1 we have an interleaved 738c2ecf20Sopenharmony_ci * SPA range, REGION1, that spans those two dimms as well as dimm2 748c2ecf20Sopenharmony_ci * and dimm3. Some of REGION1 allocated to a PMEM namespace named 758c2ecf20Sopenharmony_ci * "pm1.0" the rest is reclaimed in 4 BLK namespaces (for each 768c2ecf20Sopenharmony_ci * dimm in the interleave set), "blk2.1", "blk3.1", "blk4.0", and 778c2ecf20Sopenharmony_ci * "blk5.0". 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * *) The portion of dimm2 and dimm3 that do not participate in the 808c2ecf20Sopenharmony_ci * REGION1 interleaved SPA range (i.e. the DPA address below offset 818c2ecf20Sopenharmony_ci * (b) are also included in the "blk4.0" and "blk5.0" namespaces. 828c2ecf20Sopenharmony_ci * Note, that BLK namespaces need not be contiguous in DPA-space, and 838c2ecf20Sopenharmony_ci * can consume aliased capacity from multiple interleave sets. 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * BUS1: Legacy NVDIMM (single contiguous range) 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * region2 888c2ecf20Sopenharmony_ci * +---------------------+ 898c2ecf20Sopenharmony_ci * |---------------------| 908c2ecf20Sopenharmony_ci * || pm2.0 || 918c2ecf20Sopenharmony_ci * |---------------------| 928c2ecf20Sopenharmony_ci * +---------------------+ 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * *) A NFIT-table may describe a simple system-physical-address range 958c2ecf20Sopenharmony_ci * with no BLK aliasing. This type of region may optionally 968c2ecf20Sopenharmony_ci * reference an NVDIMM. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cienum { 998c2ecf20Sopenharmony_ci NUM_PM = 3, 1008c2ecf20Sopenharmony_ci NUM_DCR = 5, 1018c2ecf20Sopenharmony_ci NUM_HINTS = 8, 1028c2ecf20Sopenharmony_ci NUM_BDW = NUM_DCR, 1038c2ecf20Sopenharmony_ci NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, 1048c2ecf20Sopenharmony_ci NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ 1058c2ecf20Sopenharmony_ci + 4 /* spa1 iset */ + 1 /* spa11 iset */, 1068c2ecf20Sopenharmony_ci DIMM_SIZE = SZ_32M, 1078c2ecf20Sopenharmony_ci LABEL_SIZE = SZ_128K, 1088c2ecf20Sopenharmony_ci SPA_VCD_SIZE = SZ_4M, 1098c2ecf20Sopenharmony_ci SPA0_SIZE = DIMM_SIZE, 1108c2ecf20Sopenharmony_ci SPA1_SIZE = DIMM_SIZE*2, 1118c2ecf20Sopenharmony_ci SPA2_SIZE = DIMM_SIZE, 1128c2ecf20Sopenharmony_ci BDW_SIZE = 64 << 8, 1138c2ecf20Sopenharmony_ci DCR_SIZE = 12, 1148c2ecf20Sopenharmony_ci NUM_NFITS = 2, /* permit testing multiple NFITs per system */ 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistruct nfit_test_dcr { 1188c2ecf20Sopenharmony_ci __le64 bdw_addr; 1198c2ecf20Sopenharmony_ci __le32 bdw_status; 1208c2ecf20Sopenharmony_ci __u8 aperature[BDW_SIZE]; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define NFIT_DIMM_HANDLE(node, socket, imc, chan, dimm) \ 1248c2ecf20Sopenharmony_ci (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \ 1258c2ecf20Sopenharmony_ci | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf)) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic u32 handle[] = { 1288c2ecf20Sopenharmony_ci [0] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0), 1298c2ecf20Sopenharmony_ci [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), 1308c2ecf20Sopenharmony_ci [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), 1318c2ecf20Sopenharmony_ci [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), 1328c2ecf20Sopenharmony_ci [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), 1338c2ecf20Sopenharmony_ci [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0), 1348c2ecf20Sopenharmony_ci [6] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 1), 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic unsigned long dimm_fail_cmd_flags[ARRAY_SIZE(handle)]; 1388c2ecf20Sopenharmony_cistatic int dimm_fail_cmd_code[ARRAY_SIZE(handle)]; 1398c2ecf20Sopenharmony_cistruct nfit_test_sec { 1408c2ecf20Sopenharmony_ci u8 state; 1418c2ecf20Sopenharmony_ci u8 ext_state; 1428c2ecf20Sopenharmony_ci u8 old_state; 1438c2ecf20Sopenharmony_ci u8 passphrase[32]; 1448c2ecf20Sopenharmony_ci u8 master_passphrase[32]; 1458c2ecf20Sopenharmony_ci u64 overwrite_end_time; 1468c2ecf20Sopenharmony_ci} dimm_sec_info[NUM_DCR]; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const struct nd_intel_smart smart_def = { 1498c2ecf20Sopenharmony_ci .flags = ND_INTEL_SMART_HEALTH_VALID 1508c2ecf20Sopenharmony_ci | ND_INTEL_SMART_SPARES_VALID 1518c2ecf20Sopenharmony_ci | ND_INTEL_SMART_ALARM_VALID 1528c2ecf20Sopenharmony_ci | ND_INTEL_SMART_USED_VALID 1538c2ecf20Sopenharmony_ci | ND_INTEL_SMART_SHUTDOWN_VALID 1548c2ecf20Sopenharmony_ci | ND_INTEL_SMART_SHUTDOWN_COUNT_VALID 1558c2ecf20Sopenharmony_ci | ND_INTEL_SMART_MTEMP_VALID 1568c2ecf20Sopenharmony_ci | ND_INTEL_SMART_CTEMP_VALID, 1578c2ecf20Sopenharmony_ci .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, 1588c2ecf20Sopenharmony_ci .media_temperature = 23 * 16, 1598c2ecf20Sopenharmony_ci .ctrl_temperature = 25 * 16, 1608c2ecf20Sopenharmony_ci .pmic_temperature = 40 * 16, 1618c2ecf20Sopenharmony_ci .spares = 75, 1628c2ecf20Sopenharmony_ci .alarm_flags = ND_INTEL_SMART_SPARE_TRIP 1638c2ecf20Sopenharmony_ci | ND_INTEL_SMART_TEMP_TRIP, 1648c2ecf20Sopenharmony_ci .ait_status = 1, 1658c2ecf20Sopenharmony_ci .life_used = 5, 1668c2ecf20Sopenharmony_ci .shutdown_state = 0, 1678c2ecf20Sopenharmony_ci .shutdown_count = 42, 1688c2ecf20Sopenharmony_ci .vendor_size = 0, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct nfit_test_fw { 1728c2ecf20Sopenharmony_ci enum intel_fw_update_state state; 1738c2ecf20Sopenharmony_ci u32 context; 1748c2ecf20Sopenharmony_ci u64 version; 1758c2ecf20Sopenharmony_ci u32 size_received; 1768c2ecf20Sopenharmony_ci u64 end_time; 1778c2ecf20Sopenharmony_ci bool armed; 1788c2ecf20Sopenharmony_ci bool missed_activate; 1798c2ecf20Sopenharmony_ci unsigned long last_activate; 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistruct nfit_test { 1838c2ecf20Sopenharmony_ci struct acpi_nfit_desc acpi_desc; 1848c2ecf20Sopenharmony_ci struct platform_device pdev; 1858c2ecf20Sopenharmony_ci struct list_head resources; 1868c2ecf20Sopenharmony_ci void *nfit_buf; 1878c2ecf20Sopenharmony_ci dma_addr_t nfit_dma; 1888c2ecf20Sopenharmony_ci size_t nfit_size; 1898c2ecf20Sopenharmony_ci size_t nfit_filled; 1908c2ecf20Sopenharmony_ci int dcr_idx; 1918c2ecf20Sopenharmony_ci int num_dcr; 1928c2ecf20Sopenharmony_ci int num_pm; 1938c2ecf20Sopenharmony_ci void **dimm; 1948c2ecf20Sopenharmony_ci dma_addr_t *dimm_dma; 1958c2ecf20Sopenharmony_ci void **flush; 1968c2ecf20Sopenharmony_ci dma_addr_t *flush_dma; 1978c2ecf20Sopenharmony_ci void **label; 1988c2ecf20Sopenharmony_ci dma_addr_t *label_dma; 1998c2ecf20Sopenharmony_ci void **spa_set; 2008c2ecf20Sopenharmony_ci dma_addr_t *spa_set_dma; 2018c2ecf20Sopenharmony_ci struct nfit_test_dcr **dcr; 2028c2ecf20Sopenharmony_ci dma_addr_t *dcr_dma; 2038c2ecf20Sopenharmony_ci int (*alloc)(struct nfit_test *t); 2048c2ecf20Sopenharmony_ci void (*setup)(struct nfit_test *t); 2058c2ecf20Sopenharmony_ci int setup_hotplug; 2068c2ecf20Sopenharmony_ci union acpi_object **_fit; 2078c2ecf20Sopenharmony_ci dma_addr_t _fit_dma; 2088c2ecf20Sopenharmony_ci struct ars_state { 2098c2ecf20Sopenharmony_ci struct nd_cmd_ars_status *ars_status; 2108c2ecf20Sopenharmony_ci unsigned long deadline; 2118c2ecf20Sopenharmony_ci spinlock_t lock; 2128c2ecf20Sopenharmony_ci } ars_state; 2138c2ecf20Sopenharmony_ci struct device *dimm_dev[ARRAY_SIZE(handle)]; 2148c2ecf20Sopenharmony_ci struct nd_intel_smart *smart; 2158c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *smart_threshold; 2168c2ecf20Sopenharmony_ci struct badrange badrange; 2178c2ecf20Sopenharmony_ci struct work_struct work; 2188c2ecf20Sopenharmony_ci struct nfit_test_fw *fw; 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic struct workqueue_struct *nfit_wq; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic struct gen_pool *nfit_pool; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const char zero_key[NVDIMM_PASSPHRASE_LEN]; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic struct nfit_test *to_nfit_test(struct device *dev) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return container_of(pdev, struct nfit_test, pdev); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int nd_intel_test_get_fw_info(struct nfit_test *t, 2358c2ecf20Sopenharmony_ci struct nd_intel_fw_info *nd_cmd, unsigned int buf_len, 2368c2ecf20Sopenharmony_ci int idx) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 2398c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[idx]; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p, buf_len: %u, idx: %d\n", 2428c2ecf20Sopenharmony_ci __func__, t, nd_cmd, buf_len, idx); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci nd_cmd->status = 0; 2488c2ecf20Sopenharmony_ci nd_cmd->storage_size = INTEL_FW_STORAGE_SIZE; 2498c2ecf20Sopenharmony_ci nd_cmd->max_send_len = INTEL_FW_MAX_SEND_LEN; 2508c2ecf20Sopenharmony_ci nd_cmd->query_interval = INTEL_FW_QUERY_INTERVAL; 2518c2ecf20Sopenharmony_ci nd_cmd->max_query_time = INTEL_FW_QUERY_MAX_TIME; 2528c2ecf20Sopenharmony_ci nd_cmd->update_cap = 0; 2538c2ecf20Sopenharmony_ci nd_cmd->fis_version = INTEL_FW_FIS_VERSION; 2548c2ecf20Sopenharmony_ci nd_cmd->run_version = 0; 2558c2ecf20Sopenharmony_ci nd_cmd->updated_version = fw->version; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int nd_intel_test_start_update(struct nfit_test *t, 2618c2ecf20Sopenharmony_ci struct nd_intel_fw_start *nd_cmd, unsigned int buf_len, 2628c2ecf20Sopenharmony_ci int idx) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 2658c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[idx]; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 2688c2ecf20Sopenharmony_ci __func__, t, nd_cmd, buf_len, idx); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 2718c2ecf20Sopenharmony_ci return -EINVAL; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (fw->state != FW_STATE_NEW) { 2748c2ecf20Sopenharmony_ci /* extended status, FW update in progress */ 2758c2ecf20Sopenharmony_ci nd_cmd->status = 0x10007; 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci fw->state = FW_STATE_IN_PROGRESS; 2808c2ecf20Sopenharmony_ci fw->context++; 2818c2ecf20Sopenharmony_ci fw->size_received = 0; 2828c2ecf20Sopenharmony_ci nd_cmd->status = 0; 2838c2ecf20Sopenharmony_ci nd_cmd->context = fw->context; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: context issued: %#x\n", __func__, nd_cmd->context); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int nd_intel_test_send_data(struct nfit_test *t, 2918c2ecf20Sopenharmony_ci struct nd_intel_fw_send_data *nd_cmd, unsigned int buf_len, 2928c2ecf20Sopenharmony_ci int idx) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 2958c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[idx]; 2968c2ecf20Sopenharmony_ci u32 *status = (u32 *)&nd_cmd->data[nd_cmd->length]; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 2998c2ecf20Sopenharmony_ci __func__, t, nd_cmd, buf_len, idx); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: cmd->status: %#x\n", __func__, *status); 3068c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: cmd->data[0]: %#x\n", __func__, nd_cmd->data[0]); 3078c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: cmd->data[%u]: %#x\n", __func__, nd_cmd->length-1, 3088c2ecf20Sopenharmony_ci nd_cmd->data[nd_cmd->length-1]); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (fw->state != FW_STATE_IN_PROGRESS) { 3118c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: not in IN_PROGRESS state\n", __func__); 3128c2ecf20Sopenharmony_ci *status = 0x5; 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (nd_cmd->context != fw->context) { 3178c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 3188c2ecf20Sopenharmony_ci __func__, nd_cmd->context, fw->context); 3198c2ecf20Sopenharmony_ci *status = 0x10007; 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * check offset + len > size of fw storage 3258c2ecf20Sopenharmony_ci * check length is > max send length 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci if (nd_cmd->offset + nd_cmd->length > INTEL_FW_STORAGE_SIZE || 3288c2ecf20Sopenharmony_ci nd_cmd->length > INTEL_FW_MAX_SEND_LEN) { 3298c2ecf20Sopenharmony_ci *status = 0x3; 3308c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: buffer boundary violation\n", __func__); 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci fw->size_received += nd_cmd->length; 3358c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: copying %u bytes, %u bytes so far\n", 3368c2ecf20Sopenharmony_ci __func__, nd_cmd->length, fw->size_received); 3378c2ecf20Sopenharmony_ci *status = 0; 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int nd_intel_test_finish_fw(struct nfit_test *t, 3428c2ecf20Sopenharmony_ci struct nd_intel_fw_finish_update *nd_cmd, 3438c2ecf20Sopenharmony_ci unsigned int buf_len, int idx) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 3468c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[idx]; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 3498c2ecf20Sopenharmony_ci __func__, t, nd_cmd, buf_len, idx); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (fw->state == FW_STATE_UPDATED) { 3528c2ecf20Sopenharmony_ci /* update already done, need activation */ 3538c2ecf20Sopenharmony_ci nd_cmd->status = 0x20007; 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: context: %#x ctrl_flags: %#x\n", 3588c2ecf20Sopenharmony_ci __func__, nd_cmd->context, nd_cmd->ctrl_flags); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci switch (nd_cmd->ctrl_flags) { 3618c2ecf20Sopenharmony_ci case 0: /* finish */ 3628c2ecf20Sopenharmony_ci if (nd_cmd->context != fw->context) { 3638c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 3648c2ecf20Sopenharmony_ci __func__, nd_cmd->context, 3658c2ecf20Sopenharmony_ci fw->context); 3668c2ecf20Sopenharmony_ci nd_cmd->status = 0x10007; 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci nd_cmd->status = 0; 3708c2ecf20Sopenharmony_ci fw->state = FW_STATE_VERIFY; 3718c2ecf20Sopenharmony_ci /* set 1 second of time for firmware "update" */ 3728c2ecf20Sopenharmony_ci fw->end_time = jiffies + HZ; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci case 1: /* abort */ 3768c2ecf20Sopenharmony_ci fw->size_received = 0; 3778c2ecf20Sopenharmony_ci /* successfully aborted status */ 3788c2ecf20Sopenharmony_ci nd_cmd->status = 0x40007; 3798c2ecf20Sopenharmony_ci fw->state = FW_STATE_NEW; 3808c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: abort successful\n", __func__); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci default: /* bad control flag */ 3848c2ecf20Sopenharmony_ci dev_warn(dev, "%s: unknown control flag: %#x\n", 3858c2ecf20Sopenharmony_ci __func__, nd_cmd->ctrl_flags); 3868c2ecf20Sopenharmony_ci return -EINVAL; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int nd_intel_test_finish_query(struct nfit_test *t, 3938c2ecf20Sopenharmony_ci struct nd_intel_fw_finish_query *nd_cmd, 3948c2ecf20Sopenharmony_ci unsigned int buf_len, int idx) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 3978c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[idx]; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(nfit_test: %p nd_cmd: %p buf_len: %u idx: %d)\n", 4008c2ecf20Sopenharmony_ci __func__, t, nd_cmd, buf_len, idx); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 4038c2ecf20Sopenharmony_ci return -EINVAL; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (nd_cmd->context != fw->context) { 4068c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: incorrect context: in: %#x correct: %#x\n", 4078c2ecf20Sopenharmony_ci __func__, nd_cmd->context, fw->context); 4088c2ecf20Sopenharmony_ci nd_cmd->status = 0x10007; 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci dev_dbg(dev, "%s context: %#x\n", __func__, nd_cmd->context); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci switch (fw->state) { 4158c2ecf20Sopenharmony_ci case FW_STATE_NEW: 4168c2ecf20Sopenharmony_ci nd_cmd->updated_fw_rev = 0; 4178c2ecf20Sopenharmony_ci nd_cmd->status = 0; 4188c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: new state\n", __func__); 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci case FW_STATE_IN_PROGRESS: 4228c2ecf20Sopenharmony_ci /* sequencing error */ 4238c2ecf20Sopenharmony_ci nd_cmd->status = 0x40007; 4248c2ecf20Sopenharmony_ci nd_cmd->updated_fw_rev = 0; 4258c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: sequence error\n", __func__); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci case FW_STATE_VERIFY: 4298c2ecf20Sopenharmony_ci if (time_is_after_jiffies64(fw->end_time)) { 4308c2ecf20Sopenharmony_ci nd_cmd->updated_fw_rev = 0; 4318c2ecf20Sopenharmony_ci nd_cmd->status = 0x20007; 4328c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: still verifying\n", __func__); 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: transition out verify\n", __func__); 4368c2ecf20Sopenharmony_ci fw->state = FW_STATE_UPDATED; 4378c2ecf20Sopenharmony_ci fw->missed_activate = false; 4388c2ecf20Sopenharmony_ci /* fall through */ 4398c2ecf20Sopenharmony_ci case FW_STATE_UPDATED: 4408c2ecf20Sopenharmony_ci nd_cmd->status = 0; 4418c2ecf20Sopenharmony_ci /* bogus test version */ 4428c2ecf20Sopenharmony_ci fw->version = nd_cmd->updated_fw_rev = 4438c2ecf20Sopenharmony_ci INTEL_FW_FAKE_VERSION; 4448c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: updated\n", __func__); 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci default: /* we should never get here */ 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, 4558c2ecf20Sopenharmony_ci unsigned int buf_len) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci nd_cmd->status = 0; 4618c2ecf20Sopenharmony_ci nd_cmd->config_size = LABEL_SIZE; 4628c2ecf20Sopenharmony_ci nd_cmd->max_xfer = SZ_4K; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr 4688c2ecf20Sopenharmony_ci *nd_cmd, unsigned int buf_len, void *label) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci unsigned int len, offset = nd_cmd->in_offset; 4718c2ecf20Sopenharmony_ci int rc; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci if (offset >= LABEL_SIZE) 4768c2ecf20Sopenharmony_ci return -EINVAL; 4778c2ecf20Sopenharmony_ci if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci nd_cmd->status = 0; 4818c2ecf20Sopenharmony_ci len = min(nd_cmd->in_length, LABEL_SIZE - offset); 4828c2ecf20Sopenharmony_ci memcpy(nd_cmd->out_buf, label + offset, len); 4838c2ecf20Sopenharmony_ci rc = buf_len - sizeof(*nd_cmd) - len; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return rc; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, 4898c2ecf20Sopenharmony_ci unsigned int buf_len, void *label) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci unsigned int len, offset = nd_cmd->in_offset; 4928c2ecf20Sopenharmony_ci u32 *status; 4938c2ecf20Sopenharmony_ci int rc; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 4968c2ecf20Sopenharmony_ci return -EINVAL; 4978c2ecf20Sopenharmony_ci if (offset >= LABEL_SIZE) 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd); 5038c2ecf20Sopenharmony_ci *status = 0; 5048c2ecf20Sopenharmony_ci len = min(nd_cmd->in_length, LABEL_SIZE - offset); 5058c2ecf20Sopenharmony_ci memcpy(label + offset, nd_cmd->in_buf, len); 5068c2ecf20Sopenharmony_ci rc = buf_len - sizeof(*nd_cmd) - (len + 4); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return rc; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#define NFIT_TEST_CLEAR_ERR_UNIT 256 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, 5148c2ecf20Sopenharmony_ci unsigned int buf_len) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci int ars_recs; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 5198c2ecf20Sopenharmony_ci return -EINVAL; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* for testing, only store up to n records that fit within 4k */ 5228c2ecf20Sopenharmony_ci ars_recs = SZ_4K / sizeof(struct nd_ars_record); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status) 5258c2ecf20Sopenharmony_ci + ars_recs * sizeof(struct nd_ars_record); 5268c2ecf20Sopenharmony_ci nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; 5278c2ecf20Sopenharmony_ci nd_cmd->clear_err_unit = NFIT_TEST_CLEAR_ERR_UNIT; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void post_ars_status(struct ars_state *ars_state, 5338c2ecf20Sopenharmony_ci struct badrange *badrange, u64 addr, u64 len) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct nd_cmd_ars_status *ars_status; 5368c2ecf20Sopenharmony_ci struct nd_ars_record *ars_record; 5378c2ecf20Sopenharmony_ci struct badrange_entry *be; 5388c2ecf20Sopenharmony_ci u64 end = addr + len - 1; 5398c2ecf20Sopenharmony_ci int i = 0; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci ars_state->deadline = jiffies + 1*HZ; 5428c2ecf20Sopenharmony_ci ars_status = ars_state->ars_status; 5438c2ecf20Sopenharmony_ci ars_status->status = 0; 5448c2ecf20Sopenharmony_ci ars_status->address = addr; 5458c2ecf20Sopenharmony_ci ars_status->length = len; 5468c2ecf20Sopenharmony_ci ars_status->type = ND_ARS_PERSISTENT; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci spin_lock(&badrange->lock); 5498c2ecf20Sopenharmony_ci list_for_each_entry(be, &badrange->list, list) { 5508c2ecf20Sopenharmony_ci u64 be_end = be->start + be->length - 1; 5518c2ecf20Sopenharmony_ci u64 rstart, rend; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* skip entries outside the range */ 5548c2ecf20Sopenharmony_ci if (be_end < addr || be->start > end) 5558c2ecf20Sopenharmony_ci continue; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci rstart = (be->start < addr) ? addr : be->start; 5588c2ecf20Sopenharmony_ci rend = (be_end < end) ? be_end : end; 5598c2ecf20Sopenharmony_ci ars_record = &ars_status->records[i]; 5608c2ecf20Sopenharmony_ci ars_record->handle = 0; 5618c2ecf20Sopenharmony_ci ars_record->err_address = rstart; 5628c2ecf20Sopenharmony_ci ars_record->length = rend - rstart + 1; 5638c2ecf20Sopenharmony_ci i++; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci spin_unlock(&badrange->lock); 5668c2ecf20Sopenharmony_ci ars_status->num_records = i; 5678c2ecf20Sopenharmony_ci ars_status->out_length = sizeof(struct nd_cmd_ars_status) 5688c2ecf20Sopenharmony_ci + i * sizeof(struct nd_ars_record); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_start(struct nfit_test *t, 5728c2ecf20Sopenharmony_ci struct ars_state *ars_state, 5738c2ecf20Sopenharmony_ci struct nd_cmd_ars_start *ars_start, unsigned int buf_len, 5748c2ecf20Sopenharmony_ci int *cmd_rc) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci if (buf_len < sizeof(*ars_start)) 5778c2ecf20Sopenharmony_ci return -EINVAL; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci spin_lock(&ars_state->lock); 5808c2ecf20Sopenharmony_ci if (time_before(jiffies, ars_state->deadline)) { 5818c2ecf20Sopenharmony_ci ars_start->status = NFIT_ARS_START_BUSY; 5828c2ecf20Sopenharmony_ci *cmd_rc = -EBUSY; 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci ars_start->status = 0; 5858c2ecf20Sopenharmony_ci ars_start->scrub_time = 1; 5868c2ecf20Sopenharmony_ci post_ars_status(ars_state, &t->badrange, ars_start->address, 5878c2ecf20Sopenharmony_ci ars_start->length); 5888c2ecf20Sopenharmony_ci *cmd_rc = 0; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci spin_unlock(&ars_state->lock); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_status(struct ars_state *ars_state, 5968c2ecf20Sopenharmony_ci struct nd_cmd_ars_status *ars_status, unsigned int buf_len, 5978c2ecf20Sopenharmony_ci int *cmd_rc) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci if (buf_len < ars_state->ars_status->out_length) 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci spin_lock(&ars_state->lock); 6038c2ecf20Sopenharmony_ci if (time_before(jiffies, ars_state->deadline)) { 6048c2ecf20Sopenharmony_ci memset(ars_status, 0, buf_len); 6058c2ecf20Sopenharmony_ci ars_status->status = NFIT_ARS_STATUS_BUSY; 6068c2ecf20Sopenharmony_ci ars_status->out_length = sizeof(*ars_status); 6078c2ecf20Sopenharmony_ci *cmd_rc = -EBUSY; 6088c2ecf20Sopenharmony_ci } else { 6098c2ecf20Sopenharmony_ci memcpy(ars_status, ars_state->ars_status, 6108c2ecf20Sopenharmony_ci ars_state->ars_status->out_length); 6118c2ecf20Sopenharmony_ci *cmd_rc = 0; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci spin_unlock(&ars_state->lock); 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int nfit_test_cmd_clear_error(struct nfit_test *t, 6188c2ecf20Sopenharmony_ci struct nd_cmd_clear_error *clear_err, 6198c2ecf20Sopenharmony_ci unsigned int buf_len, int *cmd_rc) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci const u64 mask = NFIT_TEST_CLEAR_ERR_UNIT - 1; 6228c2ecf20Sopenharmony_ci if (buf_len < sizeof(*clear_err)) 6238c2ecf20Sopenharmony_ci return -EINVAL; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if ((clear_err->address & mask) || (clear_err->length & mask)) 6268c2ecf20Sopenharmony_ci return -EINVAL; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci badrange_forget(&t->badrange, clear_err->address, clear_err->length); 6298c2ecf20Sopenharmony_ci clear_err->status = 0; 6308c2ecf20Sopenharmony_ci clear_err->cleared = clear_err->length; 6318c2ecf20Sopenharmony_ci *cmd_rc = 0; 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistruct region_search_spa { 6368c2ecf20Sopenharmony_ci u64 addr; 6378c2ecf20Sopenharmony_ci struct nd_region *region; 6388c2ecf20Sopenharmony_ci}; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int is_region_device(struct device *dev) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci return !strncmp(dev->kobj.name, "region", 6); 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic int nfit_test_search_region_spa(struct device *dev, void *data) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct region_search_spa *ctx = data; 6488c2ecf20Sopenharmony_ci struct nd_region *nd_region; 6498c2ecf20Sopenharmony_ci resource_size_t ndr_end; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (!is_region_device(dev)) 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci nd_region = to_nd_region(dev); 6558c2ecf20Sopenharmony_ci ndr_end = nd_region->ndr_start + nd_region->ndr_size; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (ctx->addr >= nd_region->ndr_start && ctx->addr < ndr_end) { 6588c2ecf20Sopenharmony_ci ctx->region = nd_region; 6598c2ecf20Sopenharmony_ci return 1; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int nfit_test_search_spa(struct nvdimm_bus *bus, 6668c2ecf20Sopenharmony_ci struct nd_cmd_translate_spa *spa) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci int ret; 6698c2ecf20Sopenharmony_ci struct nd_region *nd_region = NULL; 6708c2ecf20Sopenharmony_ci struct nvdimm *nvdimm = NULL; 6718c2ecf20Sopenharmony_ci struct nd_mapping *nd_mapping = NULL; 6728c2ecf20Sopenharmony_ci struct region_search_spa ctx = { 6738c2ecf20Sopenharmony_ci .addr = spa->spa, 6748c2ecf20Sopenharmony_ci .region = NULL, 6758c2ecf20Sopenharmony_ci }; 6768c2ecf20Sopenharmony_ci u64 dpa; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ret = device_for_each_child(&bus->dev, &ctx, 6798c2ecf20Sopenharmony_ci nfit_test_search_region_spa); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (!ret) 6828c2ecf20Sopenharmony_ci return -ENODEV; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci nd_region = ctx.region; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci dpa = ctx.addr - nd_region->ndr_start; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* 6898c2ecf20Sopenharmony_ci * last dimm is selected for test 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci nd_mapping = &nd_region->mapping[nd_region->ndr_mappings - 1]; 6928c2ecf20Sopenharmony_ci nvdimm = nd_mapping->nvdimm; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci spa->devices[0].nfit_device_handle = handle[nvdimm->id]; 6958c2ecf20Sopenharmony_ci spa->num_nvdimms = 1; 6968c2ecf20Sopenharmony_ci spa->devices[0].dpa = dpa; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int nfit_test_cmd_translate_spa(struct nvdimm_bus *bus, 7028c2ecf20Sopenharmony_ci struct nd_cmd_translate_spa *spa, unsigned int buf_len) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci if (buf_len < spa->translate_length) 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (nfit_test_search_spa(bus, spa) < 0 || !spa->num_nvdimms) 7088c2ecf20Sopenharmony_ci spa->status = 2; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int nfit_test_cmd_smart(struct nd_intel_smart *smart, unsigned int buf_len, 7148c2ecf20Sopenharmony_ci struct nd_intel_smart *smart_data) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci if (buf_len < sizeof(*smart)) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci memcpy(smart, smart_data, sizeof(*smart)); 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int nfit_test_cmd_smart_threshold( 7238c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *out, 7248c2ecf20Sopenharmony_ci unsigned int buf_len, 7258c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *smart_t) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci if (buf_len < sizeof(*smart_t)) 7288c2ecf20Sopenharmony_ci return -EINVAL; 7298c2ecf20Sopenharmony_ci memcpy(out, smart_t, sizeof(*smart_t)); 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void smart_notify(struct device *bus_dev, 7348c2ecf20Sopenharmony_ci struct device *dimm_dev, struct nd_intel_smart *smart, 7358c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *thresh) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci dev_dbg(dimm_dev, "%s: alarm: %#x spares: %d (%d) mtemp: %d (%d) ctemp: %d (%d)\n", 7388c2ecf20Sopenharmony_ci __func__, thresh->alarm_control, thresh->spares, 7398c2ecf20Sopenharmony_ci smart->spares, thresh->media_temperature, 7408c2ecf20Sopenharmony_ci smart->media_temperature, thresh->ctrl_temperature, 7418c2ecf20Sopenharmony_ci smart->ctrl_temperature); 7428c2ecf20Sopenharmony_ci if (((thresh->alarm_control & ND_INTEL_SMART_SPARE_TRIP) 7438c2ecf20Sopenharmony_ci && smart->spares 7448c2ecf20Sopenharmony_ci <= thresh->spares) 7458c2ecf20Sopenharmony_ci || ((thresh->alarm_control & ND_INTEL_SMART_TEMP_TRIP) 7468c2ecf20Sopenharmony_ci && smart->media_temperature 7478c2ecf20Sopenharmony_ci >= thresh->media_temperature) 7488c2ecf20Sopenharmony_ci || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) 7498c2ecf20Sopenharmony_ci && smart->ctrl_temperature 7508c2ecf20Sopenharmony_ci >= thresh->ctrl_temperature) 7518c2ecf20Sopenharmony_ci || (smart->health != ND_INTEL_SMART_NON_CRITICAL_HEALTH) 7528c2ecf20Sopenharmony_ci || (smart->shutdown_state != 0)) { 7538c2ecf20Sopenharmony_ci device_lock(bus_dev); 7548c2ecf20Sopenharmony_ci __acpi_nvdimm_notify(dimm_dev, 0x81); 7558c2ecf20Sopenharmony_ci device_unlock(bus_dev); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic int nfit_test_cmd_smart_set_threshold( 7608c2ecf20Sopenharmony_ci struct nd_intel_smart_set_threshold *in, 7618c2ecf20Sopenharmony_ci unsigned int buf_len, 7628c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *thresh, 7638c2ecf20Sopenharmony_ci struct nd_intel_smart *smart, 7648c2ecf20Sopenharmony_ci struct device *bus_dev, struct device *dimm_dev) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci unsigned int size; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci size = sizeof(*in) - 4; 7698c2ecf20Sopenharmony_ci if (buf_len < size) 7708c2ecf20Sopenharmony_ci return -EINVAL; 7718c2ecf20Sopenharmony_ci memcpy(thresh->data, in, size); 7728c2ecf20Sopenharmony_ci in->status = 0; 7738c2ecf20Sopenharmony_ci smart_notify(bus_dev, dimm_dev, smart, thresh); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return 0; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic int nfit_test_cmd_smart_inject( 7798c2ecf20Sopenharmony_ci struct nd_intel_smart_inject *inj, 7808c2ecf20Sopenharmony_ci unsigned int buf_len, 7818c2ecf20Sopenharmony_ci struct nd_intel_smart_threshold *thresh, 7828c2ecf20Sopenharmony_ci struct nd_intel_smart *smart, 7838c2ecf20Sopenharmony_ci struct device *bus_dev, struct device *dimm_dev) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci if (buf_len != sizeof(*inj)) 7868c2ecf20Sopenharmony_ci return -EINVAL; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (inj->flags & ND_INTEL_SMART_INJECT_MTEMP) { 7898c2ecf20Sopenharmony_ci if (inj->mtemp_enable) 7908c2ecf20Sopenharmony_ci smart->media_temperature = inj->media_temperature; 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci smart->media_temperature = smart_def.media_temperature; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci if (inj->flags & ND_INTEL_SMART_INJECT_SPARE) { 7958c2ecf20Sopenharmony_ci if (inj->spare_enable) 7968c2ecf20Sopenharmony_ci smart->spares = inj->spares; 7978c2ecf20Sopenharmony_ci else 7988c2ecf20Sopenharmony_ci smart->spares = smart_def.spares; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci if (inj->flags & ND_INTEL_SMART_INJECT_FATAL) { 8018c2ecf20Sopenharmony_ci if (inj->fatal_enable) 8028c2ecf20Sopenharmony_ci smart->health = ND_INTEL_SMART_FATAL_HEALTH; 8038c2ecf20Sopenharmony_ci else 8048c2ecf20Sopenharmony_ci smart->health = ND_INTEL_SMART_NON_CRITICAL_HEALTH; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci if (inj->flags & ND_INTEL_SMART_INJECT_SHUTDOWN) { 8078c2ecf20Sopenharmony_ci if (inj->unsafe_shutdown_enable) { 8088c2ecf20Sopenharmony_ci smart->shutdown_state = 1; 8098c2ecf20Sopenharmony_ci smart->shutdown_count++; 8108c2ecf20Sopenharmony_ci } else 8118c2ecf20Sopenharmony_ci smart->shutdown_state = 0; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci inj->status = 0; 8148c2ecf20Sopenharmony_ci smart_notify(bus_dev, dimm_dev, smart, thresh); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic void uc_error_notify(struct work_struct *work) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct nfit_test *t = container_of(work, typeof(*t), work); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci __acpi_nfit_notify(&t->pdev.dev, t, NFIT_NOTIFY_UC_MEMORY_ERROR); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_error_inject(struct nfit_test *t, 8278c2ecf20Sopenharmony_ci struct nd_cmd_ars_err_inj *err_inj, unsigned int buf_len) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci int rc; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (buf_len != sizeof(*err_inj)) { 8328c2ecf20Sopenharmony_ci rc = -EINVAL; 8338c2ecf20Sopenharmony_ci goto err; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (err_inj->err_inj_spa_range_length <= 0) { 8378c2ecf20Sopenharmony_ci rc = -EINVAL; 8388c2ecf20Sopenharmony_ci goto err; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci rc = badrange_add(&t->badrange, err_inj->err_inj_spa_range_base, 8428c2ecf20Sopenharmony_ci err_inj->err_inj_spa_range_length); 8438c2ecf20Sopenharmony_ci if (rc < 0) 8448c2ecf20Sopenharmony_ci goto err; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (err_inj->err_inj_options & (1 << ND_ARS_ERR_INJ_OPT_NOTIFY)) 8478c2ecf20Sopenharmony_ci queue_work(nfit_wq, &t->work); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci err_inj->status = 0; 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cierr: 8538c2ecf20Sopenharmony_ci err_inj->status = NFIT_ARS_INJECT_INVALID; 8548c2ecf20Sopenharmony_ci return rc; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_inject_clear(struct nfit_test *t, 8588c2ecf20Sopenharmony_ci struct nd_cmd_ars_err_inj_clr *err_clr, unsigned int buf_len) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci int rc; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (buf_len != sizeof(*err_clr)) { 8638c2ecf20Sopenharmony_ci rc = -EINVAL; 8648c2ecf20Sopenharmony_ci goto err; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (err_clr->err_inj_clr_spa_range_length <= 0) { 8688c2ecf20Sopenharmony_ci rc = -EINVAL; 8698c2ecf20Sopenharmony_ci goto err; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci badrange_forget(&t->badrange, err_clr->err_inj_clr_spa_range_base, 8738c2ecf20Sopenharmony_ci err_clr->err_inj_clr_spa_range_length); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci err_clr->status = 0; 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cierr: 8798c2ecf20Sopenharmony_ci err_clr->status = NFIT_ARS_INJECT_INVALID; 8808c2ecf20Sopenharmony_ci return rc; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int nfit_test_cmd_ars_inject_status(struct nfit_test *t, 8848c2ecf20Sopenharmony_ci struct nd_cmd_ars_err_inj_stat *err_stat, 8858c2ecf20Sopenharmony_ci unsigned int buf_len) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct badrange_entry *be; 8888c2ecf20Sopenharmony_ci int max = SZ_4K / sizeof(struct nd_error_stat_query_record); 8898c2ecf20Sopenharmony_ci int i = 0; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci err_stat->status = 0; 8928c2ecf20Sopenharmony_ci spin_lock(&t->badrange.lock); 8938c2ecf20Sopenharmony_ci list_for_each_entry(be, &t->badrange.list, list) { 8948c2ecf20Sopenharmony_ci err_stat->record[i].err_inj_stat_spa_range_base = be->start; 8958c2ecf20Sopenharmony_ci err_stat->record[i].err_inj_stat_spa_range_length = be->length; 8968c2ecf20Sopenharmony_ci i++; 8978c2ecf20Sopenharmony_ci if (i > max) 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci spin_unlock(&t->badrange.lock); 9018c2ecf20Sopenharmony_ci err_stat->inj_err_rec_count = i; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_set_lss_status(struct nfit_test *t, 9078c2ecf20Sopenharmony_ci struct nd_intel_lss *nd_cmd, unsigned int buf_len) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (buf_len < sizeof(*nd_cmd)) 9128c2ecf20Sopenharmony_ci return -EINVAL; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci switch (nd_cmd->enable) { 9158c2ecf20Sopenharmony_ci case 0: 9168c2ecf20Sopenharmony_ci nd_cmd->status = 0; 9178c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Latch System Shutdown Status disabled\n", 9188c2ecf20Sopenharmony_ci __func__); 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci case 1: 9218c2ecf20Sopenharmony_ci nd_cmd->status = 0; 9228c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Latch System Shutdown Status enabled\n", 9238c2ecf20Sopenharmony_ci __func__); 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci default: 9268c2ecf20Sopenharmony_ci dev_warn(dev, "Unknown enable value: %#x\n", nd_cmd->enable); 9278c2ecf20Sopenharmony_ci nd_cmd->status = 0x3; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return 0; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int override_return_code(int dimm, unsigned int func, int rc) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci if ((1 << func) & dimm_fail_cmd_flags[dimm]) { 9388c2ecf20Sopenharmony_ci if (dimm_fail_cmd_code[dimm]) 9398c2ecf20Sopenharmony_ci return dimm_fail_cmd_code[dimm]; 9408c2ecf20Sopenharmony_ci return -EIO; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci return rc; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_security_status(struct nfit_test *t, 9468c2ecf20Sopenharmony_ci struct nd_intel_get_security_state *nd_cmd, 9478c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 9508c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci nd_cmd->status = 0; 9538c2ecf20Sopenharmony_ci nd_cmd->state = sec->state; 9548c2ecf20Sopenharmony_ci nd_cmd->extended_state = sec->ext_state; 9558c2ecf20Sopenharmony_ci dev_dbg(dev, "security state (%#x) returned\n", nd_cmd->state); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_unlock_unit(struct nfit_test *t, 9618c2ecf20Sopenharmony_ci struct nd_intel_unlock_unit *nd_cmd, 9628c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 9658c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!(sec->state & ND_INTEL_SEC_STATE_LOCKED) || 9688c2ecf20Sopenharmony_ci (sec->state & ND_INTEL_SEC_STATE_FROZEN)) { 9698c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 9708c2ecf20Sopenharmony_ci dev_dbg(dev, "unlock unit: invalid state: %#x\n", 9718c2ecf20Sopenharmony_ci sec->state); 9728c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->passphrase, sec->passphrase, 9738c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 9748c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 9758c2ecf20Sopenharmony_ci dev_dbg(dev, "unlock unit: invalid passphrase\n"); 9768c2ecf20Sopenharmony_ci } else { 9778c2ecf20Sopenharmony_ci nd_cmd->status = 0; 9788c2ecf20Sopenharmony_ci sec->state = ND_INTEL_SEC_STATE_ENABLED; 9798c2ecf20Sopenharmony_ci dev_dbg(dev, "Unit unlocked\n"); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci dev_dbg(dev, "unlocking status returned: %#x\n", nd_cmd->status); 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_set_pass(struct nfit_test *t, 9878c2ecf20Sopenharmony_ci struct nd_intel_set_passphrase *nd_cmd, 9888c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 9918c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (sec->state & ND_INTEL_SEC_STATE_FROZEN) { 9948c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 9958c2ecf20Sopenharmony_ci dev_dbg(dev, "set passphrase: wrong security state\n"); 9968c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->old_pass, sec->passphrase, 9978c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 9988c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 9998c2ecf20Sopenharmony_ci dev_dbg(dev, "set passphrase: wrong passphrase\n"); 10008c2ecf20Sopenharmony_ci } else { 10018c2ecf20Sopenharmony_ci memcpy(sec->passphrase, nd_cmd->new_pass, 10028c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE); 10038c2ecf20Sopenharmony_ci sec->state |= ND_INTEL_SEC_STATE_ENABLED; 10048c2ecf20Sopenharmony_ci nd_cmd->status = 0; 10058c2ecf20Sopenharmony_ci dev_dbg(dev, "passphrase updated\n"); 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_freeze_lock(struct nfit_test *t, 10128c2ecf20Sopenharmony_ci struct nd_intel_freeze_lock *nd_cmd, 10138c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 10168c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED)) { 10198c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 10208c2ecf20Sopenharmony_ci dev_dbg(dev, "freeze lock: wrong security state\n"); 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci sec->state |= ND_INTEL_SEC_STATE_FROZEN; 10238c2ecf20Sopenharmony_ci nd_cmd->status = 0; 10248c2ecf20Sopenharmony_ci dev_dbg(dev, "security frozen\n"); 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_disable_pass(struct nfit_test *t, 10318c2ecf20Sopenharmony_ci struct nd_intel_disable_passphrase *nd_cmd, 10328c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 10358c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) || 10388c2ecf20Sopenharmony_ci (sec->state & ND_INTEL_SEC_STATE_FROZEN)) { 10398c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 10408c2ecf20Sopenharmony_ci dev_dbg(dev, "disable passphrase: wrong security state\n"); 10418c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->passphrase, sec->passphrase, 10428c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 10438c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 10448c2ecf20Sopenharmony_ci dev_dbg(dev, "disable passphrase: wrong passphrase\n"); 10458c2ecf20Sopenharmony_ci } else { 10468c2ecf20Sopenharmony_ci memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); 10478c2ecf20Sopenharmony_ci sec->state = 0; 10488c2ecf20Sopenharmony_ci dev_dbg(dev, "disable passphrase: done\n"); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci return 0; 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_secure_erase(struct nfit_test *t, 10558c2ecf20Sopenharmony_ci struct nd_intel_secure_erase *nd_cmd, 10568c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 10598c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (sec->state & ND_INTEL_SEC_STATE_FROZEN) { 10628c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 10638c2ecf20Sopenharmony_ci dev_dbg(dev, "secure erase: wrong security state\n"); 10648c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->passphrase, sec->passphrase, 10658c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 10668c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 10678c2ecf20Sopenharmony_ci dev_dbg(dev, "secure erase: wrong passphrase\n"); 10688c2ecf20Sopenharmony_ci } else { 10698c2ecf20Sopenharmony_ci if (!(sec->state & ND_INTEL_SEC_STATE_ENABLED) 10708c2ecf20Sopenharmony_ci && (memcmp(nd_cmd->passphrase, zero_key, 10718c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0)) { 10728c2ecf20Sopenharmony_ci dev_dbg(dev, "invalid zero key\n"); 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); 10768c2ecf20Sopenharmony_ci memset(sec->master_passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); 10778c2ecf20Sopenharmony_ci sec->state = 0; 10788c2ecf20Sopenharmony_ci sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED; 10798c2ecf20Sopenharmony_ci dev_dbg(dev, "secure erase: done\n"); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_overwrite(struct nfit_test *t, 10868c2ecf20Sopenharmony_ci struct nd_intel_overwrite *nd_cmd, 10878c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 10908c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if ((sec->state & ND_INTEL_SEC_STATE_ENABLED) && 10938c2ecf20Sopenharmony_ci memcmp(nd_cmd->passphrase, sec->passphrase, 10948c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 10958c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 10968c2ecf20Sopenharmony_ci dev_dbg(dev, "overwrite: wrong passphrase\n"); 10978c2ecf20Sopenharmony_ci return 0; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci sec->old_state = sec->state; 11018c2ecf20Sopenharmony_ci sec->state = ND_INTEL_SEC_STATE_OVERWRITE; 11028c2ecf20Sopenharmony_ci dev_dbg(dev, "overwrite progressing.\n"); 11038c2ecf20Sopenharmony_ci sec->overwrite_end_time = get_jiffies_64() + 5 * HZ; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return 0; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_query_overwrite(struct nfit_test *t, 11098c2ecf20Sopenharmony_ci struct nd_intel_query_overwrite *nd_cmd, 11108c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 11138c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!(sec->state & ND_INTEL_SEC_STATE_OVERWRITE)) { 11168c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_OQUERY_SEQUENCE_ERR; 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (time_is_before_jiffies64(sec->overwrite_end_time)) { 11218c2ecf20Sopenharmony_ci sec->overwrite_end_time = 0; 11228c2ecf20Sopenharmony_ci sec->state = sec->old_state; 11238c2ecf20Sopenharmony_ci sec->old_state = 0; 11248c2ecf20Sopenharmony_ci sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED; 11258c2ecf20Sopenharmony_ci dev_dbg(dev, "overwrite is complete\n"); 11268c2ecf20Sopenharmony_ci } else 11278c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_OQUERY_INPROGRESS; 11288c2ecf20Sopenharmony_ci return 0; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_master_set_pass(struct nfit_test *t, 11328c2ecf20Sopenharmony_ci struct nd_intel_set_master_passphrase *nd_cmd, 11338c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 11368c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (!(sec->ext_state & ND_INTEL_SEC_ESTATE_ENABLED)) { 11398c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_NOT_SUPPORTED; 11408c2ecf20Sopenharmony_ci dev_dbg(dev, "master set passphrase: in wrong state\n"); 11418c2ecf20Sopenharmony_ci } else if (sec->ext_state & ND_INTEL_SEC_ESTATE_PLIMIT) { 11428c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 11438c2ecf20Sopenharmony_ci dev_dbg(dev, "master set passphrase: in wrong security state\n"); 11448c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->old_pass, sec->master_passphrase, 11458c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 11468c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 11478c2ecf20Sopenharmony_ci dev_dbg(dev, "master set passphrase: wrong passphrase\n"); 11488c2ecf20Sopenharmony_ci } else { 11498c2ecf20Sopenharmony_ci memcpy(sec->master_passphrase, nd_cmd->new_pass, 11508c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE); 11518c2ecf20Sopenharmony_ci sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED; 11528c2ecf20Sopenharmony_ci dev_dbg(dev, "master passphrase: updated\n"); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return 0; 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_master_secure_erase(struct nfit_test *t, 11598c2ecf20Sopenharmony_ci struct nd_intel_master_secure_erase *nd_cmd, 11608c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 11638c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (!(sec->ext_state & ND_INTEL_SEC_ESTATE_ENABLED)) { 11668c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_NOT_SUPPORTED; 11678c2ecf20Sopenharmony_ci dev_dbg(dev, "master secure erase: in wrong state\n"); 11688c2ecf20Sopenharmony_ci } else if (sec->ext_state & ND_INTEL_SEC_ESTATE_PLIMIT) { 11698c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_STATE; 11708c2ecf20Sopenharmony_ci dev_dbg(dev, "master secure erase: in wrong security state\n"); 11718c2ecf20Sopenharmony_ci } else if (memcmp(nd_cmd->passphrase, sec->master_passphrase, 11728c2ecf20Sopenharmony_ci ND_INTEL_PASSPHRASE_SIZE) != 0) { 11738c2ecf20Sopenharmony_ci nd_cmd->status = ND_INTEL_STATUS_INVALID_PASS; 11748c2ecf20Sopenharmony_ci dev_dbg(dev, "master secure erase: wrong passphrase\n"); 11758c2ecf20Sopenharmony_ci } else { 11768c2ecf20Sopenharmony_ci /* we do not erase master state passphrase ever */ 11778c2ecf20Sopenharmony_ci sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED; 11788c2ecf20Sopenharmony_ci memset(sec->passphrase, 0, ND_INTEL_PASSPHRASE_SIZE); 11798c2ecf20Sopenharmony_ci sec->state = 0; 11808c2ecf20Sopenharmony_ci dev_dbg(dev, "master secure erase: done\n"); 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci return 0; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic unsigned long last_activate; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic int nvdimm_bus_intel_fw_activate_businfo(struct nfit_test *t, 11898c2ecf20Sopenharmony_ci struct nd_intel_bus_fw_activate_businfo *nd_cmd, 11908c2ecf20Sopenharmony_ci unsigned int buf_len) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci int i, armed = 0; 11938c2ecf20Sopenharmony_ci int state; 11948c2ecf20Sopenharmony_ci u64 tmo; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DCR; i++) { 11978c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[i]; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci if (fw->armed) 12008c2ecf20Sopenharmony_ci armed++; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* 12048c2ecf20Sopenharmony_ci * Emulate 3 second activation max, and 1 second incremental 12058c2ecf20Sopenharmony_ci * quiesce time per dimm requiring multiple activates to get all 12068c2ecf20Sopenharmony_ci * DIMMs updated. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci if (armed) 12098c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_ARMED; 12108c2ecf20Sopenharmony_ci else if (!last_activate || time_after(jiffies, last_activate + 3 * HZ)) 12118c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_IDLE; 12128c2ecf20Sopenharmony_ci else 12138c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_BUSY; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci tmo = armed * USEC_PER_SEC; 12168c2ecf20Sopenharmony_ci *nd_cmd = (struct nd_intel_bus_fw_activate_businfo) { 12178c2ecf20Sopenharmony_ci .capability = ND_INTEL_BUS_FWA_CAP_FWQUIESCE 12188c2ecf20Sopenharmony_ci | ND_INTEL_BUS_FWA_CAP_OSQUIESCE 12198c2ecf20Sopenharmony_ci | ND_INTEL_BUS_FWA_CAP_RESET, 12208c2ecf20Sopenharmony_ci .state = state, 12218c2ecf20Sopenharmony_ci .activate_tmo = tmo, 12228c2ecf20Sopenharmony_ci .cpu_quiesce_tmo = tmo, 12238c2ecf20Sopenharmony_ci .io_quiesce_tmo = tmo, 12248c2ecf20Sopenharmony_ci .max_quiesce_tmo = 3 * USEC_PER_SEC, 12258c2ecf20Sopenharmony_ci }; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return 0; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic int nvdimm_bus_intel_fw_activate(struct nfit_test *t, 12318c2ecf20Sopenharmony_ci struct nd_intel_bus_fw_activate *nd_cmd, 12328c2ecf20Sopenharmony_ci unsigned int buf_len) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci struct nd_intel_bus_fw_activate_businfo info; 12358c2ecf20Sopenharmony_ci u32 status = 0; 12368c2ecf20Sopenharmony_ci int i; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci nvdimm_bus_intel_fw_activate_businfo(t, &info, sizeof(info)); 12398c2ecf20Sopenharmony_ci if (info.state == ND_INTEL_FWA_BUSY) 12408c2ecf20Sopenharmony_ci status = ND_INTEL_BUS_FWA_STATUS_BUSY; 12418c2ecf20Sopenharmony_ci else if (info.activate_tmo > info.max_quiesce_tmo) 12428c2ecf20Sopenharmony_ci status = ND_INTEL_BUS_FWA_STATUS_TMO; 12438c2ecf20Sopenharmony_ci else if (info.state == ND_INTEL_FWA_IDLE) 12448c2ecf20Sopenharmony_ci status = ND_INTEL_BUS_FWA_STATUS_NOARM; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci dev_dbg(&t->pdev.dev, "status: %d\n", status); 12478c2ecf20Sopenharmony_ci nd_cmd->status = status; 12488c2ecf20Sopenharmony_ci if (status && status != ND_INTEL_BUS_FWA_STATUS_TMO) 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci last_activate = jiffies; 12528c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DCR; i++) { 12538c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[i]; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (!fw->armed) 12568c2ecf20Sopenharmony_ci continue; 12578c2ecf20Sopenharmony_ci if (fw->state != FW_STATE_UPDATED) 12588c2ecf20Sopenharmony_ci fw->missed_activate = true; 12598c2ecf20Sopenharmony_ci else 12608c2ecf20Sopenharmony_ci fw->state = FW_STATE_NEW; 12618c2ecf20Sopenharmony_ci fw->armed = false; 12628c2ecf20Sopenharmony_ci fw->last_activate = last_activate; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_fw_activate_dimminfo(struct nfit_test *t, 12698c2ecf20Sopenharmony_ci struct nd_intel_fw_activate_dimminfo *nd_cmd, 12708c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci struct nd_intel_bus_fw_activate_businfo info; 12738c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[dimm]; 12748c2ecf20Sopenharmony_ci u32 result, state; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci nvdimm_bus_intel_fw_activate_businfo(t, &info, sizeof(info)); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (info.state == ND_INTEL_FWA_BUSY) 12798c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_BUSY; 12808c2ecf20Sopenharmony_ci else if (info.state == ND_INTEL_FWA_IDLE) 12818c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_IDLE; 12828c2ecf20Sopenharmony_ci else if (fw->armed) 12838c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_ARMED; 12848c2ecf20Sopenharmony_ci else 12858c2ecf20Sopenharmony_ci state = ND_INTEL_FWA_IDLE; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci result = ND_INTEL_DIMM_FWA_NONE; 12888c2ecf20Sopenharmony_ci if (last_activate && fw->last_activate == last_activate && 12898c2ecf20Sopenharmony_ci state == ND_INTEL_FWA_IDLE) { 12908c2ecf20Sopenharmony_ci if (fw->missed_activate) 12918c2ecf20Sopenharmony_ci result = ND_INTEL_DIMM_FWA_NOTSTAGED; 12928c2ecf20Sopenharmony_ci else 12938c2ecf20Sopenharmony_ci result = ND_INTEL_DIMM_FWA_SUCCESS; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci *nd_cmd = (struct nd_intel_fw_activate_dimminfo) { 12978c2ecf20Sopenharmony_ci .result = result, 12988c2ecf20Sopenharmony_ci .state = state, 12998c2ecf20Sopenharmony_ci }; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int nd_intel_test_cmd_fw_activate_arm(struct nfit_test *t, 13058c2ecf20Sopenharmony_ci struct nd_intel_fw_activate_arm *nd_cmd, 13068c2ecf20Sopenharmony_ci unsigned int buf_len, int dimm) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct nfit_test_fw *fw = &t->fw[dimm]; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci fw->armed = nd_cmd->activate_arm == ND_INTEL_DIMM_FWA_ARM; 13118c2ecf20Sopenharmony_ci nd_cmd->status = 0; 13128c2ecf20Sopenharmony_ci return 0; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int get_dimm(struct nfit_mem *nfit_mem, unsigned int func) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci int i; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* lookup per-dimm data */ 13208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(handle); i++) 13218c2ecf20Sopenharmony_ci if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i]) 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(handle)) 13248c2ecf20Sopenharmony_ci return -ENXIO; 13258c2ecf20Sopenharmony_ci return i; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic void nfit_ctl_dbg(struct acpi_nfit_desc *acpi_desc, 13298c2ecf20Sopenharmony_ci struct nvdimm *nvdimm, unsigned int cmd, void *buf, 13308c2ecf20Sopenharmony_ci unsigned int len) 13318c2ecf20Sopenharmony_ci{ 13328c2ecf20Sopenharmony_ci struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); 13338c2ecf20Sopenharmony_ci unsigned int func = cmd; 13348c2ecf20Sopenharmony_ci unsigned int family = 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (cmd == ND_CMD_CALL) { 13378c2ecf20Sopenharmony_ci struct nd_cmd_pkg *pkg = buf; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci len = pkg->nd_size_in; 13408c2ecf20Sopenharmony_ci family = pkg->nd_family; 13418c2ecf20Sopenharmony_ci buf = pkg->nd_payload; 13428c2ecf20Sopenharmony_ci func = pkg->nd_command; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci dev_dbg(&t->pdev.dev, "%s family: %d cmd: %d: func: %d input length: %d\n", 13458c2ecf20Sopenharmony_ci nvdimm ? nvdimm_name(nvdimm) : "bus", family, cmd, func, 13468c2ecf20Sopenharmony_ci len); 13478c2ecf20Sopenharmony_ci print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 16, 4, 13488c2ecf20Sopenharmony_ci buf, min(len, 256u), true); 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, 13528c2ecf20Sopenharmony_ci struct nvdimm *nvdimm, unsigned int cmd, void *buf, 13538c2ecf20Sopenharmony_ci unsigned int buf_len, int *cmd_rc) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); 13568c2ecf20Sopenharmony_ci struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); 13578c2ecf20Sopenharmony_ci unsigned int func = cmd; 13588c2ecf20Sopenharmony_ci int i, rc = 0, __cmd_rc; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (!cmd_rc) 13618c2ecf20Sopenharmony_ci cmd_rc = &__cmd_rc; 13628c2ecf20Sopenharmony_ci *cmd_rc = 0; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci nfit_ctl_dbg(acpi_desc, nvdimm, cmd, buf, buf_len); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (nvdimm) { 13678c2ecf20Sopenharmony_ci struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 13688c2ecf20Sopenharmony_ci unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (!nfit_mem) 13718c2ecf20Sopenharmony_ci return -ENOTTY; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (cmd == ND_CMD_CALL) { 13748c2ecf20Sopenharmony_ci struct nd_cmd_pkg *call_pkg = buf; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; 13778c2ecf20Sopenharmony_ci buf = (void *) call_pkg->nd_payload; 13788c2ecf20Sopenharmony_ci func = call_pkg->nd_command; 13798c2ecf20Sopenharmony_ci if (call_pkg->nd_family != nfit_mem->family) 13808c2ecf20Sopenharmony_ci return -ENOTTY; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci i = get_dimm(nfit_mem, func); 13838c2ecf20Sopenharmony_ci if (i < 0) 13848c2ecf20Sopenharmony_ci return i; 13858c2ecf20Sopenharmony_ci if (i >= NUM_DCR) { 13868c2ecf20Sopenharmony_ci dev_WARN_ONCE(&t->pdev.dev, 1, 13878c2ecf20Sopenharmony_ci "ND_CMD_CALL only valid for nfit_test0\n"); 13888c2ecf20Sopenharmony_ci return -EINVAL; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci switch (func) { 13928c2ecf20Sopenharmony_ci case NVDIMM_INTEL_GET_SECURITY_STATE: 13938c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_security_status(t, 13948c2ecf20Sopenharmony_ci buf, buf_len, i); 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci case NVDIMM_INTEL_UNLOCK_UNIT: 13978c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_unlock_unit(t, 13988c2ecf20Sopenharmony_ci buf, buf_len, i); 13998c2ecf20Sopenharmony_ci break; 14008c2ecf20Sopenharmony_ci case NVDIMM_INTEL_SET_PASSPHRASE: 14018c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_set_pass(t, 14028c2ecf20Sopenharmony_ci buf, buf_len, i); 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci case NVDIMM_INTEL_DISABLE_PASSPHRASE: 14058c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_disable_pass(t, 14068c2ecf20Sopenharmony_ci buf, buf_len, i); 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci case NVDIMM_INTEL_FREEZE_LOCK: 14098c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_freeze_lock(t, 14108c2ecf20Sopenharmony_ci buf, buf_len, i); 14118c2ecf20Sopenharmony_ci break; 14128c2ecf20Sopenharmony_ci case NVDIMM_INTEL_SECURE_ERASE: 14138c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_secure_erase(t, 14148c2ecf20Sopenharmony_ci buf, buf_len, i); 14158c2ecf20Sopenharmony_ci break; 14168c2ecf20Sopenharmony_ci case NVDIMM_INTEL_OVERWRITE: 14178c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_overwrite(t, 14188c2ecf20Sopenharmony_ci buf, buf_len, i); 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci case NVDIMM_INTEL_QUERY_OVERWRITE: 14218c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_query_overwrite(t, 14228c2ecf20Sopenharmony_ci buf, buf_len, i); 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci case NVDIMM_INTEL_SET_MASTER_PASSPHRASE: 14258c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_master_set_pass(t, 14268c2ecf20Sopenharmony_ci buf, buf_len, i); 14278c2ecf20Sopenharmony_ci break; 14288c2ecf20Sopenharmony_ci case NVDIMM_INTEL_MASTER_SECURE_ERASE: 14298c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_master_secure_erase(t, 14308c2ecf20Sopenharmony_ci buf, buf_len, i); 14318c2ecf20Sopenharmony_ci break; 14328c2ecf20Sopenharmony_ci case NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO: 14338c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_fw_activate_dimminfo( 14348c2ecf20Sopenharmony_ci t, buf, buf_len, i); 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci case NVDIMM_INTEL_FW_ACTIVATE_ARM: 14378c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_fw_activate_arm( 14388c2ecf20Sopenharmony_ci t, buf, buf_len, i); 14398c2ecf20Sopenharmony_ci break; 14408c2ecf20Sopenharmony_ci case ND_INTEL_ENABLE_LSS_STATUS: 14418c2ecf20Sopenharmony_ci rc = nd_intel_test_cmd_set_lss_status(t, 14428c2ecf20Sopenharmony_ci buf, buf_len); 14438c2ecf20Sopenharmony_ci break; 14448c2ecf20Sopenharmony_ci case ND_INTEL_FW_GET_INFO: 14458c2ecf20Sopenharmony_ci rc = nd_intel_test_get_fw_info(t, buf, 14468c2ecf20Sopenharmony_ci buf_len, i); 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci case ND_INTEL_FW_START_UPDATE: 14498c2ecf20Sopenharmony_ci rc = nd_intel_test_start_update(t, buf, 14508c2ecf20Sopenharmony_ci buf_len, i); 14518c2ecf20Sopenharmony_ci break; 14528c2ecf20Sopenharmony_ci case ND_INTEL_FW_SEND_DATA: 14538c2ecf20Sopenharmony_ci rc = nd_intel_test_send_data(t, buf, 14548c2ecf20Sopenharmony_ci buf_len, i); 14558c2ecf20Sopenharmony_ci break; 14568c2ecf20Sopenharmony_ci case ND_INTEL_FW_FINISH_UPDATE: 14578c2ecf20Sopenharmony_ci rc = nd_intel_test_finish_fw(t, buf, 14588c2ecf20Sopenharmony_ci buf_len, i); 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case ND_INTEL_FW_FINISH_QUERY: 14618c2ecf20Sopenharmony_ci rc = nd_intel_test_finish_query(t, buf, 14628c2ecf20Sopenharmony_ci buf_len, i); 14638c2ecf20Sopenharmony_ci break; 14648c2ecf20Sopenharmony_ci case ND_INTEL_SMART: 14658c2ecf20Sopenharmony_ci rc = nfit_test_cmd_smart(buf, buf_len, 14668c2ecf20Sopenharmony_ci &t->smart[i]); 14678c2ecf20Sopenharmony_ci break; 14688c2ecf20Sopenharmony_ci case ND_INTEL_SMART_THRESHOLD: 14698c2ecf20Sopenharmony_ci rc = nfit_test_cmd_smart_threshold(buf, 14708c2ecf20Sopenharmony_ci buf_len, 14718c2ecf20Sopenharmony_ci &t->smart_threshold[i]); 14728c2ecf20Sopenharmony_ci break; 14738c2ecf20Sopenharmony_ci case ND_INTEL_SMART_SET_THRESHOLD: 14748c2ecf20Sopenharmony_ci rc = nfit_test_cmd_smart_set_threshold(buf, 14758c2ecf20Sopenharmony_ci buf_len, 14768c2ecf20Sopenharmony_ci &t->smart_threshold[i], 14778c2ecf20Sopenharmony_ci &t->smart[i], 14788c2ecf20Sopenharmony_ci &t->pdev.dev, t->dimm_dev[i]); 14798c2ecf20Sopenharmony_ci break; 14808c2ecf20Sopenharmony_ci case ND_INTEL_SMART_INJECT: 14818c2ecf20Sopenharmony_ci rc = nfit_test_cmd_smart_inject(buf, 14828c2ecf20Sopenharmony_ci buf_len, 14838c2ecf20Sopenharmony_ci &t->smart_threshold[i], 14848c2ecf20Sopenharmony_ci &t->smart[i], 14858c2ecf20Sopenharmony_ci &t->pdev.dev, t->dimm_dev[i]); 14868c2ecf20Sopenharmony_ci break; 14878c2ecf20Sopenharmony_ci default: 14888c2ecf20Sopenharmony_ci return -ENOTTY; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci return override_return_code(i, func, rc); 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (!test_bit(cmd, &cmd_mask) 14948c2ecf20Sopenharmony_ci || !test_bit(func, &nfit_mem->dsm_mask)) 14958c2ecf20Sopenharmony_ci return -ENOTTY; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci i = get_dimm(nfit_mem, func); 14988c2ecf20Sopenharmony_ci if (i < 0) 14998c2ecf20Sopenharmony_ci return i; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci switch (func) { 15028c2ecf20Sopenharmony_ci case ND_CMD_GET_CONFIG_SIZE: 15038c2ecf20Sopenharmony_ci rc = nfit_test_cmd_get_config_size(buf, buf_len); 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci case ND_CMD_GET_CONFIG_DATA: 15068c2ecf20Sopenharmony_ci rc = nfit_test_cmd_get_config_data(buf, buf_len, 15078c2ecf20Sopenharmony_ci t->label[i - t->dcr_idx]); 15088c2ecf20Sopenharmony_ci break; 15098c2ecf20Sopenharmony_ci case ND_CMD_SET_CONFIG_DATA: 15108c2ecf20Sopenharmony_ci rc = nfit_test_cmd_set_config_data(buf, buf_len, 15118c2ecf20Sopenharmony_ci t->label[i - t->dcr_idx]); 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci default: 15148c2ecf20Sopenharmony_ci return -ENOTTY; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci return override_return_code(i, func, rc); 15178c2ecf20Sopenharmony_ci } else { 15188c2ecf20Sopenharmony_ci struct ars_state *ars_state = &t->ars_state; 15198c2ecf20Sopenharmony_ci struct nd_cmd_pkg *call_pkg = buf; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (!nd_desc) 15228c2ecf20Sopenharmony_ci return -ENOTTY; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (cmd == ND_CMD_CALL && call_pkg->nd_family 15258c2ecf20Sopenharmony_ci == NVDIMM_BUS_FAMILY_NFIT) { 15268c2ecf20Sopenharmony_ci func = call_pkg->nd_command; 15278c2ecf20Sopenharmony_ci buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; 15288c2ecf20Sopenharmony_ci buf = (void *) call_pkg->nd_payload; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci switch (func) { 15318c2ecf20Sopenharmony_ci case NFIT_CMD_TRANSLATE_SPA: 15328c2ecf20Sopenharmony_ci rc = nfit_test_cmd_translate_spa( 15338c2ecf20Sopenharmony_ci acpi_desc->nvdimm_bus, buf, buf_len); 15348c2ecf20Sopenharmony_ci return rc; 15358c2ecf20Sopenharmony_ci case NFIT_CMD_ARS_INJECT_SET: 15368c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_error_inject(t, buf, 15378c2ecf20Sopenharmony_ci buf_len); 15388c2ecf20Sopenharmony_ci return rc; 15398c2ecf20Sopenharmony_ci case NFIT_CMD_ARS_INJECT_CLEAR: 15408c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_inject_clear(t, buf, 15418c2ecf20Sopenharmony_ci buf_len); 15428c2ecf20Sopenharmony_ci return rc; 15438c2ecf20Sopenharmony_ci case NFIT_CMD_ARS_INJECT_GET: 15448c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_inject_status(t, buf, 15458c2ecf20Sopenharmony_ci buf_len); 15468c2ecf20Sopenharmony_ci return rc; 15478c2ecf20Sopenharmony_ci default: 15488c2ecf20Sopenharmony_ci return -ENOTTY; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci } else if (cmd == ND_CMD_CALL && call_pkg->nd_family 15518c2ecf20Sopenharmony_ci == NVDIMM_BUS_FAMILY_INTEL) { 15528c2ecf20Sopenharmony_ci func = call_pkg->nd_command; 15538c2ecf20Sopenharmony_ci buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; 15548c2ecf20Sopenharmony_ci buf = (void *) call_pkg->nd_payload; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci switch (func) { 15578c2ecf20Sopenharmony_ci case NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO: 15588c2ecf20Sopenharmony_ci rc = nvdimm_bus_intel_fw_activate_businfo(t, 15598c2ecf20Sopenharmony_ci buf, buf_len); 15608c2ecf20Sopenharmony_ci return rc; 15618c2ecf20Sopenharmony_ci case NVDIMM_BUS_INTEL_FW_ACTIVATE: 15628c2ecf20Sopenharmony_ci rc = nvdimm_bus_intel_fw_activate(t, buf, 15638c2ecf20Sopenharmony_ci buf_len); 15648c2ecf20Sopenharmony_ci return rc; 15658c2ecf20Sopenharmony_ci default: 15668c2ecf20Sopenharmony_ci return -ENOTTY; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci } else if (cmd == ND_CMD_CALL) 15698c2ecf20Sopenharmony_ci return -ENOTTY; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) 15728c2ecf20Sopenharmony_ci return -ENOTTY; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci switch (func) { 15758c2ecf20Sopenharmony_ci case ND_CMD_ARS_CAP: 15768c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_cap(buf, buf_len); 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci case ND_CMD_ARS_START: 15798c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_start(t, ars_state, buf, 15808c2ecf20Sopenharmony_ci buf_len, cmd_rc); 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci case ND_CMD_ARS_STATUS: 15838c2ecf20Sopenharmony_ci rc = nfit_test_cmd_ars_status(ars_state, buf, buf_len, 15848c2ecf20Sopenharmony_ci cmd_rc); 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci case ND_CMD_CLEAR_ERROR: 15878c2ecf20Sopenharmony_ci rc = nfit_test_cmd_clear_error(t, buf, buf_len, cmd_rc); 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci default: 15908c2ecf20Sopenharmony_ci return -ENOTTY; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci return rc; 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(nfit_test_lock); 15988c2ecf20Sopenharmony_cistatic struct nfit_test *instances[NUM_NFITS]; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void release_nfit_res(void *data) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct nfit_test_resource *nfit_res = data; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci spin_lock(&nfit_test_lock); 16058c2ecf20Sopenharmony_ci list_del(&nfit_res->list); 16068c2ecf20Sopenharmony_ci spin_unlock(&nfit_test_lock); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (resource_size(&nfit_res->res) >= DIMM_SIZE) 16098c2ecf20Sopenharmony_ci gen_pool_free(nfit_pool, nfit_res->res.start, 16108c2ecf20Sopenharmony_ci resource_size(&nfit_res->res)); 16118c2ecf20Sopenharmony_ci vfree(nfit_res->buf); 16128c2ecf20Sopenharmony_ci kfree(nfit_res); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, 16168c2ecf20Sopenharmony_ci void *buf) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct device *dev = &t->pdev.dev; 16198c2ecf20Sopenharmony_ci struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res), 16208c2ecf20Sopenharmony_ci GFP_KERNEL); 16218c2ecf20Sopenharmony_ci int rc; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (!buf || !nfit_res || !*dma) 16248c2ecf20Sopenharmony_ci goto err; 16258c2ecf20Sopenharmony_ci rc = devm_add_action(dev, release_nfit_res, nfit_res); 16268c2ecf20Sopenharmony_ci if (rc) 16278c2ecf20Sopenharmony_ci goto err; 16288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfit_res->list); 16298c2ecf20Sopenharmony_ci memset(buf, 0, size); 16308c2ecf20Sopenharmony_ci nfit_res->dev = dev; 16318c2ecf20Sopenharmony_ci nfit_res->buf = buf; 16328c2ecf20Sopenharmony_ci nfit_res->res.start = *dma; 16338c2ecf20Sopenharmony_ci nfit_res->res.end = *dma + size - 1; 16348c2ecf20Sopenharmony_ci nfit_res->res.name = "NFIT"; 16358c2ecf20Sopenharmony_ci spin_lock_init(&nfit_res->lock); 16368c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfit_res->requests); 16378c2ecf20Sopenharmony_ci spin_lock(&nfit_test_lock); 16388c2ecf20Sopenharmony_ci list_add(&nfit_res->list, &t->resources); 16398c2ecf20Sopenharmony_ci spin_unlock(&nfit_test_lock); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci return nfit_res->buf; 16428c2ecf20Sopenharmony_ci err: 16438c2ecf20Sopenharmony_ci if (*dma && size >= DIMM_SIZE) 16448c2ecf20Sopenharmony_ci gen_pool_free(nfit_pool, *dma, size); 16458c2ecf20Sopenharmony_ci if (buf) 16468c2ecf20Sopenharmony_ci vfree(buf); 16478c2ecf20Sopenharmony_ci kfree(nfit_res); 16488c2ecf20Sopenharmony_ci return NULL; 16498c2ecf20Sopenharmony_ci} 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_cistatic void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct genpool_data_align data = { 16548c2ecf20Sopenharmony_ci .align = SZ_128M, 16558c2ecf20Sopenharmony_ci }; 16568c2ecf20Sopenharmony_ci void *buf = vmalloc(size); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (size >= DIMM_SIZE) 16598c2ecf20Sopenharmony_ci *dma = gen_pool_alloc_algo(nfit_pool, size, 16608c2ecf20Sopenharmony_ci gen_pool_first_fit_align, &data); 16618c2ecf20Sopenharmony_ci else 16628c2ecf20Sopenharmony_ci *dma = (unsigned long) buf; 16638c2ecf20Sopenharmony_ci return __test_alloc(t, size, dma, buf); 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cistatic struct nfit_test_resource *nfit_test_lookup(resource_size_t addr) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci int i; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(instances); i++) { 16718c2ecf20Sopenharmony_ci struct nfit_test_resource *n, *nfit_res = NULL; 16728c2ecf20Sopenharmony_ci struct nfit_test *t = instances[i]; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (!t) 16758c2ecf20Sopenharmony_ci continue; 16768c2ecf20Sopenharmony_ci spin_lock(&nfit_test_lock); 16778c2ecf20Sopenharmony_ci list_for_each_entry(n, &t->resources, list) { 16788c2ecf20Sopenharmony_ci if (addr >= n->res.start && (addr < n->res.start 16798c2ecf20Sopenharmony_ci + resource_size(&n->res))) { 16808c2ecf20Sopenharmony_ci nfit_res = n; 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci } else if (addr >= (unsigned long) n->buf 16838c2ecf20Sopenharmony_ci && (addr < (unsigned long) n->buf 16848c2ecf20Sopenharmony_ci + resource_size(&n->res))) { 16858c2ecf20Sopenharmony_ci nfit_res = n; 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci spin_unlock(&nfit_test_lock); 16908c2ecf20Sopenharmony_ci if (nfit_res) 16918c2ecf20Sopenharmony_ci return nfit_res; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci return NULL; 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_cistatic int ars_state_init(struct device *dev, struct ars_state *ars_state) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci /* for testing, only store up to n records that fit within 4k */ 17008c2ecf20Sopenharmony_ci ars_state->ars_status = devm_kzalloc(dev, 17018c2ecf20Sopenharmony_ci sizeof(struct nd_cmd_ars_status) + SZ_4K, GFP_KERNEL); 17028c2ecf20Sopenharmony_ci if (!ars_state->ars_status) 17038c2ecf20Sopenharmony_ci return -ENOMEM; 17048c2ecf20Sopenharmony_ci spin_lock_init(&ars_state->lock); 17058c2ecf20Sopenharmony_ci return 0; 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cistatic void put_dimms(void *data) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci struct nfit_test *t = data; 17118c2ecf20Sopenharmony_ci int i; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) 17148c2ecf20Sopenharmony_ci if (t->dimm_dev[i]) 17158c2ecf20Sopenharmony_ci device_unregister(t->dimm_dev[i]); 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic struct class *nfit_test_dimm; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic int dimm_name_to_id(struct device *dev) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci int dimm; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (sscanf(dev_name(dev), "test_dimm%d", &dimm) != 1) 17258c2ecf20Sopenharmony_ci return -ENXIO; 17268c2ecf20Sopenharmony_ci return dimm; 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic ssize_t handle_show(struct device *dev, struct device_attribute *attr, 17308c2ecf20Sopenharmony_ci char *buf) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (dimm < 0) 17358c2ecf20Sopenharmony_ci return dimm; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", handle[dimm]); 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ciDEVICE_ATTR_RO(handle); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cistatic ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr, 17428c2ecf20Sopenharmony_ci char *buf) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (dimm < 0) 17478c2ecf20Sopenharmony_ci return dimm; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci return sprintf(buf, "%#lx\n", dimm_fail_cmd_flags[dimm]); 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_cistatic ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr, 17538c2ecf20Sopenharmony_ci const char *buf, size_t size) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 17568c2ecf20Sopenharmony_ci unsigned long val; 17578c2ecf20Sopenharmony_ci ssize_t rc; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci if (dimm < 0) 17608c2ecf20Sopenharmony_ci return dimm; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci rc = kstrtol(buf, 0, &val); 17638c2ecf20Sopenharmony_ci if (rc) 17648c2ecf20Sopenharmony_ci return rc; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci dimm_fail_cmd_flags[dimm] = val; 17678c2ecf20Sopenharmony_ci return size; 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fail_cmd); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic ssize_t fail_cmd_code_show(struct device *dev, struct device_attribute *attr, 17728c2ecf20Sopenharmony_ci char *buf) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci if (dimm < 0) 17778c2ecf20Sopenharmony_ci return dimm; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", dimm_fail_cmd_code[dimm]); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_cistatic ssize_t fail_cmd_code_store(struct device *dev, struct device_attribute *attr, 17838c2ecf20Sopenharmony_ci const char *buf, size_t size) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 17868c2ecf20Sopenharmony_ci unsigned long val; 17878c2ecf20Sopenharmony_ci ssize_t rc; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (dimm < 0) 17908c2ecf20Sopenharmony_ci return dimm; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci rc = kstrtol(buf, 0, &val); 17938c2ecf20Sopenharmony_ci if (rc) 17948c2ecf20Sopenharmony_ci return rc; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci dimm_fail_cmd_code[dimm] = val; 17978c2ecf20Sopenharmony_ci return size; 17988c2ecf20Sopenharmony_ci} 17998c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fail_cmd_code); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic ssize_t lock_dimm_store(struct device *dev, 18028c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t size) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci int dimm = dimm_name_to_id(dev); 18058c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[dimm]; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci sec->state = ND_INTEL_SEC_STATE_ENABLED | ND_INTEL_SEC_STATE_LOCKED; 18088c2ecf20Sopenharmony_ci return size; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_cistatic DEVICE_ATTR_WO(lock_dimm); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic struct attribute *nfit_test_dimm_attributes[] = { 18138c2ecf20Sopenharmony_ci &dev_attr_fail_cmd.attr, 18148c2ecf20Sopenharmony_ci &dev_attr_fail_cmd_code.attr, 18158c2ecf20Sopenharmony_ci &dev_attr_handle.attr, 18168c2ecf20Sopenharmony_ci &dev_attr_lock_dimm.attr, 18178c2ecf20Sopenharmony_ci NULL, 18188c2ecf20Sopenharmony_ci}; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic struct attribute_group nfit_test_dimm_attribute_group = { 18218c2ecf20Sopenharmony_ci .attrs = nfit_test_dimm_attributes, 18228c2ecf20Sopenharmony_ci}; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic const struct attribute_group *nfit_test_dimm_attribute_groups[] = { 18258c2ecf20Sopenharmony_ci &nfit_test_dimm_attribute_group, 18268c2ecf20Sopenharmony_ci NULL, 18278c2ecf20Sopenharmony_ci}; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic int nfit_test_dimm_init(struct nfit_test *t) 18308c2ecf20Sopenharmony_ci{ 18318c2ecf20Sopenharmony_ci int i; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci if (devm_add_action_or_reset(&t->pdev.dev, put_dimms, t)) 18348c2ecf20Sopenharmony_ci return -ENOMEM; 18358c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 18368c2ecf20Sopenharmony_ci t->dimm_dev[i] = device_create_with_groups(nfit_test_dimm, 18378c2ecf20Sopenharmony_ci &t->pdev.dev, 0, NULL, 18388c2ecf20Sopenharmony_ci nfit_test_dimm_attribute_groups, 18398c2ecf20Sopenharmony_ci "test_dimm%d", i + t->dcr_idx); 18408c2ecf20Sopenharmony_ci if (!t->dimm_dev[i]) 18418c2ecf20Sopenharmony_ci return -ENOMEM; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci return 0; 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic void security_init(struct nfit_test *t) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci int i; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 18518c2ecf20Sopenharmony_ci struct nfit_test_sec *sec = &dimm_sec_info[i]; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci sec->ext_state = ND_INTEL_SEC_ESTATE_ENABLED; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_cistatic void smart_init(struct nfit_test *t) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci int i; 18608c2ecf20Sopenharmony_ci const struct nd_intel_smart_threshold smart_t_data = { 18618c2ecf20Sopenharmony_ci .alarm_control = ND_INTEL_SMART_SPARE_TRIP 18628c2ecf20Sopenharmony_ci | ND_INTEL_SMART_TEMP_TRIP, 18638c2ecf20Sopenharmony_ci .media_temperature = 40 * 16, 18648c2ecf20Sopenharmony_ci .ctrl_temperature = 30 * 16, 18658c2ecf20Sopenharmony_ci .spares = 5, 18668c2ecf20Sopenharmony_ci }; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 18698c2ecf20Sopenharmony_ci memcpy(&t->smart[i], &smart_def, sizeof(smart_def)); 18708c2ecf20Sopenharmony_ci memcpy(&t->smart_threshold[i], &smart_t_data, 18718c2ecf20Sopenharmony_ci sizeof(smart_t_data)); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic int nfit_test0_alloc(struct nfit_test *t) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA 18788c2ecf20Sopenharmony_ci + sizeof(struct acpi_nfit_memory_map) * NUM_MEM 18798c2ecf20Sopenharmony_ci + sizeof(struct acpi_nfit_control_region) * NUM_DCR 18808c2ecf20Sopenharmony_ci + offsetof(struct acpi_nfit_control_region, 18818c2ecf20Sopenharmony_ci window_size) * NUM_DCR 18828c2ecf20Sopenharmony_ci + sizeof(struct acpi_nfit_data_region) * NUM_BDW 18838c2ecf20Sopenharmony_ci + (sizeof(struct acpi_nfit_flush_address) 18848c2ecf20Sopenharmony_ci + sizeof(u64) * NUM_HINTS) * NUM_DCR 18858c2ecf20Sopenharmony_ci + sizeof(struct acpi_nfit_capabilities); 18868c2ecf20Sopenharmony_ci int i; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma); 18898c2ecf20Sopenharmony_ci if (!t->nfit_buf) 18908c2ecf20Sopenharmony_ci return -ENOMEM; 18918c2ecf20Sopenharmony_ci t->nfit_size = nfit_size; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci t->spa_set[0] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[0]); 18948c2ecf20Sopenharmony_ci if (!t->spa_set[0]) 18958c2ecf20Sopenharmony_ci return -ENOMEM; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci t->spa_set[1] = test_alloc(t, SPA1_SIZE, &t->spa_set_dma[1]); 18988c2ecf20Sopenharmony_ci if (!t->spa_set[1]) 18998c2ecf20Sopenharmony_ci return -ENOMEM; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci t->spa_set[2] = test_alloc(t, SPA0_SIZE, &t->spa_set_dma[2]); 19028c2ecf20Sopenharmony_ci if (!t->spa_set[2]) 19038c2ecf20Sopenharmony_ci return -ENOMEM; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 19068c2ecf20Sopenharmony_ci t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]); 19078c2ecf20Sopenharmony_ci if (!t->dimm[i]) 19088c2ecf20Sopenharmony_ci return -ENOMEM; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci t->label[i] = test_alloc(t, LABEL_SIZE, &t->label_dma[i]); 19118c2ecf20Sopenharmony_ci if (!t->label[i]) 19128c2ecf20Sopenharmony_ci return -ENOMEM; 19138c2ecf20Sopenharmony_ci sprintf(t->label[i], "label%d", i); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci t->flush[i] = test_alloc(t, max(PAGE_SIZE, 19168c2ecf20Sopenharmony_ci sizeof(u64) * NUM_HINTS), 19178c2ecf20Sopenharmony_ci &t->flush_dma[i]); 19188c2ecf20Sopenharmony_ci if (!t->flush[i]) 19198c2ecf20Sopenharmony_ci return -ENOMEM; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 19238c2ecf20Sopenharmony_ci t->dcr[i] = test_alloc(t, LABEL_SIZE, &t->dcr_dma[i]); 19248c2ecf20Sopenharmony_ci if (!t->dcr[i]) 19258c2ecf20Sopenharmony_ci return -ENOMEM; 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci t->_fit = test_alloc(t, sizeof(union acpi_object **), &t->_fit_dma); 19298c2ecf20Sopenharmony_ci if (!t->_fit) 19308c2ecf20Sopenharmony_ci return -ENOMEM; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci if (nfit_test_dimm_init(t)) 19338c2ecf20Sopenharmony_ci return -ENOMEM; 19348c2ecf20Sopenharmony_ci smart_init(t); 19358c2ecf20Sopenharmony_ci security_init(t); 19368c2ecf20Sopenharmony_ci return ars_state_init(&t->pdev.dev, &t->ars_state); 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_cistatic int nfit_test1_alloc(struct nfit_test *t) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2 19428c2ecf20Sopenharmony_ci + sizeof(struct acpi_nfit_memory_map) * 2 19438c2ecf20Sopenharmony_ci + offsetof(struct acpi_nfit_control_region, window_size) * 2; 19448c2ecf20Sopenharmony_ci int i; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma); 19478c2ecf20Sopenharmony_ci if (!t->nfit_buf) 19488c2ecf20Sopenharmony_ci return -ENOMEM; 19498c2ecf20Sopenharmony_ci t->nfit_size = nfit_size; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci t->spa_set[0] = test_alloc(t, SPA2_SIZE, &t->spa_set_dma[0]); 19528c2ecf20Sopenharmony_ci if (!t->spa_set[0]) 19538c2ecf20Sopenharmony_ci return -ENOMEM; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci for (i = 0; i < t->num_dcr; i++) { 19568c2ecf20Sopenharmony_ci t->label[i] = test_alloc(t, LABEL_SIZE, &t->label_dma[i]); 19578c2ecf20Sopenharmony_ci if (!t->label[i]) 19588c2ecf20Sopenharmony_ci return -ENOMEM; 19598c2ecf20Sopenharmony_ci sprintf(t->label[i], "label%d", i); 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci t->spa_set[1] = test_alloc(t, SPA_VCD_SIZE, &t->spa_set_dma[1]); 19638c2ecf20Sopenharmony_ci if (!t->spa_set[1]) 19648c2ecf20Sopenharmony_ci return -ENOMEM; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (nfit_test_dimm_init(t)) 19678c2ecf20Sopenharmony_ci return -ENOMEM; 19688c2ecf20Sopenharmony_ci smart_init(t); 19698c2ecf20Sopenharmony_ci return ars_state_init(&t->pdev.dev, &t->ars_state); 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic void dcr_common_init(struct acpi_nfit_control_region *dcr) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci dcr->vendor_id = 0xabcd; 19758c2ecf20Sopenharmony_ci dcr->device_id = 0; 19768c2ecf20Sopenharmony_ci dcr->revision_id = 1; 19778c2ecf20Sopenharmony_ci dcr->valid_fields = 1; 19788c2ecf20Sopenharmony_ci dcr->manufacturing_location = 0xa; 19798c2ecf20Sopenharmony_ci dcr->manufacturing_date = cpu_to_be16(2016); 19808c2ecf20Sopenharmony_ci} 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cistatic void nfit_test0_setup(struct nfit_test *t) 19838c2ecf20Sopenharmony_ci{ 19848c2ecf20Sopenharmony_ci const int flush_hint_size = sizeof(struct acpi_nfit_flush_address) 19858c2ecf20Sopenharmony_ci + (sizeof(u64) * NUM_HINTS); 19868c2ecf20Sopenharmony_ci struct acpi_nfit_desc *acpi_desc; 19878c2ecf20Sopenharmony_ci struct acpi_nfit_memory_map *memdev; 19888c2ecf20Sopenharmony_ci void *nfit_buf = t->nfit_buf; 19898c2ecf20Sopenharmony_ci struct acpi_nfit_system_address *spa; 19908c2ecf20Sopenharmony_ci struct acpi_nfit_control_region *dcr; 19918c2ecf20Sopenharmony_ci struct acpi_nfit_data_region *bdw; 19928c2ecf20Sopenharmony_ci struct acpi_nfit_flush_address *flush; 19938c2ecf20Sopenharmony_ci struct acpi_nfit_capabilities *pcap; 19948c2ecf20Sopenharmony_ci unsigned int offset = 0, i; 19958c2ecf20Sopenharmony_ci unsigned long *acpi_mask; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* 19988c2ecf20Sopenharmony_ci * spa0 (interleave first half of dimm0 and dimm1, note storage 19998c2ecf20Sopenharmony_ci * does not actually alias the related block-data-window 20008c2ecf20Sopenharmony_ci * regions) 20018c2ecf20Sopenharmony_ci */ 20028c2ecf20Sopenharmony_ci spa = nfit_buf; 20038c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20048c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20058c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 20068c2ecf20Sopenharmony_ci spa->range_index = 0+1; 20078c2ecf20Sopenharmony_ci spa->address = t->spa_set_dma[0]; 20088c2ecf20Sopenharmony_ci spa->length = SPA0_SIZE; 20098c2ecf20Sopenharmony_ci offset += spa->header.length; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* 20128c2ecf20Sopenharmony_ci * spa1 (interleave last half of the 4 DIMMS, note storage 20138c2ecf20Sopenharmony_ci * does not actually alias the related block-data-window 20148c2ecf20Sopenharmony_ci * regions) 20158c2ecf20Sopenharmony_ci */ 20168c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20178c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20188c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20198c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 20208c2ecf20Sopenharmony_ci spa->range_index = 1+1; 20218c2ecf20Sopenharmony_ci spa->address = t->spa_set_dma[1]; 20228c2ecf20Sopenharmony_ci spa->length = SPA1_SIZE; 20238c2ecf20Sopenharmony_ci offset += spa->header.length; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci /* spa2 (dcr0) dimm0 */ 20268c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20278c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20288c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20298c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 20308c2ecf20Sopenharmony_ci spa->range_index = 2+1; 20318c2ecf20Sopenharmony_ci spa->address = t->dcr_dma[0]; 20328c2ecf20Sopenharmony_ci spa->length = DCR_SIZE; 20338c2ecf20Sopenharmony_ci offset += spa->header.length; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* spa3 (dcr1) dimm1 */ 20368c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20378c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20388c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20398c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 20408c2ecf20Sopenharmony_ci spa->range_index = 3+1; 20418c2ecf20Sopenharmony_ci spa->address = t->dcr_dma[1]; 20428c2ecf20Sopenharmony_ci spa->length = DCR_SIZE; 20438c2ecf20Sopenharmony_ci offset += spa->header.length; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci /* spa4 (dcr2) dimm2 */ 20468c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20478c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20488c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20498c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 20508c2ecf20Sopenharmony_ci spa->range_index = 4+1; 20518c2ecf20Sopenharmony_ci spa->address = t->dcr_dma[2]; 20528c2ecf20Sopenharmony_ci spa->length = DCR_SIZE; 20538c2ecf20Sopenharmony_ci offset += spa->header.length; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* spa5 (dcr3) dimm3 */ 20568c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20578c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20588c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20598c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 20608c2ecf20Sopenharmony_ci spa->range_index = 5+1; 20618c2ecf20Sopenharmony_ci spa->address = t->dcr_dma[3]; 20628c2ecf20Sopenharmony_ci spa->length = DCR_SIZE; 20638c2ecf20Sopenharmony_ci offset += spa->header.length; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* spa6 (bdw for dcr0) dimm0 */ 20668c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20678c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20688c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20698c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 20708c2ecf20Sopenharmony_ci spa->range_index = 6+1; 20718c2ecf20Sopenharmony_ci spa->address = t->dimm_dma[0]; 20728c2ecf20Sopenharmony_ci spa->length = DIMM_SIZE; 20738c2ecf20Sopenharmony_ci offset += spa->header.length; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci /* spa7 (bdw for dcr1) dimm1 */ 20768c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20778c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20788c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20798c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 20808c2ecf20Sopenharmony_ci spa->range_index = 7+1; 20818c2ecf20Sopenharmony_ci spa->address = t->dimm_dma[1]; 20828c2ecf20Sopenharmony_ci spa->length = DIMM_SIZE; 20838c2ecf20Sopenharmony_ci offset += spa->header.length; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci /* spa8 (bdw for dcr2) dimm2 */ 20868c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20878c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20888c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20898c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 20908c2ecf20Sopenharmony_ci spa->range_index = 8+1; 20918c2ecf20Sopenharmony_ci spa->address = t->dimm_dma[2]; 20928c2ecf20Sopenharmony_ci spa->length = DIMM_SIZE; 20938c2ecf20Sopenharmony_ci offset += spa->header.length; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci /* spa9 (bdw for dcr3) dimm3 */ 20968c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 20978c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 20988c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 20998c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 21008c2ecf20Sopenharmony_ci spa->range_index = 9+1; 21018c2ecf20Sopenharmony_ci spa->address = t->dimm_dma[3]; 21028c2ecf20Sopenharmony_ci spa->length = DIMM_SIZE; 21038c2ecf20Sopenharmony_ci offset += spa->header.length; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* mem-region0 (spa0, dimm0) */ 21068c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21078c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21088c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21098c2ecf20Sopenharmony_ci memdev->device_handle = handle[0]; 21108c2ecf20Sopenharmony_ci memdev->physical_id = 0; 21118c2ecf20Sopenharmony_ci memdev->region_id = 0; 21128c2ecf20Sopenharmony_ci memdev->range_index = 0+1; 21138c2ecf20Sopenharmony_ci memdev->region_index = 4+1; 21148c2ecf20Sopenharmony_ci memdev->region_size = SPA0_SIZE/2; 21158c2ecf20Sopenharmony_ci memdev->region_offset = 1; 21168c2ecf20Sopenharmony_ci memdev->address = 0; 21178c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 21188c2ecf20Sopenharmony_ci memdev->interleave_ways = 2; 21198c2ecf20Sopenharmony_ci offset += memdev->header.length; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci /* mem-region1 (spa0, dimm1) */ 21228c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21238c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21248c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21258c2ecf20Sopenharmony_ci memdev->device_handle = handle[1]; 21268c2ecf20Sopenharmony_ci memdev->physical_id = 1; 21278c2ecf20Sopenharmony_ci memdev->region_id = 0; 21288c2ecf20Sopenharmony_ci memdev->range_index = 0+1; 21298c2ecf20Sopenharmony_ci memdev->region_index = 5+1; 21308c2ecf20Sopenharmony_ci memdev->region_size = SPA0_SIZE/2; 21318c2ecf20Sopenharmony_ci memdev->region_offset = (1 << 8); 21328c2ecf20Sopenharmony_ci memdev->address = 0; 21338c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 21348c2ecf20Sopenharmony_ci memdev->interleave_ways = 2; 21358c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; 21368c2ecf20Sopenharmony_ci offset += memdev->header.length; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci /* mem-region2 (spa1, dimm0) */ 21398c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21408c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21418c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21428c2ecf20Sopenharmony_ci memdev->device_handle = handle[0]; 21438c2ecf20Sopenharmony_ci memdev->physical_id = 0; 21448c2ecf20Sopenharmony_ci memdev->region_id = 1; 21458c2ecf20Sopenharmony_ci memdev->range_index = 1+1; 21468c2ecf20Sopenharmony_ci memdev->region_index = 4+1; 21478c2ecf20Sopenharmony_ci memdev->region_size = SPA1_SIZE/4; 21488c2ecf20Sopenharmony_ci memdev->region_offset = (1 << 16); 21498c2ecf20Sopenharmony_ci memdev->address = SPA0_SIZE/2; 21508c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 21518c2ecf20Sopenharmony_ci memdev->interleave_ways = 4; 21528c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; 21538c2ecf20Sopenharmony_ci offset += memdev->header.length; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci /* mem-region3 (spa1, dimm1) */ 21568c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21578c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21588c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21598c2ecf20Sopenharmony_ci memdev->device_handle = handle[1]; 21608c2ecf20Sopenharmony_ci memdev->physical_id = 1; 21618c2ecf20Sopenharmony_ci memdev->region_id = 1; 21628c2ecf20Sopenharmony_ci memdev->range_index = 1+1; 21638c2ecf20Sopenharmony_ci memdev->region_index = 5+1; 21648c2ecf20Sopenharmony_ci memdev->region_size = SPA1_SIZE/4; 21658c2ecf20Sopenharmony_ci memdev->region_offset = (1 << 24); 21668c2ecf20Sopenharmony_ci memdev->address = SPA0_SIZE/2; 21678c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 21688c2ecf20Sopenharmony_ci memdev->interleave_ways = 4; 21698c2ecf20Sopenharmony_ci offset += memdev->header.length; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci /* mem-region4 (spa1, dimm2) */ 21728c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21738c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21748c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21758c2ecf20Sopenharmony_ci memdev->device_handle = handle[2]; 21768c2ecf20Sopenharmony_ci memdev->physical_id = 2; 21778c2ecf20Sopenharmony_ci memdev->region_id = 0; 21788c2ecf20Sopenharmony_ci memdev->range_index = 1+1; 21798c2ecf20Sopenharmony_ci memdev->region_index = 6+1; 21808c2ecf20Sopenharmony_ci memdev->region_size = SPA1_SIZE/4; 21818c2ecf20Sopenharmony_ci memdev->region_offset = (1ULL << 32); 21828c2ecf20Sopenharmony_ci memdev->address = SPA0_SIZE/2; 21838c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 21848c2ecf20Sopenharmony_ci memdev->interleave_ways = 4; 21858c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; 21868c2ecf20Sopenharmony_ci offset += memdev->header.length; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci /* mem-region5 (spa1, dimm3) */ 21898c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 21908c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 21918c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 21928c2ecf20Sopenharmony_ci memdev->device_handle = handle[3]; 21938c2ecf20Sopenharmony_ci memdev->physical_id = 3; 21948c2ecf20Sopenharmony_ci memdev->region_id = 0; 21958c2ecf20Sopenharmony_ci memdev->range_index = 1+1; 21968c2ecf20Sopenharmony_ci memdev->region_index = 7+1; 21978c2ecf20Sopenharmony_ci memdev->region_size = SPA1_SIZE/4; 21988c2ecf20Sopenharmony_ci memdev->region_offset = (1ULL << 40); 21998c2ecf20Sopenharmony_ci memdev->address = SPA0_SIZE/2; 22008c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22018c2ecf20Sopenharmony_ci memdev->interleave_ways = 4; 22028c2ecf20Sopenharmony_ci offset += memdev->header.length; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci /* mem-region6 (spa/dcr0, dimm0) */ 22058c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22068c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22078c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22088c2ecf20Sopenharmony_ci memdev->device_handle = handle[0]; 22098c2ecf20Sopenharmony_ci memdev->physical_id = 0; 22108c2ecf20Sopenharmony_ci memdev->region_id = 0; 22118c2ecf20Sopenharmony_ci memdev->range_index = 2+1; 22128c2ecf20Sopenharmony_ci memdev->region_index = 0+1; 22138c2ecf20Sopenharmony_ci memdev->region_size = 0; 22148c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22158c2ecf20Sopenharmony_ci memdev->address = 0; 22168c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22178c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22188c2ecf20Sopenharmony_ci offset += memdev->header.length; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci /* mem-region7 (spa/dcr1, dimm1) */ 22218c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22228c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22238c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22248c2ecf20Sopenharmony_ci memdev->device_handle = handle[1]; 22258c2ecf20Sopenharmony_ci memdev->physical_id = 1; 22268c2ecf20Sopenharmony_ci memdev->region_id = 0; 22278c2ecf20Sopenharmony_ci memdev->range_index = 3+1; 22288c2ecf20Sopenharmony_ci memdev->region_index = 1+1; 22298c2ecf20Sopenharmony_ci memdev->region_size = 0; 22308c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22318c2ecf20Sopenharmony_ci memdev->address = 0; 22328c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22338c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22348c2ecf20Sopenharmony_ci offset += memdev->header.length; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /* mem-region8 (spa/dcr2, dimm2) */ 22378c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22388c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22398c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22408c2ecf20Sopenharmony_ci memdev->device_handle = handle[2]; 22418c2ecf20Sopenharmony_ci memdev->physical_id = 2; 22428c2ecf20Sopenharmony_ci memdev->region_id = 0; 22438c2ecf20Sopenharmony_ci memdev->range_index = 4+1; 22448c2ecf20Sopenharmony_ci memdev->region_index = 2+1; 22458c2ecf20Sopenharmony_ci memdev->region_size = 0; 22468c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22478c2ecf20Sopenharmony_ci memdev->address = 0; 22488c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22498c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22508c2ecf20Sopenharmony_ci offset += memdev->header.length; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci /* mem-region9 (spa/dcr3, dimm3) */ 22538c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22548c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22558c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22568c2ecf20Sopenharmony_ci memdev->device_handle = handle[3]; 22578c2ecf20Sopenharmony_ci memdev->physical_id = 3; 22588c2ecf20Sopenharmony_ci memdev->region_id = 0; 22598c2ecf20Sopenharmony_ci memdev->range_index = 5+1; 22608c2ecf20Sopenharmony_ci memdev->region_index = 3+1; 22618c2ecf20Sopenharmony_ci memdev->region_size = 0; 22628c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22638c2ecf20Sopenharmony_ci memdev->address = 0; 22648c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22658c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22668c2ecf20Sopenharmony_ci offset += memdev->header.length; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci /* mem-region10 (spa/bdw0, dimm0) */ 22698c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22708c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22718c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22728c2ecf20Sopenharmony_ci memdev->device_handle = handle[0]; 22738c2ecf20Sopenharmony_ci memdev->physical_id = 0; 22748c2ecf20Sopenharmony_ci memdev->region_id = 0; 22758c2ecf20Sopenharmony_ci memdev->range_index = 6+1; 22768c2ecf20Sopenharmony_ci memdev->region_index = 0+1; 22778c2ecf20Sopenharmony_ci memdev->region_size = 0; 22788c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22798c2ecf20Sopenharmony_ci memdev->address = 0; 22808c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22818c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22828c2ecf20Sopenharmony_ci offset += memdev->header.length; 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* mem-region11 (spa/bdw1, dimm1) */ 22858c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 22868c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 22878c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 22888c2ecf20Sopenharmony_ci memdev->device_handle = handle[1]; 22898c2ecf20Sopenharmony_ci memdev->physical_id = 1; 22908c2ecf20Sopenharmony_ci memdev->region_id = 0; 22918c2ecf20Sopenharmony_ci memdev->range_index = 7+1; 22928c2ecf20Sopenharmony_ci memdev->region_index = 1+1; 22938c2ecf20Sopenharmony_ci memdev->region_size = 0; 22948c2ecf20Sopenharmony_ci memdev->region_offset = 0; 22958c2ecf20Sopenharmony_ci memdev->address = 0; 22968c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 22978c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 22988c2ecf20Sopenharmony_ci offset += memdev->header.length; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci /* mem-region12 (spa/bdw2, dimm2) */ 23018c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 23028c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 23038c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 23048c2ecf20Sopenharmony_ci memdev->device_handle = handle[2]; 23058c2ecf20Sopenharmony_ci memdev->physical_id = 2; 23068c2ecf20Sopenharmony_ci memdev->region_id = 0; 23078c2ecf20Sopenharmony_ci memdev->range_index = 8+1; 23088c2ecf20Sopenharmony_ci memdev->region_index = 2+1; 23098c2ecf20Sopenharmony_ci memdev->region_size = 0; 23108c2ecf20Sopenharmony_ci memdev->region_offset = 0; 23118c2ecf20Sopenharmony_ci memdev->address = 0; 23128c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 23138c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 23148c2ecf20Sopenharmony_ci offset += memdev->header.length; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* mem-region13 (spa/dcr3, dimm3) */ 23178c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 23188c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 23198c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 23208c2ecf20Sopenharmony_ci memdev->device_handle = handle[3]; 23218c2ecf20Sopenharmony_ci memdev->physical_id = 3; 23228c2ecf20Sopenharmony_ci memdev->region_id = 0; 23238c2ecf20Sopenharmony_ci memdev->range_index = 9+1; 23248c2ecf20Sopenharmony_ci memdev->region_index = 3+1; 23258c2ecf20Sopenharmony_ci memdev->region_size = 0; 23268c2ecf20Sopenharmony_ci memdev->region_offset = 0; 23278c2ecf20Sopenharmony_ci memdev->address = 0; 23288c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 23298c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 23308c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; 23318c2ecf20Sopenharmony_ci offset += memdev->header.length; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* dcr-descriptor0: blk */ 23348c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 23358c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 23368c2ecf20Sopenharmony_ci dcr->header.length = sizeof(*dcr); 23378c2ecf20Sopenharmony_ci dcr->region_index = 0+1; 23388c2ecf20Sopenharmony_ci dcr_common_init(dcr); 23398c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[0]; 23408c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BLK; 23418c2ecf20Sopenharmony_ci dcr->windows = 1; 23428c2ecf20Sopenharmony_ci dcr->window_size = DCR_SIZE; 23438c2ecf20Sopenharmony_ci dcr->command_offset = 0; 23448c2ecf20Sopenharmony_ci dcr->command_size = 8; 23458c2ecf20Sopenharmony_ci dcr->status_offset = 8; 23468c2ecf20Sopenharmony_ci dcr->status_size = 4; 23478c2ecf20Sopenharmony_ci offset += dcr->header.length; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* dcr-descriptor1: blk */ 23508c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 23518c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 23528c2ecf20Sopenharmony_ci dcr->header.length = sizeof(*dcr); 23538c2ecf20Sopenharmony_ci dcr->region_index = 1+1; 23548c2ecf20Sopenharmony_ci dcr_common_init(dcr); 23558c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[1]; 23568c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BLK; 23578c2ecf20Sopenharmony_ci dcr->windows = 1; 23588c2ecf20Sopenharmony_ci dcr->window_size = DCR_SIZE; 23598c2ecf20Sopenharmony_ci dcr->command_offset = 0; 23608c2ecf20Sopenharmony_ci dcr->command_size = 8; 23618c2ecf20Sopenharmony_ci dcr->status_offset = 8; 23628c2ecf20Sopenharmony_ci dcr->status_size = 4; 23638c2ecf20Sopenharmony_ci offset += dcr->header.length; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* dcr-descriptor2: blk */ 23668c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 23678c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 23688c2ecf20Sopenharmony_ci dcr->header.length = sizeof(*dcr); 23698c2ecf20Sopenharmony_ci dcr->region_index = 2+1; 23708c2ecf20Sopenharmony_ci dcr_common_init(dcr); 23718c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[2]; 23728c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BLK; 23738c2ecf20Sopenharmony_ci dcr->windows = 1; 23748c2ecf20Sopenharmony_ci dcr->window_size = DCR_SIZE; 23758c2ecf20Sopenharmony_ci dcr->command_offset = 0; 23768c2ecf20Sopenharmony_ci dcr->command_size = 8; 23778c2ecf20Sopenharmony_ci dcr->status_offset = 8; 23788c2ecf20Sopenharmony_ci dcr->status_size = 4; 23798c2ecf20Sopenharmony_ci offset += dcr->header.length; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci /* dcr-descriptor3: blk */ 23828c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 23838c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 23848c2ecf20Sopenharmony_ci dcr->header.length = sizeof(*dcr); 23858c2ecf20Sopenharmony_ci dcr->region_index = 3+1; 23868c2ecf20Sopenharmony_ci dcr_common_init(dcr); 23878c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[3]; 23888c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BLK; 23898c2ecf20Sopenharmony_ci dcr->windows = 1; 23908c2ecf20Sopenharmony_ci dcr->window_size = DCR_SIZE; 23918c2ecf20Sopenharmony_ci dcr->command_offset = 0; 23928c2ecf20Sopenharmony_ci dcr->command_size = 8; 23938c2ecf20Sopenharmony_ci dcr->status_offset = 8; 23948c2ecf20Sopenharmony_ci dcr->status_size = 4; 23958c2ecf20Sopenharmony_ci offset += dcr->header.length; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci /* dcr-descriptor0: pmem */ 23988c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 23998c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 24008c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 24018c2ecf20Sopenharmony_ci window_size); 24028c2ecf20Sopenharmony_ci dcr->region_index = 4+1; 24038c2ecf20Sopenharmony_ci dcr_common_init(dcr); 24048c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[0]; 24058c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTEN; 24068c2ecf20Sopenharmony_ci dcr->windows = 0; 24078c2ecf20Sopenharmony_ci offset += dcr->header.length; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci /* dcr-descriptor1: pmem */ 24108c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 24118c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 24128c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 24138c2ecf20Sopenharmony_ci window_size); 24148c2ecf20Sopenharmony_ci dcr->region_index = 5+1; 24158c2ecf20Sopenharmony_ci dcr_common_init(dcr); 24168c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[1]; 24178c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTEN; 24188c2ecf20Sopenharmony_ci dcr->windows = 0; 24198c2ecf20Sopenharmony_ci offset += dcr->header.length; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci /* dcr-descriptor2: pmem */ 24228c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 24238c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 24248c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 24258c2ecf20Sopenharmony_ci window_size); 24268c2ecf20Sopenharmony_ci dcr->region_index = 6+1; 24278c2ecf20Sopenharmony_ci dcr_common_init(dcr); 24288c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[2]; 24298c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTEN; 24308c2ecf20Sopenharmony_ci dcr->windows = 0; 24318c2ecf20Sopenharmony_ci offset += dcr->header.length; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci /* dcr-descriptor3: pmem */ 24348c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 24358c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 24368c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 24378c2ecf20Sopenharmony_ci window_size); 24388c2ecf20Sopenharmony_ci dcr->region_index = 7+1; 24398c2ecf20Sopenharmony_ci dcr_common_init(dcr); 24408c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[3]; 24418c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTEN; 24428c2ecf20Sopenharmony_ci dcr->windows = 0; 24438c2ecf20Sopenharmony_ci offset += dcr->header.length; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci /* bdw0 (spa/dcr0, dimm0) */ 24468c2ecf20Sopenharmony_ci bdw = nfit_buf + offset; 24478c2ecf20Sopenharmony_ci bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; 24488c2ecf20Sopenharmony_ci bdw->header.length = sizeof(*bdw); 24498c2ecf20Sopenharmony_ci bdw->region_index = 0+1; 24508c2ecf20Sopenharmony_ci bdw->windows = 1; 24518c2ecf20Sopenharmony_ci bdw->offset = 0; 24528c2ecf20Sopenharmony_ci bdw->size = BDW_SIZE; 24538c2ecf20Sopenharmony_ci bdw->capacity = DIMM_SIZE; 24548c2ecf20Sopenharmony_ci bdw->start_address = 0; 24558c2ecf20Sopenharmony_ci offset += bdw->header.length; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci /* bdw1 (spa/dcr1, dimm1) */ 24588c2ecf20Sopenharmony_ci bdw = nfit_buf + offset; 24598c2ecf20Sopenharmony_ci bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; 24608c2ecf20Sopenharmony_ci bdw->header.length = sizeof(*bdw); 24618c2ecf20Sopenharmony_ci bdw->region_index = 1+1; 24628c2ecf20Sopenharmony_ci bdw->windows = 1; 24638c2ecf20Sopenharmony_ci bdw->offset = 0; 24648c2ecf20Sopenharmony_ci bdw->size = BDW_SIZE; 24658c2ecf20Sopenharmony_ci bdw->capacity = DIMM_SIZE; 24668c2ecf20Sopenharmony_ci bdw->start_address = 0; 24678c2ecf20Sopenharmony_ci offset += bdw->header.length; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci /* bdw2 (spa/dcr2, dimm2) */ 24708c2ecf20Sopenharmony_ci bdw = nfit_buf + offset; 24718c2ecf20Sopenharmony_ci bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; 24728c2ecf20Sopenharmony_ci bdw->header.length = sizeof(*bdw); 24738c2ecf20Sopenharmony_ci bdw->region_index = 2+1; 24748c2ecf20Sopenharmony_ci bdw->windows = 1; 24758c2ecf20Sopenharmony_ci bdw->offset = 0; 24768c2ecf20Sopenharmony_ci bdw->size = BDW_SIZE; 24778c2ecf20Sopenharmony_ci bdw->capacity = DIMM_SIZE; 24788c2ecf20Sopenharmony_ci bdw->start_address = 0; 24798c2ecf20Sopenharmony_ci offset += bdw->header.length; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci /* bdw3 (spa/dcr3, dimm3) */ 24828c2ecf20Sopenharmony_ci bdw = nfit_buf + offset; 24838c2ecf20Sopenharmony_ci bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; 24848c2ecf20Sopenharmony_ci bdw->header.length = sizeof(*bdw); 24858c2ecf20Sopenharmony_ci bdw->region_index = 3+1; 24868c2ecf20Sopenharmony_ci bdw->windows = 1; 24878c2ecf20Sopenharmony_ci bdw->offset = 0; 24888c2ecf20Sopenharmony_ci bdw->size = BDW_SIZE; 24898c2ecf20Sopenharmony_ci bdw->capacity = DIMM_SIZE; 24908c2ecf20Sopenharmony_ci bdw->start_address = 0; 24918c2ecf20Sopenharmony_ci offset += bdw->header.length; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* flush0 (dimm0) */ 24948c2ecf20Sopenharmony_ci flush = nfit_buf + offset; 24958c2ecf20Sopenharmony_ci flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; 24968c2ecf20Sopenharmony_ci flush->header.length = flush_hint_size; 24978c2ecf20Sopenharmony_ci flush->device_handle = handle[0]; 24988c2ecf20Sopenharmony_ci flush->hint_count = NUM_HINTS; 24998c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HINTS; i++) 25008c2ecf20Sopenharmony_ci flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); 25018c2ecf20Sopenharmony_ci offset += flush->header.length; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci /* flush1 (dimm1) */ 25048c2ecf20Sopenharmony_ci flush = nfit_buf + offset; 25058c2ecf20Sopenharmony_ci flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; 25068c2ecf20Sopenharmony_ci flush->header.length = flush_hint_size; 25078c2ecf20Sopenharmony_ci flush->device_handle = handle[1]; 25088c2ecf20Sopenharmony_ci flush->hint_count = NUM_HINTS; 25098c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HINTS; i++) 25108c2ecf20Sopenharmony_ci flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); 25118c2ecf20Sopenharmony_ci offset += flush->header.length; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* flush2 (dimm2) */ 25148c2ecf20Sopenharmony_ci flush = nfit_buf + offset; 25158c2ecf20Sopenharmony_ci flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; 25168c2ecf20Sopenharmony_ci flush->header.length = flush_hint_size; 25178c2ecf20Sopenharmony_ci flush->device_handle = handle[2]; 25188c2ecf20Sopenharmony_ci flush->hint_count = NUM_HINTS; 25198c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HINTS; i++) 25208c2ecf20Sopenharmony_ci flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); 25218c2ecf20Sopenharmony_ci offset += flush->header.length; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci /* flush3 (dimm3) */ 25248c2ecf20Sopenharmony_ci flush = nfit_buf + offset; 25258c2ecf20Sopenharmony_ci flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; 25268c2ecf20Sopenharmony_ci flush->header.length = flush_hint_size; 25278c2ecf20Sopenharmony_ci flush->device_handle = handle[3]; 25288c2ecf20Sopenharmony_ci flush->hint_count = NUM_HINTS; 25298c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HINTS; i++) 25308c2ecf20Sopenharmony_ci flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); 25318c2ecf20Sopenharmony_ci offset += flush->header.length; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci /* platform capabilities */ 25348c2ecf20Sopenharmony_ci pcap = nfit_buf + offset; 25358c2ecf20Sopenharmony_ci pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; 25368c2ecf20Sopenharmony_ci pcap->header.length = sizeof(*pcap); 25378c2ecf20Sopenharmony_ci pcap->highest_capability = 1; 25388c2ecf20Sopenharmony_ci pcap->capabilities = ACPI_NFIT_CAPABILITY_MEM_FLUSH; 25398c2ecf20Sopenharmony_ci offset += pcap->header.length; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci if (t->setup_hotplug) { 25428c2ecf20Sopenharmony_ci /* dcr-descriptor4: blk */ 25438c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 25448c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 25458c2ecf20Sopenharmony_ci dcr->header.length = sizeof(*dcr); 25468c2ecf20Sopenharmony_ci dcr->region_index = 8+1; 25478c2ecf20Sopenharmony_ci dcr_common_init(dcr); 25488c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[4]; 25498c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BLK; 25508c2ecf20Sopenharmony_ci dcr->windows = 1; 25518c2ecf20Sopenharmony_ci dcr->window_size = DCR_SIZE; 25528c2ecf20Sopenharmony_ci dcr->command_offset = 0; 25538c2ecf20Sopenharmony_ci dcr->command_size = 8; 25548c2ecf20Sopenharmony_ci dcr->status_offset = 8; 25558c2ecf20Sopenharmony_ci dcr->status_size = 4; 25568c2ecf20Sopenharmony_ci offset += dcr->header.length; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci /* dcr-descriptor4: pmem */ 25598c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 25608c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 25618c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 25628c2ecf20Sopenharmony_ci window_size); 25638c2ecf20Sopenharmony_ci dcr->region_index = 9+1; 25648c2ecf20Sopenharmony_ci dcr_common_init(dcr); 25658c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[4]; 25668c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTEN; 25678c2ecf20Sopenharmony_ci dcr->windows = 0; 25688c2ecf20Sopenharmony_ci offset += dcr->header.length; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci /* bdw4 (spa/dcr4, dimm4) */ 25718c2ecf20Sopenharmony_ci bdw = nfit_buf + offset; 25728c2ecf20Sopenharmony_ci bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; 25738c2ecf20Sopenharmony_ci bdw->header.length = sizeof(*bdw); 25748c2ecf20Sopenharmony_ci bdw->region_index = 8+1; 25758c2ecf20Sopenharmony_ci bdw->windows = 1; 25768c2ecf20Sopenharmony_ci bdw->offset = 0; 25778c2ecf20Sopenharmony_ci bdw->size = BDW_SIZE; 25788c2ecf20Sopenharmony_ci bdw->capacity = DIMM_SIZE; 25798c2ecf20Sopenharmony_ci bdw->start_address = 0; 25808c2ecf20Sopenharmony_ci offset += bdw->header.length; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci /* spa10 (dcr4) dimm4 */ 25838c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 25848c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 25858c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 25868c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); 25878c2ecf20Sopenharmony_ci spa->range_index = 10+1; 25888c2ecf20Sopenharmony_ci spa->address = t->dcr_dma[4]; 25898c2ecf20Sopenharmony_ci spa->length = DCR_SIZE; 25908c2ecf20Sopenharmony_ci offset += spa->header.length; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci /* 25938c2ecf20Sopenharmony_ci * spa11 (single-dimm interleave for hotplug, note storage 25948c2ecf20Sopenharmony_ci * does not actually alias the related block-data-window 25958c2ecf20Sopenharmony_ci * regions) 25968c2ecf20Sopenharmony_ci */ 25978c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 25988c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 25998c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 26008c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 26018c2ecf20Sopenharmony_ci spa->range_index = 11+1; 26028c2ecf20Sopenharmony_ci spa->address = t->spa_set_dma[2]; 26038c2ecf20Sopenharmony_ci spa->length = SPA0_SIZE; 26048c2ecf20Sopenharmony_ci offset += spa->header.length; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci /* spa12 (bdw for dcr4) dimm4 */ 26078c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 26088c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 26098c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 26108c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); 26118c2ecf20Sopenharmony_ci spa->range_index = 12+1; 26128c2ecf20Sopenharmony_ci spa->address = t->dimm_dma[4]; 26138c2ecf20Sopenharmony_ci spa->length = DIMM_SIZE; 26148c2ecf20Sopenharmony_ci offset += spa->header.length; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci /* mem-region14 (spa/dcr4, dimm4) */ 26178c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 26188c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 26198c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 26208c2ecf20Sopenharmony_ci memdev->device_handle = handle[4]; 26218c2ecf20Sopenharmony_ci memdev->physical_id = 4; 26228c2ecf20Sopenharmony_ci memdev->region_id = 0; 26238c2ecf20Sopenharmony_ci memdev->range_index = 10+1; 26248c2ecf20Sopenharmony_ci memdev->region_index = 8+1; 26258c2ecf20Sopenharmony_ci memdev->region_size = 0; 26268c2ecf20Sopenharmony_ci memdev->region_offset = 0; 26278c2ecf20Sopenharmony_ci memdev->address = 0; 26288c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 26298c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 26308c2ecf20Sopenharmony_ci offset += memdev->header.length; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* mem-region15 (spa11, dimm4) */ 26338c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 26348c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 26358c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 26368c2ecf20Sopenharmony_ci memdev->device_handle = handle[4]; 26378c2ecf20Sopenharmony_ci memdev->physical_id = 4; 26388c2ecf20Sopenharmony_ci memdev->region_id = 0; 26398c2ecf20Sopenharmony_ci memdev->range_index = 11+1; 26408c2ecf20Sopenharmony_ci memdev->region_index = 9+1; 26418c2ecf20Sopenharmony_ci memdev->region_size = SPA0_SIZE; 26428c2ecf20Sopenharmony_ci memdev->region_offset = (1ULL << 48); 26438c2ecf20Sopenharmony_ci memdev->address = 0; 26448c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 26458c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 26468c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; 26478c2ecf20Sopenharmony_ci offset += memdev->header.length; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci /* mem-region16 (spa/bdw4, dimm4) */ 26508c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 26518c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 26528c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 26538c2ecf20Sopenharmony_ci memdev->device_handle = handle[4]; 26548c2ecf20Sopenharmony_ci memdev->physical_id = 4; 26558c2ecf20Sopenharmony_ci memdev->region_id = 0; 26568c2ecf20Sopenharmony_ci memdev->range_index = 12+1; 26578c2ecf20Sopenharmony_ci memdev->region_index = 8+1; 26588c2ecf20Sopenharmony_ci memdev->region_size = 0; 26598c2ecf20Sopenharmony_ci memdev->region_offset = 0; 26608c2ecf20Sopenharmony_ci memdev->address = 0; 26618c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 26628c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 26638c2ecf20Sopenharmony_ci offset += memdev->header.length; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci /* flush3 (dimm4) */ 26668c2ecf20Sopenharmony_ci flush = nfit_buf + offset; 26678c2ecf20Sopenharmony_ci flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; 26688c2ecf20Sopenharmony_ci flush->header.length = flush_hint_size; 26698c2ecf20Sopenharmony_ci flush->device_handle = handle[4]; 26708c2ecf20Sopenharmony_ci flush->hint_count = NUM_HINTS; 26718c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HINTS; i++) 26728c2ecf20Sopenharmony_ci flush->hint_address[i] = t->flush_dma[4] 26738c2ecf20Sopenharmony_ci + i * sizeof(u64); 26748c2ecf20Sopenharmony_ci offset += flush->header.length; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci /* sanity check to make sure we've filled the buffer */ 26778c2ecf20Sopenharmony_ci WARN_ON(offset != t->nfit_size); 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci t->nfit_filled = offset; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], 26838c2ecf20Sopenharmony_ci SPA0_SIZE); 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci acpi_desc = &t->acpi_desc; 26868c2ecf20Sopenharmony_ci set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); 26878c2ecf20Sopenharmony_ci set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); 26888c2ecf20Sopenharmony_ci set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); 26898c2ecf20Sopenharmony_ci set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); 26908c2ecf20Sopenharmony_ci set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); 26918c2ecf20Sopenharmony_ci set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); 26928c2ecf20Sopenharmony_ci set_bit(ND_INTEL_SMART_INJECT, &acpi_desc->dimm_cmd_force_en); 26938c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); 26948c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); 26958c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); 26968c2ecf20Sopenharmony_ci set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); 26978c2ecf20Sopenharmony_ci set_bit(ND_CMD_CALL, &acpi_desc->bus_cmd_force_en); 26988c2ecf20Sopenharmony_ci set_bit(NFIT_CMD_TRANSLATE_SPA, &acpi_desc->bus_dsm_mask); 26998c2ecf20Sopenharmony_ci set_bit(NFIT_CMD_ARS_INJECT_SET, &acpi_desc->bus_dsm_mask); 27008c2ecf20Sopenharmony_ci set_bit(NFIT_CMD_ARS_INJECT_CLEAR, &acpi_desc->bus_dsm_mask); 27018c2ecf20Sopenharmony_ci set_bit(NFIT_CMD_ARS_INJECT_GET, &acpi_desc->bus_dsm_mask); 27028c2ecf20Sopenharmony_ci set_bit(ND_INTEL_FW_GET_INFO, &acpi_desc->dimm_cmd_force_en); 27038c2ecf20Sopenharmony_ci set_bit(ND_INTEL_FW_START_UPDATE, &acpi_desc->dimm_cmd_force_en); 27048c2ecf20Sopenharmony_ci set_bit(ND_INTEL_FW_SEND_DATA, &acpi_desc->dimm_cmd_force_en); 27058c2ecf20Sopenharmony_ci set_bit(ND_INTEL_FW_FINISH_UPDATE, &acpi_desc->dimm_cmd_force_en); 27068c2ecf20Sopenharmony_ci set_bit(ND_INTEL_FW_FINISH_QUERY, &acpi_desc->dimm_cmd_force_en); 27078c2ecf20Sopenharmony_ci set_bit(ND_INTEL_ENABLE_LSS_STATUS, &acpi_desc->dimm_cmd_force_en); 27088c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_GET_SECURITY_STATE, 27098c2ecf20Sopenharmony_ci &acpi_desc->dimm_cmd_force_en); 27108c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_SET_PASSPHRASE, &acpi_desc->dimm_cmd_force_en); 27118c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, 27128c2ecf20Sopenharmony_ci &acpi_desc->dimm_cmd_force_en); 27138c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_UNLOCK_UNIT, &acpi_desc->dimm_cmd_force_en); 27148c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_FREEZE_LOCK, &acpi_desc->dimm_cmd_force_en); 27158c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_SECURE_ERASE, &acpi_desc->dimm_cmd_force_en); 27168c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_OVERWRITE, &acpi_desc->dimm_cmd_force_en); 27178c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &acpi_desc->dimm_cmd_force_en); 27188c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_SET_MASTER_PASSPHRASE, 27198c2ecf20Sopenharmony_ci &acpi_desc->dimm_cmd_force_en); 27208c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_MASTER_SECURE_ERASE, 27218c2ecf20Sopenharmony_ci &acpi_desc->dimm_cmd_force_en); 27228c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO, &acpi_desc->dimm_cmd_force_en); 27238c2ecf20Sopenharmony_ci set_bit(NVDIMM_INTEL_FW_ACTIVATE_ARM, &acpi_desc->dimm_cmd_force_en); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci acpi_mask = &acpi_desc->family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL]; 27268c2ecf20Sopenharmony_ci set_bit(NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO, acpi_mask); 27278c2ecf20Sopenharmony_ci set_bit(NVDIMM_BUS_INTEL_FW_ACTIVATE, acpi_mask); 27288c2ecf20Sopenharmony_ci} 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_cistatic void nfit_test1_setup(struct nfit_test *t) 27318c2ecf20Sopenharmony_ci{ 27328c2ecf20Sopenharmony_ci size_t offset; 27338c2ecf20Sopenharmony_ci void *nfit_buf = t->nfit_buf; 27348c2ecf20Sopenharmony_ci struct acpi_nfit_memory_map *memdev; 27358c2ecf20Sopenharmony_ci struct acpi_nfit_control_region *dcr; 27368c2ecf20Sopenharmony_ci struct acpi_nfit_system_address *spa; 27378c2ecf20Sopenharmony_ci struct acpi_nfit_desc *acpi_desc; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci offset = 0; 27408c2ecf20Sopenharmony_ci /* spa0 (flat range with no bdw aliasing) */ 27418c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 27428c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 27438c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 27448c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); 27458c2ecf20Sopenharmony_ci spa->range_index = 0+1; 27468c2ecf20Sopenharmony_ci spa->address = t->spa_set_dma[0]; 27478c2ecf20Sopenharmony_ci spa->length = SPA2_SIZE; 27488c2ecf20Sopenharmony_ci offset += spa->header.length; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci /* virtual cd region */ 27518c2ecf20Sopenharmony_ci spa = nfit_buf + offset; 27528c2ecf20Sopenharmony_ci spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; 27538c2ecf20Sopenharmony_ci spa->header.length = sizeof(*spa); 27548c2ecf20Sopenharmony_ci memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); 27558c2ecf20Sopenharmony_ci spa->range_index = 0; 27568c2ecf20Sopenharmony_ci spa->address = t->spa_set_dma[1]; 27578c2ecf20Sopenharmony_ci spa->length = SPA_VCD_SIZE; 27588c2ecf20Sopenharmony_ci offset += spa->header.length; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci /* mem-region0 (spa0, dimm0) */ 27618c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 27628c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 27638c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 27648c2ecf20Sopenharmony_ci memdev->device_handle = handle[5]; 27658c2ecf20Sopenharmony_ci memdev->physical_id = 0; 27668c2ecf20Sopenharmony_ci memdev->region_id = 0; 27678c2ecf20Sopenharmony_ci memdev->range_index = 0+1; 27688c2ecf20Sopenharmony_ci memdev->region_index = 0+1; 27698c2ecf20Sopenharmony_ci memdev->region_size = SPA2_SIZE; 27708c2ecf20Sopenharmony_ci memdev->region_offset = 0; 27718c2ecf20Sopenharmony_ci memdev->address = 0; 27728c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 27738c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 27748c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED 27758c2ecf20Sopenharmony_ci | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED 27768c2ecf20Sopenharmony_ci | ACPI_NFIT_MEM_NOT_ARMED; 27778c2ecf20Sopenharmony_ci offset += memdev->header.length; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci /* dcr-descriptor0 */ 27808c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 27818c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 27828c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 27838c2ecf20Sopenharmony_ci window_size); 27848c2ecf20Sopenharmony_ci dcr->region_index = 0+1; 27858c2ecf20Sopenharmony_ci dcr_common_init(dcr); 27868c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[5]; 27878c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTE; 27888c2ecf20Sopenharmony_ci dcr->windows = 0; 27898c2ecf20Sopenharmony_ci offset += dcr->header.length; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci memdev = nfit_buf + offset; 27928c2ecf20Sopenharmony_ci memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; 27938c2ecf20Sopenharmony_ci memdev->header.length = sizeof(*memdev); 27948c2ecf20Sopenharmony_ci memdev->device_handle = handle[6]; 27958c2ecf20Sopenharmony_ci memdev->physical_id = 0; 27968c2ecf20Sopenharmony_ci memdev->region_id = 0; 27978c2ecf20Sopenharmony_ci memdev->range_index = 0; 27988c2ecf20Sopenharmony_ci memdev->region_index = 0+2; 27998c2ecf20Sopenharmony_ci memdev->region_size = SPA2_SIZE; 28008c2ecf20Sopenharmony_ci memdev->region_offset = 0; 28018c2ecf20Sopenharmony_ci memdev->address = 0; 28028c2ecf20Sopenharmony_ci memdev->interleave_index = 0; 28038c2ecf20Sopenharmony_ci memdev->interleave_ways = 1; 28048c2ecf20Sopenharmony_ci memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; 28058c2ecf20Sopenharmony_ci offset += memdev->header.length; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci /* dcr-descriptor1 */ 28088c2ecf20Sopenharmony_ci dcr = nfit_buf + offset; 28098c2ecf20Sopenharmony_ci dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; 28108c2ecf20Sopenharmony_ci dcr->header.length = offsetof(struct acpi_nfit_control_region, 28118c2ecf20Sopenharmony_ci window_size); 28128c2ecf20Sopenharmony_ci dcr->region_index = 0+2; 28138c2ecf20Sopenharmony_ci dcr_common_init(dcr); 28148c2ecf20Sopenharmony_ci dcr->serial_number = ~handle[6]; 28158c2ecf20Sopenharmony_ci dcr->code = NFIT_FIC_BYTE; 28168c2ecf20Sopenharmony_ci dcr->windows = 0; 28178c2ecf20Sopenharmony_ci offset += dcr->header.length; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci /* sanity check to make sure we've filled the buffer */ 28208c2ecf20Sopenharmony_ci WARN_ON(offset != t->nfit_size); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci t->nfit_filled = offset; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], 28258c2ecf20Sopenharmony_ci SPA2_SIZE); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci acpi_desc = &t->acpi_desc; 28288c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); 28298c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); 28308c2ecf20Sopenharmony_ci set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); 28318c2ecf20Sopenharmony_ci set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); 28328c2ecf20Sopenharmony_ci set_bit(ND_INTEL_ENABLE_LSS_STATUS, &acpi_desc->dimm_cmd_force_en); 28338c2ecf20Sopenharmony_ci set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); 28348c2ecf20Sopenharmony_ci set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); 28358c2ecf20Sopenharmony_ci set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_cistatic int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, 28398c2ecf20Sopenharmony_ci void *iobuf, u64 len, int rw) 28408c2ecf20Sopenharmony_ci{ 28418c2ecf20Sopenharmony_ci struct nfit_blk *nfit_blk = ndbr->blk_provider_data; 28428c2ecf20Sopenharmony_ci struct nfit_blk_mmio *mmio = &nfit_blk->mmio[BDW]; 28438c2ecf20Sopenharmony_ci struct nd_region *nd_region = &ndbr->nd_region; 28448c2ecf20Sopenharmony_ci unsigned int lane; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci lane = nd_region_acquire_lane(nd_region); 28478c2ecf20Sopenharmony_ci if (rw) 28488c2ecf20Sopenharmony_ci memcpy(mmio->addr.base + dpa, iobuf, len); 28498c2ecf20Sopenharmony_ci else { 28508c2ecf20Sopenharmony_ci memcpy(iobuf, mmio->addr.base + dpa, len); 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci /* give us some some coverage of the arch_invalidate_pmem() API */ 28538c2ecf20Sopenharmony_ci arch_invalidate_pmem(mmio->addr.base + dpa, len); 28548c2ecf20Sopenharmony_ci } 28558c2ecf20Sopenharmony_ci nd_region_release_lane(nd_region, lane); 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci return 0; 28588c2ecf20Sopenharmony_ci} 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_cistatic unsigned long nfit_ctl_handle; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ciunion acpi_object *result; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_cistatic union acpi_object *nfit_test_evaluate_dsm(acpi_handle handle, 28658c2ecf20Sopenharmony_ci const guid_t *guid, u64 rev, u64 func, union acpi_object *argv4) 28668c2ecf20Sopenharmony_ci{ 28678c2ecf20Sopenharmony_ci if (handle != &nfit_ctl_handle) 28688c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci return result; 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_cistatic int setup_result(void *buf, size_t size) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci result = kmalloc(sizeof(union acpi_object) + size, GFP_KERNEL); 28768c2ecf20Sopenharmony_ci if (!result) 28778c2ecf20Sopenharmony_ci return -ENOMEM; 28788c2ecf20Sopenharmony_ci result->package.type = ACPI_TYPE_BUFFER, 28798c2ecf20Sopenharmony_ci result->buffer.pointer = (void *) (result + 1); 28808c2ecf20Sopenharmony_ci result->buffer.length = size; 28818c2ecf20Sopenharmony_ci memcpy(result->buffer.pointer, buf, size); 28828c2ecf20Sopenharmony_ci memset(buf, 0, size); 28838c2ecf20Sopenharmony_ci return 0; 28848c2ecf20Sopenharmony_ci} 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_cistatic int nfit_ctl_test(struct device *dev) 28878c2ecf20Sopenharmony_ci{ 28888c2ecf20Sopenharmony_ci int rc, cmd_rc; 28898c2ecf20Sopenharmony_ci struct nvdimm *nvdimm; 28908c2ecf20Sopenharmony_ci struct acpi_device *adev; 28918c2ecf20Sopenharmony_ci struct nfit_mem *nfit_mem; 28928c2ecf20Sopenharmony_ci struct nd_ars_record *record; 28938c2ecf20Sopenharmony_ci struct acpi_nfit_desc *acpi_desc; 28948c2ecf20Sopenharmony_ci const u64 test_val = 0x0123456789abcdefULL; 28958c2ecf20Sopenharmony_ci unsigned long mask, cmd_size, offset; 28968c2ecf20Sopenharmony_ci struct nfit_ctl_test_cmd { 28978c2ecf20Sopenharmony_ci struct nd_cmd_pkg pkg; 28988c2ecf20Sopenharmony_ci union { 28998c2ecf20Sopenharmony_ci struct nd_cmd_get_config_size cfg_size; 29008c2ecf20Sopenharmony_ci struct nd_cmd_clear_error clear_err; 29018c2ecf20Sopenharmony_ci struct nd_cmd_ars_status ars_stat; 29028c2ecf20Sopenharmony_ci struct nd_cmd_ars_cap ars_cap; 29038c2ecf20Sopenharmony_ci struct nd_intel_bus_fw_activate_businfo fwa_info; 29048c2ecf20Sopenharmony_ci char buf[sizeof(struct nd_cmd_ars_status) 29058c2ecf20Sopenharmony_ci + sizeof(struct nd_ars_record)]; 29068c2ecf20Sopenharmony_ci }; 29078c2ecf20Sopenharmony_ci } cmd; 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); 29108c2ecf20Sopenharmony_ci if (!adev) 29118c2ecf20Sopenharmony_ci return -ENOMEM; 29128c2ecf20Sopenharmony_ci *adev = (struct acpi_device) { 29138c2ecf20Sopenharmony_ci .handle = &nfit_ctl_handle, 29148c2ecf20Sopenharmony_ci .dev = { 29158c2ecf20Sopenharmony_ci .init_name = "test-adev", 29168c2ecf20Sopenharmony_ci }, 29178c2ecf20Sopenharmony_ci }; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL); 29208c2ecf20Sopenharmony_ci if (!acpi_desc) 29218c2ecf20Sopenharmony_ci return -ENOMEM; 29228c2ecf20Sopenharmony_ci *acpi_desc = (struct acpi_nfit_desc) { 29238c2ecf20Sopenharmony_ci .nd_desc = { 29248c2ecf20Sopenharmony_ci .cmd_mask = 1UL << ND_CMD_ARS_CAP 29258c2ecf20Sopenharmony_ci | 1UL << ND_CMD_ARS_START 29268c2ecf20Sopenharmony_ci | 1UL << ND_CMD_ARS_STATUS 29278c2ecf20Sopenharmony_ci | 1UL << ND_CMD_CLEAR_ERROR 29288c2ecf20Sopenharmony_ci | 1UL << ND_CMD_CALL, 29298c2ecf20Sopenharmony_ci .module = THIS_MODULE, 29308c2ecf20Sopenharmony_ci .provider_name = "ACPI.NFIT", 29318c2ecf20Sopenharmony_ci .ndctl = acpi_nfit_ctl, 29328c2ecf20Sopenharmony_ci .bus_family_mask = 1UL << NVDIMM_BUS_FAMILY_NFIT 29338c2ecf20Sopenharmony_ci | 1UL << NVDIMM_BUS_FAMILY_INTEL, 29348c2ecf20Sopenharmony_ci }, 29358c2ecf20Sopenharmony_ci .bus_dsm_mask = 1UL << NFIT_CMD_TRANSLATE_SPA 29368c2ecf20Sopenharmony_ci | 1UL << NFIT_CMD_ARS_INJECT_SET 29378c2ecf20Sopenharmony_ci | 1UL << NFIT_CMD_ARS_INJECT_CLEAR 29388c2ecf20Sopenharmony_ci | 1UL << NFIT_CMD_ARS_INJECT_GET, 29398c2ecf20Sopenharmony_ci .family_dsm_mask[NVDIMM_BUS_FAMILY_INTEL] = 29408c2ecf20Sopenharmony_ci NVDIMM_BUS_INTEL_FW_ACTIVATE_CMDMASK, 29418c2ecf20Sopenharmony_ci .dev = &adev->dev, 29428c2ecf20Sopenharmony_ci }; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci nfit_mem = devm_kzalloc(dev, sizeof(*nfit_mem), GFP_KERNEL); 29458c2ecf20Sopenharmony_ci if (!nfit_mem) 29468c2ecf20Sopenharmony_ci return -ENOMEM; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci mask = 1UL << ND_CMD_SMART | 1UL << ND_CMD_SMART_THRESHOLD 29498c2ecf20Sopenharmony_ci | 1UL << ND_CMD_DIMM_FLAGS | 1UL << ND_CMD_GET_CONFIG_SIZE 29508c2ecf20Sopenharmony_ci | 1UL << ND_CMD_GET_CONFIG_DATA | 1UL << ND_CMD_SET_CONFIG_DATA 29518c2ecf20Sopenharmony_ci | 1UL << ND_CMD_VENDOR; 29528c2ecf20Sopenharmony_ci *nfit_mem = (struct nfit_mem) { 29538c2ecf20Sopenharmony_ci .adev = adev, 29548c2ecf20Sopenharmony_ci .family = NVDIMM_FAMILY_INTEL, 29558c2ecf20Sopenharmony_ci .dsm_mask = mask, 29568c2ecf20Sopenharmony_ci }; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci nvdimm = devm_kzalloc(dev, sizeof(*nvdimm), GFP_KERNEL); 29598c2ecf20Sopenharmony_ci if (!nvdimm) 29608c2ecf20Sopenharmony_ci return -ENOMEM; 29618c2ecf20Sopenharmony_ci *nvdimm = (struct nvdimm) { 29628c2ecf20Sopenharmony_ci .provider_data = nfit_mem, 29638c2ecf20Sopenharmony_ci .cmd_mask = mask, 29648c2ecf20Sopenharmony_ci .dev = { 29658c2ecf20Sopenharmony_ci .init_name = "test-dimm", 29668c2ecf20Sopenharmony_ci }, 29678c2ecf20Sopenharmony_ci }; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci /* basic checkout of a typical 'get config size' command */ 29718c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.cfg_size); 29728c2ecf20Sopenharmony_ci cmd.cfg_size = (struct nd_cmd_get_config_size) { 29738c2ecf20Sopenharmony_ci .status = 0, 29748c2ecf20Sopenharmony_ci .config_size = SZ_128K, 29758c2ecf20Sopenharmony_ci .max_xfer = SZ_4K, 29768c2ecf20Sopenharmony_ci }; 29778c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 29788c2ecf20Sopenharmony_ci if (rc) 29798c2ecf20Sopenharmony_ci return rc; 29808c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, nvdimm, ND_CMD_GET_CONFIG_SIZE, 29818c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc || cmd.cfg_size.status != 0 29848c2ecf20Sopenharmony_ci || cmd.cfg_size.config_size != SZ_128K 29858c2ecf20Sopenharmony_ci || cmd.cfg_size.max_xfer != SZ_4K) { 29868c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 29878c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 29888c2ecf20Sopenharmony_ci return -EIO; 29898c2ecf20Sopenharmony_ci } 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci /* test ars_status with zero output */ 29938c2ecf20Sopenharmony_ci cmd_size = offsetof(struct nd_cmd_ars_status, address); 29948c2ecf20Sopenharmony_ci cmd.ars_stat = (struct nd_cmd_ars_status) { 29958c2ecf20Sopenharmony_ci .out_length = 0, 29968c2ecf20Sopenharmony_ci }; 29978c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 29988c2ecf20Sopenharmony_ci if (rc) 29998c2ecf20Sopenharmony_ci return rc; 30008c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS, 30018c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc) { 30048c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 30058c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 30068c2ecf20Sopenharmony_ci return -EIO; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci /* test ars_cap with benign extended status */ 30118c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.ars_cap); 30128c2ecf20Sopenharmony_ci cmd.ars_cap = (struct nd_cmd_ars_cap) { 30138c2ecf20Sopenharmony_ci .status = ND_ARS_PERSISTENT << 16, 30148c2ecf20Sopenharmony_ci }; 30158c2ecf20Sopenharmony_ci offset = offsetof(struct nd_cmd_ars_cap, status); 30168c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf + offset, cmd_size - offset); 30178c2ecf20Sopenharmony_ci if (rc) 30188c2ecf20Sopenharmony_ci return rc; 30198c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_CAP, 30208c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc) { 30238c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 30248c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 30258c2ecf20Sopenharmony_ci return -EIO; 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci /* test ars_status with 'status' trimmed from 'out_length' */ 30308c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.ars_stat) + sizeof(struct nd_ars_record); 30318c2ecf20Sopenharmony_ci cmd.ars_stat = (struct nd_cmd_ars_status) { 30328c2ecf20Sopenharmony_ci .out_length = cmd_size - 4, 30338c2ecf20Sopenharmony_ci }; 30348c2ecf20Sopenharmony_ci record = &cmd.ars_stat.records[0]; 30358c2ecf20Sopenharmony_ci *record = (struct nd_ars_record) { 30368c2ecf20Sopenharmony_ci .length = test_val, 30378c2ecf20Sopenharmony_ci }; 30388c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 30398c2ecf20Sopenharmony_ci if (rc) 30408c2ecf20Sopenharmony_ci return rc; 30418c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS, 30428c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc || record->length != test_val) { 30458c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 30468c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 30478c2ecf20Sopenharmony_ci return -EIO; 30488c2ecf20Sopenharmony_ci } 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci /* test ars_status with 'Output (Size)' including 'status' */ 30528c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.ars_stat) + sizeof(struct nd_ars_record); 30538c2ecf20Sopenharmony_ci cmd.ars_stat = (struct nd_cmd_ars_status) { 30548c2ecf20Sopenharmony_ci .out_length = cmd_size, 30558c2ecf20Sopenharmony_ci }; 30568c2ecf20Sopenharmony_ci record = &cmd.ars_stat.records[0]; 30578c2ecf20Sopenharmony_ci *record = (struct nd_ars_record) { 30588c2ecf20Sopenharmony_ci .length = test_val, 30598c2ecf20Sopenharmony_ci }; 30608c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 30618c2ecf20Sopenharmony_ci if (rc) 30628c2ecf20Sopenharmony_ci return rc; 30638c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS, 30648c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc || record->length != test_val) { 30678c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 30688c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 30698c2ecf20Sopenharmony_ci return -EIO; 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci /* test extended status for get_config_size results in failure */ 30748c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.cfg_size); 30758c2ecf20Sopenharmony_ci cmd.cfg_size = (struct nd_cmd_get_config_size) { 30768c2ecf20Sopenharmony_ci .status = 1 << 16, 30778c2ecf20Sopenharmony_ci }; 30788c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 30798c2ecf20Sopenharmony_ci if (rc) 30808c2ecf20Sopenharmony_ci return rc; 30818c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, nvdimm, ND_CMD_GET_CONFIG_SIZE, 30828c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc >= 0) { 30858c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 30868c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 30878c2ecf20Sopenharmony_ci return -EIO; 30888c2ecf20Sopenharmony_ci } 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* test clear error */ 30918c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.clear_err); 30928c2ecf20Sopenharmony_ci cmd.clear_err = (struct nd_cmd_clear_error) { 30938c2ecf20Sopenharmony_ci .length = 512, 30948c2ecf20Sopenharmony_ci .cleared = 512, 30958c2ecf20Sopenharmony_ci }; 30968c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 30978c2ecf20Sopenharmony_ci if (rc) 30988c2ecf20Sopenharmony_ci return rc; 30998c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_CLEAR_ERROR, 31008c2ecf20Sopenharmony_ci cmd.buf, cmd_size, &cmd_rc); 31018c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc) { 31028c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 31038c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 31048c2ecf20Sopenharmony_ci return -EIO; 31058c2ecf20Sopenharmony_ci } 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci /* test firmware activate bus info */ 31088c2ecf20Sopenharmony_ci cmd_size = sizeof(cmd.fwa_info); 31098c2ecf20Sopenharmony_ci cmd = (struct nfit_ctl_test_cmd) { 31108c2ecf20Sopenharmony_ci .pkg = { 31118c2ecf20Sopenharmony_ci .nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO, 31128c2ecf20Sopenharmony_ci .nd_family = NVDIMM_BUS_FAMILY_INTEL, 31138c2ecf20Sopenharmony_ci .nd_size_out = cmd_size, 31148c2ecf20Sopenharmony_ci .nd_fw_size = cmd_size, 31158c2ecf20Sopenharmony_ci }, 31168c2ecf20Sopenharmony_ci .fwa_info = { 31178c2ecf20Sopenharmony_ci .state = ND_INTEL_FWA_IDLE, 31188c2ecf20Sopenharmony_ci .capability = ND_INTEL_BUS_FWA_CAP_FWQUIESCE 31198c2ecf20Sopenharmony_ci | ND_INTEL_BUS_FWA_CAP_OSQUIESCE, 31208c2ecf20Sopenharmony_ci .activate_tmo = 1, 31218c2ecf20Sopenharmony_ci .cpu_quiesce_tmo = 1, 31228c2ecf20Sopenharmony_ci .io_quiesce_tmo = 1, 31238c2ecf20Sopenharmony_ci .max_quiesce_tmo = 1, 31248c2ecf20Sopenharmony_ci }, 31258c2ecf20Sopenharmony_ci }; 31268c2ecf20Sopenharmony_ci rc = setup_result(cmd.buf, cmd_size); 31278c2ecf20Sopenharmony_ci if (rc) 31288c2ecf20Sopenharmony_ci return rc; 31298c2ecf20Sopenharmony_ci rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_CALL, 31308c2ecf20Sopenharmony_ci &cmd, sizeof(cmd.pkg) + cmd_size, &cmd_rc); 31318c2ecf20Sopenharmony_ci if (rc < 0 || cmd_rc) { 31328c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n", 31338c2ecf20Sopenharmony_ci __func__, __LINE__, rc, cmd_rc); 31348c2ecf20Sopenharmony_ci return -EIO; 31358c2ecf20Sopenharmony_ci } 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci return 0; 31388c2ecf20Sopenharmony_ci} 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_cistatic int nfit_test_probe(struct platform_device *pdev) 31418c2ecf20Sopenharmony_ci{ 31428c2ecf20Sopenharmony_ci struct nvdimm_bus_descriptor *nd_desc; 31438c2ecf20Sopenharmony_ci struct acpi_nfit_desc *acpi_desc; 31448c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 31458c2ecf20Sopenharmony_ci struct nfit_test *nfit_test; 31468c2ecf20Sopenharmony_ci struct nfit_mem *nfit_mem; 31478c2ecf20Sopenharmony_ci union acpi_object *obj; 31488c2ecf20Sopenharmony_ci int rc; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (strcmp(dev_name(&pdev->dev), "nfit_test.0") == 0) { 31518c2ecf20Sopenharmony_ci rc = nfit_ctl_test(&pdev->dev); 31528c2ecf20Sopenharmony_ci if (rc) 31538c2ecf20Sopenharmony_ci return rc; 31548c2ecf20Sopenharmony_ci } 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci nfit_test = to_nfit_test(&pdev->dev); 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci /* common alloc */ 31598c2ecf20Sopenharmony_ci if (nfit_test->num_dcr) { 31608c2ecf20Sopenharmony_ci int num = nfit_test->num_dcr; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci nfit_test->dimm = devm_kcalloc(dev, num, sizeof(void *), 31638c2ecf20Sopenharmony_ci GFP_KERNEL); 31648c2ecf20Sopenharmony_ci nfit_test->dimm_dma = devm_kcalloc(dev, num, sizeof(dma_addr_t), 31658c2ecf20Sopenharmony_ci GFP_KERNEL); 31668c2ecf20Sopenharmony_ci nfit_test->flush = devm_kcalloc(dev, num, sizeof(void *), 31678c2ecf20Sopenharmony_ci GFP_KERNEL); 31688c2ecf20Sopenharmony_ci nfit_test->flush_dma = devm_kcalloc(dev, num, sizeof(dma_addr_t), 31698c2ecf20Sopenharmony_ci GFP_KERNEL); 31708c2ecf20Sopenharmony_ci nfit_test->label = devm_kcalloc(dev, num, sizeof(void *), 31718c2ecf20Sopenharmony_ci GFP_KERNEL); 31728c2ecf20Sopenharmony_ci nfit_test->label_dma = devm_kcalloc(dev, num, 31738c2ecf20Sopenharmony_ci sizeof(dma_addr_t), GFP_KERNEL); 31748c2ecf20Sopenharmony_ci nfit_test->dcr = devm_kcalloc(dev, num, 31758c2ecf20Sopenharmony_ci sizeof(struct nfit_test_dcr *), GFP_KERNEL); 31768c2ecf20Sopenharmony_ci nfit_test->dcr_dma = devm_kcalloc(dev, num, 31778c2ecf20Sopenharmony_ci sizeof(dma_addr_t), GFP_KERNEL); 31788c2ecf20Sopenharmony_ci nfit_test->smart = devm_kcalloc(dev, num, 31798c2ecf20Sopenharmony_ci sizeof(struct nd_intel_smart), GFP_KERNEL); 31808c2ecf20Sopenharmony_ci nfit_test->smart_threshold = devm_kcalloc(dev, num, 31818c2ecf20Sopenharmony_ci sizeof(struct nd_intel_smart_threshold), 31828c2ecf20Sopenharmony_ci GFP_KERNEL); 31838c2ecf20Sopenharmony_ci nfit_test->fw = devm_kcalloc(dev, num, 31848c2ecf20Sopenharmony_ci sizeof(struct nfit_test_fw), GFP_KERNEL); 31858c2ecf20Sopenharmony_ci if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label 31868c2ecf20Sopenharmony_ci && nfit_test->label_dma && nfit_test->dcr 31878c2ecf20Sopenharmony_ci && nfit_test->dcr_dma && nfit_test->flush 31888c2ecf20Sopenharmony_ci && nfit_test->flush_dma 31898c2ecf20Sopenharmony_ci && nfit_test->fw) 31908c2ecf20Sopenharmony_ci /* pass */; 31918c2ecf20Sopenharmony_ci else 31928c2ecf20Sopenharmony_ci return -ENOMEM; 31938c2ecf20Sopenharmony_ci } 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci if (nfit_test->num_pm) { 31968c2ecf20Sopenharmony_ci int num = nfit_test->num_pm; 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci nfit_test->spa_set = devm_kcalloc(dev, num, sizeof(void *), 31998c2ecf20Sopenharmony_ci GFP_KERNEL); 32008c2ecf20Sopenharmony_ci nfit_test->spa_set_dma = devm_kcalloc(dev, num, 32018c2ecf20Sopenharmony_ci sizeof(dma_addr_t), GFP_KERNEL); 32028c2ecf20Sopenharmony_ci if (nfit_test->spa_set && nfit_test->spa_set_dma) 32038c2ecf20Sopenharmony_ci /* pass */; 32048c2ecf20Sopenharmony_ci else 32058c2ecf20Sopenharmony_ci return -ENOMEM; 32068c2ecf20Sopenharmony_ci } 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci /* per-nfit specific alloc */ 32098c2ecf20Sopenharmony_ci if (nfit_test->alloc(nfit_test)) 32108c2ecf20Sopenharmony_ci return -ENOMEM; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci nfit_test->setup(nfit_test); 32138c2ecf20Sopenharmony_ci acpi_desc = &nfit_test->acpi_desc; 32148c2ecf20Sopenharmony_ci acpi_nfit_desc_init(acpi_desc, &pdev->dev); 32158c2ecf20Sopenharmony_ci acpi_desc->blk_do_io = nfit_test_blk_do_io; 32168c2ecf20Sopenharmony_ci nd_desc = &acpi_desc->nd_desc; 32178c2ecf20Sopenharmony_ci nd_desc->provider_name = NULL; 32188c2ecf20Sopenharmony_ci nd_desc->module = THIS_MODULE; 32198c2ecf20Sopenharmony_ci nd_desc->ndctl = nfit_test_ctl; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, 32228c2ecf20Sopenharmony_ci nfit_test->nfit_filled); 32238c2ecf20Sopenharmony_ci if (rc) 32248c2ecf20Sopenharmony_ci return rc; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci rc = devm_add_action_or_reset(&pdev->dev, acpi_nfit_shutdown, acpi_desc); 32278c2ecf20Sopenharmony_ci if (rc) 32288c2ecf20Sopenharmony_ci return rc; 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci if (nfit_test->setup != nfit_test0_setup) 32318c2ecf20Sopenharmony_ci return 0; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci nfit_test->setup_hotplug = 1; 32348c2ecf20Sopenharmony_ci nfit_test->setup(nfit_test); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci obj = kzalloc(sizeof(*obj), GFP_KERNEL); 32378c2ecf20Sopenharmony_ci if (!obj) 32388c2ecf20Sopenharmony_ci return -ENOMEM; 32398c2ecf20Sopenharmony_ci obj->type = ACPI_TYPE_BUFFER; 32408c2ecf20Sopenharmony_ci obj->buffer.length = nfit_test->nfit_size; 32418c2ecf20Sopenharmony_ci obj->buffer.pointer = nfit_test->nfit_buf; 32428c2ecf20Sopenharmony_ci *(nfit_test->_fit) = obj; 32438c2ecf20Sopenharmony_ci __acpi_nfit_notify(&pdev->dev, nfit_test, 0x80); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci /* associate dimm devices with nfit_mem data for notification testing */ 32468c2ecf20Sopenharmony_ci mutex_lock(&acpi_desc->init_mutex); 32478c2ecf20Sopenharmony_ci list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { 32488c2ecf20Sopenharmony_ci u32 nfit_handle = __to_nfit_memdev(nfit_mem)->device_handle; 32498c2ecf20Sopenharmony_ci int i; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(handle); i++) 32528c2ecf20Sopenharmony_ci if (nfit_handle == handle[i]) 32538c2ecf20Sopenharmony_ci dev_set_drvdata(nfit_test->dimm_dev[i], 32548c2ecf20Sopenharmony_ci nfit_mem); 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci mutex_unlock(&acpi_desc->init_mutex); 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci return 0; 32598c2ecf20Sopenharmony_ci} 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_cistatic int nfit_test_remove(struct platform_device *pdev) 32628c2ecf20Sopenharmony_ci{ 32638c2ecf20Sopenharmony_ci return 0; 32648c2ecf20Sopenharmony_ci} 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_cistatic void nfit_test_release(struct device *dev) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci struct nfit_test *nfit_test = to_nfit_test(dev); 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci kfree(nfit_test); 32718c2ecf20Sopenharmony_ci} 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_cistatic const struct platform_device_id nfit_test_id[] = { 32748c2ecf20Sopenharmony_ci { KBUILD_MODNAME }, 32758c2ecf20Sopenharmony_ci { }, 32768c2ecf20Sopenharmony_ci}; 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic struct platform_driver nfit_test_driver = { 32798c2ecf20Sopenharmony_ci .probe = nfit_test_probe, 32808c2ecf20Sopenharmony_ci .remove = nfit_test_remove, 32818c2ecf20Sopenharmony_ci .driver = { 32828c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 32838c2ecf20Sopenharmony_ci }, 32848c2ecf20Sopenharmony_ci .id_table = nfit_test_id, 32858c2ecf20Sopenharmony_ci}; 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_cistatic char copy_mc_buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_cienum INJECT { 32908c2ecf20Sopenharmony_ci INJECT_NONE, 32918c2ecf20Sopenharmony_ci INJECT_SRC, 32928c2ecf20Sopenharmony_ci INJECT_DST, 32938c2ecf20Sopenharmony_ci}; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_cistatic void copy_mc_test_init(char *dst, char *src, size_t size) 32968c2ecf20Sopenharmony_ci{ 32978c2ecf20Sopenharmony_ci size_t i; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci memset(dst, 0xff, size); 33008c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 33018c2ecf20Sopenharmony_ci src[i] = (char) i; 33028c2ecf20Sopenharmony_ci} 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_cistatic bool copy_mc_test_validate(unsigned char *dst, unsigned char *src, 33058c2ecf20Sopenharmony_ci size_t size, unsigned long rem) 33068c2ecf20Sopenharmony_ci{ 33078c2ecf20Sopenharmony_ci size_t i; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci for (i = 0; i < size - rem; i++) 33108c2ecf20Sopenharmony_ci if (dst[i] != (unsigned char) i) { 33118c2ecf20Sopenharmony_ci pr_info_once("%s:%d: offset: %zd got: %#x expect: %#x\n", 33128c2ecf20Sopenharmony_ci __func__, __LINE__, i, dst[i], 33138c2ecf20Sopenharmony_ci (unsigned char) i); 33148c2ecf20Sopenharmony_ci return false; 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci for (i = size - rem; i < size; i++) 33178c2ecf20Sopenharmony_ci if (dst[i] != 0xffU) { 33188c2ecf20Sopenharmony_ci pr_info_once("%s:%d: offset: %zd got: %#x expect: 0xff\n", 33198c2ecf20Sopenharmony_ci __func__, __LINE__, i, dst[i]); 33208c2ecf20Sopenharmony_ci return false; 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci return true; 33238c2ecf20Sopenharmony_ci} 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_civoid copy_mc_test(void) 33268c2ecf20Sopenharmony_ci{ 33278c2ecf20Sopenharmony_ci char *inject_desc[] = { "none", "source", "destination" }; 33288c2ecf20Sopenharmony_ci enum INJECT inj; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_COPY_MC_TEST)) { 33318c2ecf20Sopenharmony_ci pr_info("%s: run...\n", __func__); 33328c2ecf20Sopenharmony_ci } else { 33338c2ecf20Sopenharmony_ci pr_info("%s: disabled, skip.\n", __func__); 33348c2ecf20Sopenharmony_ci return; 33358c2ecf20Sopenharmony_ci } 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci for (inj = INJECT_NONE; inj <= INJECT_DST; inj++) { 33388c2ecf20Sopenharmony_ci int i; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci pr_info("%s: inject: %s\n", __func__, inject_desc[inj]); 33418c2ecf20Sopenharmony_ci for (i = 0; i < 512; i++) { 33428c2ecf20Sopenharmony_ci unsigned long expect, rem; 33438c2ecf20Sopenharmony_ci void *src, *dst; 33448c2ecf20Sopenharmony_ci bool valid; 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci switch (inj) { 33478c2ecf20Sopenharmony_ci case INJECT_NONE: 33488c2ecf20Sopenharmony_ci copy_mc_inject_src(NULL); 33498c2ecf20Sopenharmony_ci copy_mc_inject_dst(NULL); 33508c2ecf20Sopenharmony_ci dst = ©_mc_buf[2048]; 33518c2ecf20Sopenharmony_ci src = ©_mc_buf[1024 - i]; 33528c2ecf20Sopenharmony_ci expect = 0; 33538c2ecf20Sopenharmony_ci break; 33548c2ecf20Sopenharmony_ci case INJECT_SRC: 33558c2ecf20Sopenharmony_ci copy_mc_inject_src(©_mc_buf[1024]); 33568c2ecf20Sopenharmony_ci copy_mc_inject_dst(NULL); 33578c2ecf20Sopenharmony_ci dst = ©_mc_buf[2048]; 33588c2ecf20Sopenharmony_ci src = ©_mc_buf[1024 - i]; 33598c2ecf20Sopenharmony_ci expect = 512 - i; 33608c2ecf20Sopenharmony_ci break; 33618c2ecf20Sopenharmony_ci case INJECT_DST: 33628c2ecf20Sopenharmony_ci copy_mc_inject_src(NULL); 33638c2ecf20Sopenharmony_ci copy_mc_inject_dst(©_mc_buf[2048]); 33648c2ecf20Sopenharmony_ci dst = ©_mc_buf[2048 - i]; 33658c2ecf20Sopenharmony_ci src = ©_mc_buf[1024]; 33668c2ecf20Sopenharmony_ci expect = 512 - i; 33678c2ecf20Sopenharmony_ci break; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci copy_mc_test_init(dst, src, 512); 33718c2ecf20Sopenharmony_ci rem = copy_mc_fragile(dst, src, 512); 33728c2ecf20Sopenharmony_ci valid = copy_mc_test_validate(dst, src, 512, expect); 33738c2ecf20Sopenharmony_ci if (rem == expect && valid) 33748c2ecf20Sopenharmony_ci continue; 33758c2ecf20Sopenharmony_ci pr_info("%s: copy(%#lx, %#lx, %d) off: %d rem: %ld %s expect: %ld\n", 33768c2ecf20Sopenharmony_ci __func__, 33778c2ecf20Sopenharmony_ci ((unsigned long) dst) & ~PAGE_MASK, 33788c2ecf20Sopenharmony_ci ((unsigned long ) src) & ~PAGE_MASK, 33798c2ecf20Sopenharmony_ci 512, i, rem, valid ? "valid" : "bad", 33808c2ecf20Sopenharmony_ci expect); 33818c2ecf20Sopenharmony_ci } 33828c2ecf20Sopenharmony_ci } 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ci copy_mc_inject_src(NULL); 33858c2ecf20Sopenharmony_ci copy_mc_inject_dst(NULL); 33868c2ecf20Sopenharmony_ci} 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_cistatic __init int nfit_test_init(void) 33898c2ecf20Sopenharmony_ci{ 33908c2ecf20Sopenharmony_ci int rc, i; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci pmem_test(); 33938c2ecf20Sopenharmony_ci libnvdimm_test(); 33948c2ecf20Sopenharmony_ci acpi_nfit_test(); 33958c2ecf20Sopenharmony_ci device_dax_test(); 33968c2ecf20Sopenharmony_ci copy_mc_test(); 33978c2ecf20Sopenharmony_ci dax_pmem_test(); 33988c2ecf20Sopenharmony_ci dax_pmem_core_test(); 33998c2ecf20Sopenharmony_ci#ifdef CONFIG_DEV_DAX_PMEM_COMPAT 34008c2ecf20Sopenharmony_ci dax_pmem_compat_test(); 34018c2ecf20Sopenharmony_ci#endif 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm); 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci nfit_wq = create_singlethread_workqueue("nfit"); 34068c2ecf20Sopenharmony_ci if (!nfit_wq) 34078c2ecf20Sopenharmony_ci return -ENOMEM; 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm"); 34108c2ecf20Sopenharmony_ci if (IS_ERR(nfit_test_dimm)) { 34118c2ecf20Sopenharmony_ci rc = PTR_ERR(nfit_test_dimm); 34128c2ecf20Sopenharmony_ci goto err_register; 34138c2ecf20Sopenharmony_ci } 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci nfit_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE); 34168c2ecf20Sopenharmony_ci if (!nfit_pool) { 34178c2ecf20Sopenharmony_ci rc = -ENOMEM; 34188c2ecf20Sopenharmony_ci goto err_register; 34198c2ecf20Sopenharmony_ci } 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci if (gen_pool_add(nfit_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) { 34228c2ecf20Sopenharmony_ci rc = -ENOMEM; 34238c2ecf20Sopenharmony_ci goto err_register; 34248c2ecf20Sopenharmony_ci } 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci for (i = 0; i < NUM_NFITS; i++) { 34278c2ecf20Sopenharmony_ci struct nfit_test *nfit_test; 34288c2ecf20Sopenharmony_ci struct platform_device *pdev; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci nfit_test = kzalloc(sizeof(*nfit_test), GFP_KERNEL); 34318c2ecf20Sopenharmony_ci if (!nfit_test) { 34328c2ecf20Sopenharmony_ci rc = -ENOMEM; 34338c2ecf20Sopenharmony_ci goto err_register; 34348c2ecf20Sopenharmony_ci } 34358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfit_test->resources); 34368c2ecf20Sopenharmony_ci badrange_init(&nfit_test->badrange); 34378c2ecf20Sopenharmony_ci switch (i) { 34388c2ecf20Sopenharmony_ci case 0: 34398c2ecf20Sopenharmony_ci nfit_test->num_pm = NUM_PM; 34408c2ecf20Sopenharmony_ci nfit_test->dcr_idx = 0; 34418c2ecf20Sopenharmony_ci nfit_test->num_dcr = NUM_DCR; 34428c2ecf20Sopenharmony_ci nfit_test->alloc = nfit_test0_alloc; 34438c2ecf20Sopenharmony_ci nfit_test->setup = nfit_test0_setup; 34448c2ecf20Sopenharmony_ci break; 34458c2ecf20Sopenharmony_ci case 1: 34468c2ecf20Sopenharmony_ci nfit_test->num_pm = 2; 34478c2ecf20Sopenharmony_ci nfit_test->dcr_idx = NUM_DCR; 34488c2ecf20Sopenharmony_ci nfit_test->num_dcr = 2; 34498c2ecf20Sopenharmony_ci nfit_test->alloc = nfit_test1_alloc; 34508c2ecf20Sopenharmony_ci nfit_test->setup = nfit_test1_setup; 34518c2ecf20Sopenharmony_ci break; 34528c2ecf20Sopenharmony_ci default: 34538c2ecf20Sopenharmony_ci rc = -EINVAL; 34548c2ecf20Sopenharmony_ci goto err_register; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci pdev = &nfit_test->pdev; 34578c2ecf20Sopenharmony_ci pdev->name = KBUILD_MODNAME; 34588c2ecf20Sopenharmony_ci pdev->id = i; 34598c2ecf20Sopenharmony_ci pdev->dev.release = nfit_test_release; 34608c2ecf20Sopenharmony_ci rc = platform_device_register(pdev); 34618c2ecf20Sopenharmony_ci if (rc) { 34628c2ecf20Sopenharmony_ci put_device(&pdev->dev); 34638c2ecf20Sopenharmony_ci goto err_register; 34648c2ecf20Sopenharmony_ci } 34658c2ecf20Sopenharmony_ci get_device(&pdev->dev); 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci rc = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 34688c2ecf20Sopenharmony_ci if (rc) 34698c2ecf20Sopenharmony_ci goto err_register; 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci instances[i] = nfit_test; 34728c2ecf20Sopenharmony_ci INIT_WORK(&nfit_test->work, uc_error_notify); 34738c2ecf20Sopenharmony_ci } 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci rc = platform_driver_register(&nfit_test_driver); 34768c2ecf20Sopenharmony_ci if (rc) 34778c2ecf20Sopenharmony_ci goto err_register; 34788c2ecf20Sopenharmony_ci return 0; 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci err_register: 34818c2ecf20Sopenharmony_ci if (nfit_pool) 34828c2ecf20Sopenharmony_ci gen_pool_destroy(nfit_pool); 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_ci destroy_workqueue(nfit_wq); 34858c2ecf20Sopenharmony_ci for (i = 0; i < NUM_NFITS; i++) 34868c2ecf20Sopenharmony_ci if (instances[i]) 34878c2ecf20Sopenharmony_ci platform_device_unregister(&instances[i]->pdev); 34888c2ecf20Sopenharmony_ci nfit_test_teardown(); 34898c2ecf20Sopenharmony_ci for (i = 0; i < NUM_NFITS; i++) 34908c2ecf20Sopenharmony_ci if (instances[i]) 34918c2ecf20Sopenharmony_ci put_device(&instances[i]->pdev.dev); 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci return rc; 34948c2ecf20Sopenharmony_ci} 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_cistatic __exit void nfit_test_exit(void) 34978c2ecf20Sopenharmony_ci{ 34988c2ecf20Sopenharmony_ci int i; 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci flush_workqueue(nfit_wq); 35018c2ecf20Sopenharmony_ci destroy_workqueue(nfit_wq); 35028c2ecf20Sopenharmony_ci for (i = 0; i < NUM_NFITS; i++) 35038c2ecf20Sopenharmony_ci platform_device_unregister(&instances[i]->pdev); 35048c2ecf20Sopenharmony_ci platform_driver_unregister(&nfit_test_driver); 35058c2ecf20Sopenharmony_ci nfit_test_teardown(); 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci gen_pool_destroy(nfit_pool); 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci for (i = 0; i < NUM_NFITS; i++) 35108c2ecf20Sopenharmony_ci put_device(&instances[i]->pdev.dev); 35118c2ecf20Sopenharmony_ci class_destroy(nfit_test_dimm); 35128c2ecf20Sopenharmony_ci} 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_cimodule_init(nfit_test_init); 35158c2ecf20Sopenharmony_cimodule_exit(nfit_test_exit); 35168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 35178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 3518