Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/papr_scm: Implement support for H_SCM_FLUSH hcall

Add support for ND_REGION_ASYNC capability if the device tree
indicates 'ibm,hcall-flush-required' property in the NVDIMM node.
Flush is done by issuing H_SCM_FLUSH hcall to the hypervisor.

If the flush request failed, the hypervisor is expected to
to reflect the problem in the subsequent nvdimm H_SCM_HEALTH call.

This patch prevents mmap of namespaces with MAP_SYNC flag if the
nvdimm requires an explicit flush[1].

References:
[1] https://github.com/avocado-framework-tests/avocado-misc-tests/blob/master/memory/ndctl.py.data/map_sync.c

Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
[mpe: Use unsigned long / long instead of uint64_t/int64_t]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/161703936121.36.7260632399582101498.stgit@e1fbed493c87

authored by

Shivaprasad G Bhat and committed by
Michael Ellerman
75b7c05e af072b1a

+55 -1
+14
Documentation/powerpc/papr_hcalls.rst
··· 275 275 Given a DRC Index collect the performance statistics for NVDIMM and copy them 276 276 to the resultBuffer. 277 277 278 + **H_SCM_FLUSH** 279 + 280 + | Input: *drcIndex, continue-token* 281 + | Out: *continue-token* 282 + | Return Value: *H_SUCCESS, H_Parameter, H_P2, H_BUSY* 283 + 284 + Given a DRC Index Flush the data to backend NVDIMM device. 285 + 286 + The hcall returns H_BUSY when the flush takes longer time and the hcall needs 287 + to be issued multiple times in order to be completely serviced. The 288 + *continue-token* from the output to be passed in the argument list of 289 + subsequent hcalls to the hypervisor until the hcall is completely serviced 290 + at which point H_SUCCESS or other error is returned by the hypervisor. 291 + 278 292 References 279 293 ========== 280 294 .. [1] "Power Architecture Platform Reference"
+2 -1
arch/powerpc/include/asm/hvcall.h
··· 315 315 #define H_SCM_HEALTH 0x400 316 316 #define H_SCM_PERFORMANCE_STATS 0x418 317 317 #define H_RPT_INVALIDATE 0x448 318 - #define MAX_HCALL_OPCODE H_RPT_INVALIDATE 318 + #define H_SCM_FLUSH 0x44C 319 + #define MAX_HCALL_OPCODE H_SCM_FLUSH 319 320 320 321 /* Scope args for H_SCM_UNBIND_ALL */ 321 322 #define H_UNBIND_SCOPE_ALL (0x1)
+39
arch/powerpc/platforms/pseries/papr_scm.c
··· 93 93 uint64_t block_size; 94 94 int metadata_size; 95 95 bool is_volatile; 96 + bool hcall_flush_required; 96 97 97 98 uint64_t bound_addr; 98 99 ··· 117 116 /* length of the stat buffer as expected by phyp */ 118 117 size_t stat_buffer_len; 119 118 }; 119 + 120 + static int papr_scm_pmem_flush(struct nd_region *nd_region, 121 + struct bio *bio __maybe_unused) 122 + { 123 + struct papr_scm_priv *p = nd_region_provider_data(nd_region); 124 + unsigned long ret_buf[PLPAR_HCALL_BUFSIZE], token = 0; 125 + long rc; 126 + 127 + dev_dbg(&p->pdev->dev, "flush drc 0x%x", p->drc_index); 128 + 129 + do { 130 + rc = plpar_hcall(H_SCM_FLUSH, ret_buf, p->drc_index, token); 131 + token = ret_buf[0]; 132 + 133 + /* Check if we are stalled for some time */ 134 + if (H_IS_LONG_BUSY(rc)) { 135 + msleep(get_longbusy_msecs(rc)); 136 + rc = H_BUSY; 137 + } else if (rc == H_BUSY) { 138 + cond_resched(); 139 + } 140 + } while (rc == H_BUSY); 141 + 142 + if (rc) { 143 + dev_err(&p->pdev->dev, "flush error: %lld", rc); 144 + rc = -EIO; 145 + } else { 146 + dev_dbg(&p->pdev->dev, "flush drc 0x%x complete", p->drc_index); 147 + } 148 + 149 + return rc; 150 + } 120 151 121 152 static LIST_HEAD(papr_nd_regions); 122 153 static DEFINE_MUTEX(papr_ndr_lock); ··· 976 943 ndr_desc.num_mappings = 1; 977 944 ndr_desc.nd_set = &p->nd_set; 978 945 946 + if (p->hcall_flush_required) { 947 + set_bit(ND_REGION_ASYNC, &ndr_desc.flags); 948 + ndr_desc.flush = papr_scm_pmem_flush; 949 + } 950 + 979 951 if (p->is_volatile) 980 952 p->region = nvdimm_volatile_region_create(p->bus, &ndr_desc); 981 953 else { ··· 1126 1088 p->block_size = block_size; 1127 1089 p->blocks = blocks; 1128 1090 p->is_volatile = !of_property_read_bool(dn, "ibm,cache-flush-required"); 1091 + p->hcall_flush_required = of_property_read_bool(dn, "ibm,hcall-flush-required"); 1129 1092 1130 1093 /* We just need to ensure that set cookies are unique across */ 1131 1094 uuid_parse(uuid_str, (uuid_t *) uuid);