]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sparc64: add ccb kill and info to DAX driver
authorJonathan Helman <jonathan.helman@oracle.com>
Fri, 21 Apr 2017 01:15:44 +0000 (18:15 -0700)
committerAllen Pais <allen.pais@oracle.com>
Fri, 16 Jun 2017 08:47:20 +0000 (14:17 +0530)
Orabug: 25825763

Introduces ccb kill and ccb info into the DAX driver. An application may
use this functionality by specifying a completion area offset, which
corresponds to a submitted CCB, to the new ccb_kill and ccb_info ioctls.
This completion area offset is converted into an RA and provided to the
hypervisor. Additionally, this patch adds the functionality to kill ccbs
which timeout within the driver (during cleanup or any of the dax/fw
functionality tests).

Signed-off-by: Jonathan Helman <jonathan.helman@oracle.com>
Reviewed-by: Sanath Kumar <sanath.s.kumar@oracle.com>
Reviewed-by: Rob Gardner <rob.gardner@oracle.com>
Signed-off-by: Allen Pais <allen.pais@oracle.com>
Documentation/sparc/dax.txt
arch/sparc/dax/dax_impl.h
arch/sparc/dax/dax_main.c
arch/sparc/dax/dax_misc.c
arch/sparc/dax/sys_dax.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/sparc_ksyms_64.c

index 5d7f4fbb039edbbc1334d12dceed43fbf05c0a85..877d37f36c9e353e4ead3bb3e82aa6217e24c9cd 100644 (file)
@@ -106,6 +106,17 @@ There also several ioctl functions related to performance counters, but these
 are not described in this document. Access to the performance counters is
 provided via a utility program included with the DAX user libraries.
 
+CCB_KILL
+
+Kills a CCB during execution. The CCB is guaranteed to not continue executing
+once this call returns successfully.
+
+CCB_INFO
+
+Retrieves info about an executing CCB. Note that some Hypervisors might return
+notfound when the CCB is in inprogress state. To ensure a CCB in the notfound
+state will never be executed, CCB_KILL must be called on that CCB.
+
 MMAP
 
 The mmap() function provides two different services depending on
index 94bdf6339fd054ea05e19da55b55c90a826195f9..894dfe5ea35947ec52de40ae7c4995c8c8720440 100644 (file)
@@ -54,6 +54,7 @@ extern const struct vm_operations_struct dax_vm_ops;
 #define DAX_DBG_FLG_LIST       0x08
 #define DAX_DBG_FLG_PERF       0x10
 #define DAX_DBG_FLG_NOMAP      0x20
+#define DAX_DBG_FLG_KILL_INFO  0x40
 #define        DAX_DBG_FLG_ALL         0xff
 
 #define dax_info(fmt, ...)     pr_info("%s: " fmt "\n", __func__,\
@@ -88,6 +89,10 @@ extern const struct vm_operations_struct dax_vm_ops;
                                        if (dax_debug & DAX_DBG_FLG_NOMAP)\
                                                dax_info(fmt, ##__VA_ARGS__);\
                                } while (0)
