The new hcall named H_SCM_UNBIND_ALL has been introduce that can unbind all the memory drc memory-blocks assigned to an lpar. This is more efficient than using H_SCM_UNBIND_MEM as currently we don't support partial unbind of drc memory-blocks.
Hence this patch proposes following changes to drc_pmem_unbind(): * Update drc_pmem_unbind() to replace hcall H_SCM_UNBIND_MEM to H_SCM_UNBIND_ALL. * Update drc_pmem_unbind() to handles cases when PHYP asks the guest kernel to wait for specific amount of time before retrying the hcall via the 'LONG_BUSY' return value. In case it takes more than 1 second to unbind the memory log a warning. * Ensure appropriate error code is returned back from the function in case of an error. Signed-off-by: Vaibhav Jain <vaib...@linux.ibm.com> --- arch/powerpc/include/asm/hvcall.h | 2 +- arch/powerpc/platforms/pseries/papr_scm.c | 37 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 463c63a9fcf1..bb56fa0f976c 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -302,7 +302,7 @@ #define H_SCM_UNBIND_MEM 0x3F0 #define H_SCM_QUERY_BLOCK_MEM_BINDING 0x3F4 #define H_SCM_QUERY_LOGICAL_MEM_BINDING 0x3F8 -#define H_SCM_MEM_QUERY 0x3FC +#define H_SCM_UNBIND_ALL 0x3FC #define H_SCM_BLOCK_CLEAR 0x400 #define MAX_HCALL_OPCODE H_SCM_BLOCK_CLEAR diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 96c53b23e58f..d790e4e4ffb3 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -11,11 +11,16 @@ #include <linux/sched.h> #include <linux/libnvdimm.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/plpar_wrappers.h> #define BIND_ANY_ADDR (~0ul) +/* Scope args for H_SCM_UNBIND_ALL */ +#define H_UNBIND_SCOPE_ALL (0x1) +#define H_UNBIND_SCOPE_DRC (0x2) + #define PAPR_SCM_DIMM_CMD_MASK \ ((1ul << ND_CMD_GET_CONFIG_SIZE) | \ (1ul << ND_CMD_GET_CONFIG_DATA) | \ @@ -78,21 +83,43 @@ static int drc_pmem_unbind(struct papr_scm_priv *p) { unsigned long ret[PLPAR_HCALL_BUFSIZE]; uint64_t rc, token; + unsigned long starttime; token = 0; - /* NB: unbind has the same retry requirements mentioned above */ + dev_dbg(&p->pdev->dev, "unbind drc %x\n", p->drc_index); + + /* NB: unbind_all has the same retry requirements as drc_pmem_bind() */ + starttime = HZ; do { - rc = plpar_hcall(H_SCM_UNBIND_MEM, ret, p->drc_index, - p->bound_addr, p->blocks, token); + /* If this is taking too much time then log warning */ + if (jiffies_to_msecs(HZ - starttime) > 1000) { + dev_warn(&p->pdev->dev, + "unbind taking > 1s to complete\n"); + starttime = HZ; + } + + /* Unbind of all SCM resources associated with drcIndex */ + rc = plpar_hcall(H_SCM_UNBIND_ALL, ret, H_UNBIND_SCOPE_DRC, + p->drc_index, token); token = ret[0]; - cond_resched(); + + /* Check if we are stalled for some time */ + if (H_IS_LONG_BUSY(rc)) { + msleep(get_longbusy_msecs(rc)); + rc = H_BUSY; + token = 0; + + } else if (rc == H_BUSY) { + cond_resched(); + } + } while (rc == H_BUSY); if (rc) dev_err(&p->pdev->dev, "unbind error: %lld\n", rc); - return !!rc; + return rc == H_SUCCESS ? 0 : -ENXIO; } static int papr_scm_meta_get(struct papr_scm_priv *p, -- 2.21.0