#include <uapi/asm/papr-indices.h>
 #include "papr-rtas-common.h"
 
+/*
+ * Function-specific return values for ibm,set-dynamic-indicator and
+ * ibm,get-dynamic-sensor-state RTAS calls.
+ * PAPR+ v2.13 7.3.18 and 7.3.19.
+ */
+#define RTAS_IBM_DYNAMIC_INDICE_NO_INDICATOR   -3
+
 /**
  * struct rtas_get_indices_params - Parameters (in and out) for
  *                                      ibm,get-indices.
        return fd;
 }
 
+/*
+ * Create work area with the input parameters. This function is used
+ * for both ibm,set-dynamic-indicator and ibm,get-dynamic-sensor-state
+ * RTAS Calls.
+ */
+static struct rtas_work_area *
+papr_dynamic_indice_buf_from_user(struct papr_indices_io_block __user *ubuf,
+                               struct papr_indices_io_block *kbuf)
+{
+       struct rtas_work_area *work_area;
+       u32 length;
+       __be32 len_be;
+
+       if (copy_from_user(kbuf, ubuf, sizeof(*kbuf)))
+               return ERR_PTR(-EFAULT);
+
+
+       if (!string_is_terminated(kbuf->dynamic_param.location_code_str,
+                       ARRAY_SIZE(kbuf->dynamic_param.location_code_str)))
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * The input data in the work area should be as follows:
+        * - 32-bit integer length of the location code string,
+        *   including NULL.
+        * - Location code string, NULL terminated, identifying the
+        *   token (sensor or indicator).
+        * PAPR 2.13 - R1–7.3.18–5 ibm,set-dynamic-indicator
+        *           - R1–7.3.19–5 ibm,get-dynamic-sensor-state
+        */
+       /*
+        * Length that user space passed should also include NULL
+        * terminator.
+        */
+       length = strlen(kbuf->dynamic_param.location_code_str) + 1;
+       if (length > LOC_CODE_SIZE)
+               return ERR_PTR(-EINVAL);
+
+       len_be = cpu_to_be32(length);
+
+       work_area = rtas_work_area_alloc(LOC_CODE_SIZE + sizeof(u32));
+       memcpy(rtas_work_area_raw_buf(work_area), &len_be, sizeof(u32));
+       memcpy((rtas_work_area_raw_buf(work_area) + sizeof(u32)),
+                       &kbuf->dynamic_param.location_code_str, length);
+
+       return work_area;
+}
+
+/**
+ * papr_dynamic_indicator_ioc_set - ibm,set-dynamic-indicator RTAS Call
+ * PAPR 2.13 7.3.18
+ *
+ * @ubuf: Input parameters to RTAS call such as indicator token and
+ *        new state.
+ *
+ * Returns success or -errno.
+ */
+static long papr_dynamic_indicator_ioc_set(struct papr_indices_io_block __user *ubuf)
+{
+       struct papr_indices_io_block kbuf;
+       struct rtas_work_area *work_area;
+       s32 fwrc, token, ret;
+
+       token = rtas_function_token(RTAS_FN_IBM_SET_DYNAMIC_INDICATOR);
+       if (token == RTAS_UNKNOWN_SERVICE)
+               return -ENOENT;
+
+       mutex_lock(&rtas_ibm_set_dynamic_indicator_lock);
+       work_area = papr_dynamic_indice_buf_from_user(ubuf, &kbuf);
+       if (IS_ERR(work_area)) {
+               ret = PTR_ERR(work_area);
+               goto out;
+       }
+
+       do {
+               fwrc = rtas_call(token, 3, 1, NULL,
+                               kbuf.dynamic_param.token,
+                               kbuf.dynamic_param.state,
+                               rtas_work_area_phys(work_area));
+       } while (rtas_busy_delay(fwrc));
+
+       rtas_work_area_free(work_area);
+
+       switch (fwrc) {
+       case RTAS_SUCCESS:
+               ret = 0;
+               break;
+       case RTAS_IBM_DYNAMIC_INDICE_NO_INDICATOR:      /* No such indicator */
+               ret = -EOPNOTSUPP;
+               break;
+       default:
+               pr_err("unexpected ibm,set-dynamic-indicator result %d\n",
+                       fwrc);
+               fallthrough;
+       case RTAS_HARDWARE_ERROR:       /* Hardware/platform error */
+               ret = -EIO;
+               break;
+       }
+
+out:
+       mutex_unlock(&rtas_ibm_set_dynamic_indicator_lock);
+       return ret;
+}
+
 /*
  * Top-level ioctl handler for /dev/papr-indices.
  */
        case PAPR_INDICES_IOC_GET:
                ret = papr_indices_create_handle(argp);
                break;
+       case PAPR_DYNAMIC_INDICATOR_IOC_SET:
+               if (filp->f_mode & FMODE_WRITE)
+                       ret = papr_dynamic_indicator_ioc_set(argp);
+               else
+                       ret = -EBADF;
+               break;
        default:
                ret = -ENOIOCTLCMD;
                break;
        if (!rtas_function_implemented(RTAS_FN_IBM_GET_INDICES))
                return -ENODEV;
 
+       if (!rtas_function_implemented(RTAS_FN_IBM_SET_DYNAMIC_INDICATOR))
+               return -ENODEV;
+
        return misc_register(&papr_indices_dev);
 }
 machine_device_initcall(pseries, papr_indices_init);