+#define        dax_kill_info_dbg(fmt, ...)     do {                            \
+                                       if (dax_debug & DAX_DBG_FLG_KILL_INFO)\
+                                               dax_info(fmt, ##__VA_ARGS__);\
+                               } while (0)
 
 #define DAX_VALIDATE_AT(hdr, type, label)                              \
        do {                                                            \
@@ -141,6 +146,12 @@ extern const struct vm_operations_struct dax_vm_ops;
 #define        DAX_CCB_WAIT_USEC               100
 #define        DAX_CCB_WAIT_RETRIES_MAX        10000
 
+#define        DAX_KILL_WAIT_USEC      100UL
+#define        DAX_KILL_RETRIES_MAX    10000
+
+#define        DAX_INFO_WAIT_USEC      100UL
+#define        DAX_INFO_RETRIES_MAX    2
+
 #define DAX_OUT_SIZE_FROM_CCB(sz)      ((1 + (sz)) * 64)
 #define DAX_IN_SIZE_FROM_CCB(sz)               (1 + (sz))
 
@@ -264,6 +275,7 @@ void dax_unlock_pages_ccb(struct dax_ctx *ctx, int ccb_num, union ccb *ccbp);
 void dax_prt_ccbs(union ccb *ccb, u64 len);
 bool dax_has_flow_ctl_numa(void);
 bool dax_has_ra_pgsz(void);
+int dax_ccb_kill(u64 ca, u16 *kill_res);
 long dax_perfcount_ioctl(struct file *f, unsigned int cmd, unsigned long arg);
 union ccb *dax_ccb_buffer_reserve(struct dax_ctx *ctx, size_t len,
                                  size_t *reserved);
index 7901f20a409ad526d7b90315088c8f8fe8a8f8de..98e046a211149eeab6fc4b62f7d7b9a891e50c62 100644 (file)
@@ -27,6 +27,8 @@ static int dax_ioctl_ccb_thr_init(void *, struct file *);
 static int dax_ioctl_ccb_thr_fini(struct file *f);
 static int dax_ioctl_ccb_exec(void *, struct file *);
 static int dax_ioctl_ca_dequeue(void *, struct file *f);
+static int dax_ioctl_ccb_kill(void *arg, struct file *f);
+static int dax_ioctl_ccb_info(void *arg, struct file *f);
 static int dax_validate_ca_dequeue_args(struct dax_ctx *,
                                        struct dax_ca_dequeue_arg *);
 static int dax_ccb_hv_submit(struct dax_ctx *, union ccb *, size_t,
@@ -293,6 +295,10 @@ static long dax_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                return dax_ioctl_ca_dequeue((void *)arg, f);
        case DAXIOC_CCB_EXEC:
                return dax_ioctl_ccb_exec((void *)arg, f);
+       case DAXIOC_CCB_KILL:
+               return dax_ioctl_ccb_kill((void *)arg, f);
+       case DAXIOC_CCB_INFO:
+               return dax_ioctl_ccb_info((void *)arg, f);
        case DAXIOC_VERSION:
                if (copy_to_user((void __user *)arg, &dax_version,
                                 sizeof(dax_version)))
@@ -384,6 +390,223 @@ static int dax_ioctl_ccb_thr_fini(struct file *f)
        }
 
        dax_state_destroy(f);
+       return 0;
+}
+
+int dax_ccb_kill_info_hv(u64 ca, unsigned long ret, char *ok_str)
+{
+       switch (ret) {
+       case HV_EOK:
+               dax_kill_info_dbg("HV returned HV_EOK for ca_ra 0x%llx, %s", ca,
+                                 ok_str);
+               return 0;
+
+       case HV_EBADALIGN:
+               dax_err("HV returned HV_EBADALIGN for ca_ra 0x%llx", ca);
+               return -EFAULT;
+
+       case HV_ENORADDR:
+               dax_err("HV returned HV_ENORADDR for ca_ra 0x%llx", ca);
+               return -EFAULT;
+
+       case HV_EINVAL:
+               dax_err("HV returned HV_EINVAL for ca_ra 0x%llx", ca);
+               return -EINVAL;
+
+       case HV_EWOULDBLOCK:
+               dax_err("HV returned HV_EWOULDBLOCK for ca_ra 0x%llx", ca);
+               return -EAGAIN;
+
+       case HV_ENOACCESS:
+               dax_err("HV returned HV_ENOACCESS for ca_ra 0x%llx", ca);
+               return -EPERM;
+
+       default:
+               dax_err("HV returned unknown (%ld) for ca_ra 0x%llx", ret, ca);
+               return -EIO;
+       }
+}
+
+int dax_ccb_kill(u64 ca, u16 *kill_res)
+{
+       unsigned long hv_ret;
+       char res_str[80];
+       int count;
+       int ret;
+
+       /* confirm dax drv and hv api constants the same */
+       BUILD_BUG_ON(DAX_KILL_COMPLETED != HV_DAX_KILL_COMPLETED);
+       BUILD_BUG_ON(DAX_KILL_DEQUEUED != HV_DAX_KILL_DEQUEUED);
+       BUILD_BUG_ON(DAX_KILL_KILLED != HV_DAX_KILL_KILLED);
+       BUILD_BUG_ON(DAX_KILL_NOTFOUND != HV_DAX_KILL_NOTFOUND);
+
+       for (count = 0; count < DAX_KILL_RETRIES_MAX; count++) {
+               dax_dbg("attempting kill on ca_ra 0x%llx", ca);
+               hv_ret = sun4v_dax_ccb_kill(ca, kill_res);
+
+               if (*kill_res == DAX_KILL_COMPLETED)
+                       snprintf(res_str, sizeof(res_str), "COMPLETED");
+               else if (*kill_res == DAX_KILL_DEQUEUED)
+                       snprintf(res_str, sizeof(res_str), "DEQUEUED");
+               else if (*kill_res == DAX_KILL_KILLED)
+                       snprintf(res_str, sizeof(res_str), "KILLED");
+               else if (*kill_res == DAX_KILL_NOTFOUND)
+                       snprintf(res_str, sizeof(res_str), "NOTFOUND");
+               else
+                       snprintf(res_str, sizeof(res_str), "??? (%d)",
+                                *kill_res);
+
+               ret = dax_ccb_kill_info_hv(ca, hv_ret, res_str);
+               if (ret != -EAGAIN)
+                       return ret;
+               dax_kill_info_dbg("ccb_kill count = %d", count);
+               udelay(DAX_KILL_WAIT_USEC);
+       }
+
+       return -EAGAIN;
+}
+
+static int dax_ccb_info(u64 ca, struct dax_ccb_info_arg *info)
+{
+       u16 *info_arr = &info->dax_ccb_state;
+       unsigned long hv_ret;
+       char info_str[80];
+       int count;
+       int ret;
+
+       /* confirm dax drv and hv api constants the same */
+       BUILD_BUG_ON(DAX_CCB_COMPLETED != HV_CCB_STATE_COMPLETED);
+       BUILD_BUG_ON(DAX_CCB_ENQUEUED != HV_CCB_STATE_ENQUEUED);
+       BUILD_BUG_ON(DAX_CCB_INPROGRESS != HV_CCB_STATE_INPROGRESS);
+       BUILD_BUG_ON(DAX_CCB_NOTFOUND != HV_CCB_STATE_NOTFOUND);
+
+       for (count = 0; count < DAX_INFO_RETRIES_MAX; count++) {
+               dax_dbg("attempting info on ca_ra 0x%llx", ca);
+               hv_ret = sun4v_dax_ccb_info(ca, info_arr);
+
+               if (info->dax_ccb_state == DAX_CCB_COMPLETED) {
+                       snprintf(info_str, sizeof(info_str),
+                                "ccb_state COMPLETED");
+               } else if (info->dax_ccb_state == DAX_CCB_ENQUEUED) {
+                       snprintf(info_str, sizeof(info_str),
+                                "ccb_state ENQUEUED (dax_unit %d, queue_num %d, queue_pos %d)",
+                                info->dax_inst_num, info->dax_q_num,
+                                info->dax_q_pos);
+               } else if (info->dax_ccb_state == DAX_CCB_INPROGRESS) {
+                       snprintf(info_str, sizeof(info_str),
+                                "ccb_state INPROGRESS");
+               } else if (info->dax_ccb_state == DAX_CCB_NOTFOUND) {
+                       snprintf(info_str, sizeof(info_str),
+                                "ccb_state NOTFOUND");
+               } else {
+                       snprintf(info_str, sizeof(info_str),
+                                "ccb_state ??? (%d)", info->dax_ccb_state);
+               }
+
+               ret = dax_ccb_kill_info_hv(ca, hv_ret, info_str);
+               if (ret != -EAGAIN)
+                       return ret;
+               dax_kill_info_dbg("ccb_info count = %d", count);
+               udelay(DAX_INFO_WAIT_USEC);
+       }
+
+       return -EAGAIN;
+}
+
+static int dax_ioctl_ccb_kill(void *arg, struct file *f)
+{
+       struct dax_ctx *dax_ctx = (struct dax_ctx *) f->private_data;
+       struct dax_ccb_kill_arg kill_arg;
+       int ret;
+       u64 ca;
+
+       if (dax_ctx == NULL) {
+               dax_err("CCB_INIT ioctl not previously called");
+               return -ENOENT;
+       }
+
+       if (dax_ctx->owner != current) {
+               dax_err("wrong thread");
+               return -EUSERS;
+       }
+
+       if (copy_from_user(&kill_arg, (void __user *)arg, sizeof(kill_arg))) {
+               dax_err("copy_from_user failed");
+               return -EFAULT;
+       }
+
+       dax_dbg("ca_offset=%d", kill_arg.dax_ca_offset);
+
+       if (kill_arg.dax_ca_offset >= dax_ctx->ca_buflen) {
+               dax_err("invalid dax_ca_offset (%d) >= ca_buflen (%d)",
+                       kill_arg.dax_ca_offset, dax_ctx->ca_buflen);
+               return -EINVAL;
+       }
+
+       ca = dax_ctx->ca_buf_ra + kill_arg.dax_ca_offset;
+
+       ret = dax_ccb_kill(ca, &kill_arg.dax_kill_res);
+       if (ret != 0) {
+               dax_err("dax_ccb_kill failed (ret=%d)", ret);
+               return ret;
+       }
+
+       dax_kill_info_dbg("kill succeeded on ca_offset %d",
+                         kill_arg.dax_ca_offset);
+
+       if (copy_to_user((void __user *)arg, &kill_arg, sizeof(kill_arg))) {
+               dax_err("copy_to_user failed");
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int dax_ioctl_ccb_info(void *arg, struct file *f)
+{
+       struct dax_ctx *dax_ctx = (struct dax_ctx *) f->private_data;
+       struct dax_ccb_info_arg info_arg;
+       int ret;
+       u64 ca;
+
+       if (dax_ctx == NULL) {
+               dax_err("CCB_INIT ioctl not previously called");
+               return -ENOENT;
+       }
+
+       if (dax_ctx->owner != current) {
+               dax_err("wrong thread");
+               return -EUSERS;
+       }
+
+       if (copy_from_user(&info_arg, (void __user *)arg, sizeof(info_arg))) {
+               dax_err("copy_from_user failed");
+               return -EFAULT;
+       }
+
+       dax_dbg("ca_offset=%d", info_arg.dax_ca_offset);
+
+       if (info_arg.dax_ca_offset >= dax_ctx->ca_buflen) {
+               dax_err("invalid dax_ca_offset (%d) >= ca_buflen (%d)",
+                       info_arg.dax_ca_offset, dax_ctx->ca_buflen);
+               return -EINVAL;
+       }
+
+       ca = dax_ctx->ca_buf_ra + info_arg.dax_ca_offset;
+
+       ret = dax_ccb_info(ca, &info_arg);
+       if (ret != 0) {
+               dax_err("dax_ccb_info failed (ret=%d)", ret);
+               return ret;
+       }
+
+       dax_kill_info_dbg("info succeeded on ca_offset %d",
+                         info_arg.dax_ca_offset);
+
+       if (copy_to_user((void __user *)arg, &info_arg, sizeof(info_arg))) {
+               dax_err("copy_to_user failed");
+               return -EFAULT;
+       }
 
        return 0;
 }
@@ -1062,6 +1285,9 @@ static int dax_ccb_flush_contig(struct dax_ctx *dax_ctx, int start_idx,
 static void dax_ccb_wait(struct dax_ctx *dax_ctx, int idx)
 {
        int nretries = 0;
+       u16 kill_res;
+       int ret;
+       u64 ca;
 
        dax_dbg("idx=%d", idx);
 
@@ -1069,9 +1295,16 @@ static void dax_ccb_wait(struct dax_ctx *dax_ctx, int idx)
                udelay(dax_ccb_wait_usec);
 
                if (++nretries >= dax_ccb_wait_retries_max) {
-                       dax_alert("dax_ctx (0x%p): CCB[%d] did not complete (timed out, wait usec=%d retries=%d). CCB kill will be attempted in future version",
-                               (void *)dax_ctx, idx, dax_ccb_wait_usec,
+                       dax_alert("dax_ctx (0x%p): CCB[%d] did not complete (timed out, wait usec=%d retries=%d). Killing ccb",
+                                 (void *)dax_ctx, idx, dax_ccb_wait_usec,
                                  dax_ccb_wait_retries_max);
+                       ca = dax_ctx->ca_buf_ra + NCCB_TO_CA_BYTE(idx);
+                       ret = dax_ccb_kill(ca, &kill_res);
+                       if (ret != 0)
+                               dax_alert("Killing CCB[%d] failed", idx);
+                       else
+                               dax_alert("CCB[%d] killed", idx);
+
                        return;
                }
        }
index 9a533463ac57369a570c67ed3bf84c3f65b9f7a0..6291a45b23e8b231c2f1f0c246ae8c7d5994dde1 100644 (file)
@@ -82,7 +82,13 @@ static int dax_has_flow_ctl_one_node(void)
                timeout = timeout - mwait_time;
        }
        if (timeout <= 0) {
-               dax_alert("dax flow control test timed out");
+               int kill_ret;
+               u16 kill_res;
+
+               dax_alert("dax flow control test timed out, killing ccb");
+               ra = virt_to_phys(ca);
+               kill_ret = dax_ccb_kill(ra, &kill_res);
+               dax_alert("kill returned %d, kill_res %d", kill_ret, kill_res);
                ret = -EIO;
                goto done;
        }
@@ -238,7 +244,13 @@ bool dax_has_ra_pgsz(void)
                timeout = timeout - mwait_time;
        }
        if (timeout <= 0) {
-               dax_alert("dax ra_pgsz test timed out");
+               int kill_ret;
+               u16 kill_res;
+
+               dax_alert("dax ra_pgsz test timed out, killing ccb");
+               ra = virt_to_phys(ca);
+               kill_ret = dax_ccb_kill(ra, &kill_res);
+               dax_alert("kill returned %d, kill_res %d", kill_ret, kill_res);
                goto done;
        }
 
index 7e0cd36711cf2664107c2f1ead7ddc93b7340309..fb0a985237c8959a0a214f9f10fcf2df74e4892f 100644 (file)
 #define        DAX_SUBMIT_ERR_UNAVAIL                  12
 #define        DAX_SUBMIT_ERR_INTERNAL                 13
 
+/* DAXIOC_CCB_KILL dax_kill_res */
+#define        DAX_KILL_COMPLETED      0
+#define        DAX_KILL_DEQUEUED       1
+#define        DAX_KILL_KILLED         2
+#define        DAX_KILL_NOTFOUND       3
+
+/* DAXIOC_CCB_INFO dax_ccb_state */
+#define        DAX_CCB_COMPLETED       0
+#define        DAX_CCB_ENQUEUED        1
+#define        DAX_CCB_INPROGRESS      2
+#define        DAX_CCB_NOTFOUND        3
 
 #define        DAX_DEV "/dev/dax"
 #define DAX_DRIVER_VERSION 3
 #define        DAXIOC_CA_DEQUEUE       _IOWR(DAXIOC, 7, struct dax_ca_dequeue_arg)
 /* CCB execution */
 #define        DAXIOC_CCB_EXEC         _IOWR(DAXIOC, 8, struct dax_ccb_exec_arg)
+/* CCB kill */
+#define        DAXIOC_CCB_KILL         _IOWR(DAXIOC, 9, struct dax_ccb_kill_arg)
+/* CCB info */
+#define        DAXIOC_CCB_INFO         _IOWR(DAXIOC, 10, struct dax_ccb_info_arg)
 /* get driver version */
 #define DAXIOC_VERSION          _IOWR(DAXIOC, 5, long)
 
@@ -103,6 +118,38 @@ struct dax_ca_dequeue_arg {
        __u32 dcd_len_dequeued;
 };
 
+/*
+ * DAXIOC_CCB_KILL
+ * dax_ca_offset : ca offset for ccb to kill
+ * dax_kill_res : result of kill attempt
+ */
+struct dax_ccb_kill_arg {
+       __u16 dax_ca_offset;
+       __u16 dax_kill_res;
+};
+
+/*
+ * DAXIOC_CCB_INFO
+ * dax_ca_offset : ca offset for ccb to get info
+ * dax_ccb_state : ccb state
+ * dax_inst_num : dax instance number on which ccb is enqueued
+ *               (if dax_ccb_state == DAX_CCB_ENQUEUED)
+ * dax_q_num : queue number on which ccb is enqueued
+ *            (if dax_ccb_state == DAX_CCB_ENQUEUED)
+ * dax_q_pos : ccb position in queue (if dax_ccb_state == DAX_CCB_ENQUEUED)
+ *
+ * Note: it is possible for CCB_INFO to return dax_ccb_state as
+ * DAX_CCB_NOTFOUND when the CCB is still executing. In order to ensure a CCB
+ * in the NOTFOUND state will never be executed, CCB_KILL must be called on
+ * that CCB.
+ */
+struct dax_ccb_info_arg {
+       __u16 dax_ca_offset;
+       __u16 dax_ccb_state;
+       __u16 dax_inst_num;
+       __u16 dax_q_num;
+       __u16 dax_q_pos;
+};
 
 /* The number of DAX engines per node */
 #define DAX_PER_NODE           (8)
index b4996e679c0b45cba83c2634f85dde0c08935f3b..86e357d18f10609a51d8f5956b217ee2450256b6 100644 (file)
@@ -1002,37 +1002,60 @@ unsigned long sun4v_dax_ccb_submit(void *ccb, int len, long flags,
 /* dax_ccb_info()
  * TRAP:       HV_FAST_TRAP
  * FUNCTION:   HV_DAX_CCB_INFO
- * ARG0:        real address of CCB completion area
+ * ARG0:       real address of CCB completion area
  * RET0:       status (success or error code)
- * RET1         CCB state
- * RET2         queue position
+ * RET1:       info array
+ *                     - RET1[0]: CCB state
+ *                     - RET1[1]: dax unit
+ *                     - RET1[2]: queue number
+ *                     - RET1[3]: queue position
  *
- * ERRORS:     EWOULDBLOCK etc
- *             ENOTSUPPORTED   etc
- *
- * Details.
+ * ERRORS:     EOK             operation successful
+ *             EBADALIGN       address not 64B aligned
+ *             ENORADDR        RA in address not valid
+ *             EINVAL          CA not valid
+ *             EWOULDBLOCK     info not available for this CCB currently, try
+ *                             again
+ *             ENOACCESS       guest cannot use dax
  */
 
 #define HV_DAX_CCB_INFO                 0x35
-#define HV_DAX_STATE_COMPLETED      0
-#define HV_DAX_STATE_PENDING        1
-#define HV_DAX_STATE_INPROGRESS     2
-#define HV_DAX_STATE_NOTFOUND       3
+#ifndef __ASSEMBLY__
+unsigned long sun4v_dax_ccb_info(u64 ca, u16 *info_arr);
+#endif
+/* info array byte offsets, each elem is u16 (RET1) */
+#define DAX_CCB_INFO_OFFSET_CCB_STATE  0
+#define DAX_CCB_INFO_OFFSET_DAX_UNIT   2
+#define DAX_CCB_INFO_OFFSET_QUEUE_NUM  4
+#define DAX_CCB_INFO_OFFSET_QUEUE_POS  6
+
+/* CCB state (RET1[0]) */
+#define HV_CCB_STATE_COMPLETED      0
+#define HV_CCB_STATE_ENQUEUED       1
+#define HV_CCB_STATE_INPROGRESS     2
+#define HV_CCB_STATE_NOTFOUND       3
 
 /* dax_ccb_kill()
  * TRAP:       HV_FAST_TRAP
  * FUNCTION:   HV_DAX_CCB_KILL
- * ARG0:        real address of CCB completion area
+ * ARG0:       real address of CCB completion area
  * RET0:       status (success or error code)
- * RET1         CCB kill status
+ * RET1:       CCB kill status
  *
- * ERRORS:     EWOULDBLOCK etc
- *             ENOTSUPPORTED   etc
- *
- * Details.
+ * ERRORS:     EOK             operation successful
+ *             EBADALIGN       address not 64B aligned
+ *             ENORADDR        RA in address not valid
+ *             EINVAL          CA not valid
+ *             EWOULDBLOCK     kill not available for this CCB currently, try
+ *                             again
+ *             ENOACCESS       guest cannot use dax
  */
 
 #define HV_DAX_CCB_KILL                 0x36
+#ifndef __ASSEMBLY__
+unsigned long sun4v_dax_ccb_kill(u64 ca, u16 *kill_status);
+#endif
+/* CCB kill status (RET1) */
 #define HV_DAX_KILL_COMPLETED       0
 #define HV_DAX_KILL_DEQUEUED        1
 #define HV_DAX_KILL_KILLED          2
index a5388b4b79df056bc5c57c5166064291e8259aa1..8061686c69df4883436b1027343d7d6191eef895 100644 (file)
@@ -236,6 +236,40 @@ ENTRY(sun4v_dax_ccb_submit)
         stx    %o2, [%g1]
 ENDPROC(sun4v_dax_ccb_submit)
 
+       /* %o0: completion area ra for the ccb to get info
+        *
+        * returns:
+        * %o0: status
+        * %o1: CCB state
+        * %o2: position
+        * %o3: dax
+        * %o4: queue
+        */
+ENTRY(sun4v_dax_ccb_info)
+       mov     %o1, %g1
+       mov     HV_DAX_CCB_INFO, %o5
+       ta      HV_FAST_TRAP
+       sth     %o1, [%g1 + DAX_CCB_INFO_OFFSET_CCB_STATE]
+       sth     %o2, [%g1 + DAX_CCB_INFO_OFFSET_QUEUE_POS]
+       sth     %o3, [%g1 + DAX_CCB_INFO_OFFSET_DAX_UNIT]
+       retl
+        sth    %o4, [%g1 + DAX_CCB_INFO_OFFSET_QUEUE_NUM]
+ENDPROC(sun4v_dax_ccb_info)
+
+       /* %o0: completion area ra for the ccb to kill
+        *
+        * returns:
+        * %o0: status
+        * %o1: result of the kill
+        */
+ENTRY(sun4v_dax_ccb_kill)
+       mov     %o1, %g1
+       mov     HV_DAX_CCB_KILL, %o5
+       ta      HV_FAST_TRAP
+       retl
+        sth    %o1, [%g1]
+ENDPROC(sun4v_dax_ccb_kill)
+
        /* %o0: pointer to unsigned long time
         *
         * returns %o0: status
index 9a623004efe62d8742d1036f7ad29b49701a0319..26f9c7a8a812f728691e826254500d45ca0909d1 100644 (file)
@@ -39,6 +39,8 @@ EXPORT_SYMBOL(sun4v_niagara2_getperf);
 EXPORT_SYMBOL(sun4v_niagara2_setperf);
 EXPORT_SYMBOL(sun4v_mach_set_watchdog);
 EXPORT_SYMBOL(sun4v_dax_ccb_submit);
+EXPORT_SYMBOL(sun4v_dax_ccb_info);
+EXPORT_SYMBOL(sun4v_dax_ccb_kill);
 
 /* from hweight.S */
 EXPORT_SYMBOL(__arch_hweight8);