From c04d24ab02084b65546c4a169eb11d847a105b89 Mon Sep 17 00:00:00 2001 From: Jonathan Helman Date: Thu, 20 Apr 2017 18:15:44 -0700 Subject: [PATCH] sparc64: add ccb kill and info to DAX driver 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 Reviewed-by: Sanath Kumar Reviewed-by: Rob Gardner Signed-off-by: Allen Pais --- Documentation/sparc/dax.txt | 11 ++ arch/sparc/dax/dax_impl.h | 12 ++ arch/sparc/dax/dax_main.c | 237 +++++++++++++++++++++++++++- arch/sparc/dax/dax_misc.c | 16 +- arch/sparc/dax/sys_dax.h | 47 ++++++ arch/sparc/include/asm/hypervisor.h | 57 +++++-- arch/sparc/kernel/hvcalls.S | 34 ++++ arch/sparc/kernel/sparc_ksyms_64.c | 2 + 8 files changed, 395 insertions(+), 21 deletions(-) diff --git a/Documentation/sparc/dax.txt b/Documentation/sparc/dax.txt index 5d7f4fbb039e..877d37f36c9e 100644 --- a/Documentation/sparc/dax.txt +++ b/Documentation/sparc/dax.txt @@ -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 diff --git a/arch/sparc/dax/dax_impl.h b/arch/sparc/dax/dax_impl.h index 94bdf6339fd0..894dfe5ea359 100644 --- a/arch/sparc/dax/dax_impl.h +++ b/arch/sparc/dax/dax_impl.h @@ -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); diff --git a/arch/sparc/dax/dax_main.c b/arch/sparc/dax/dax_main.c index 7901f20a409a..98e046a21114 100644 --- a/arch/sparc/dax/dax_main.c +++ b/arch/sparc/dax/dax_main.c @@ -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; } } diff --git a/arch/sparc/dax/dax_misc.c b/arch/sparc/dax/dax_misc.c index 9a533463ac57..6291a45b23e8 100644 --- a/arch/sparc/dax/dax_misc.c +++ b/arch/sparc/dax/dax_misc.c @@ -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; } diff --git a/arch/sparc/dax/sys_dax.h b/arch/sparc/dax/sys_dax.h index 7e0cd36711cf..fb0a985237c8 100644 --- a/arch/sparc/dax/sys_dax.h +++ b/arch/sparc/dax/sys_dax.h @@ -25,6 +25,17 @@ #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 @@ -51,6 +62,10 @@ #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) diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h index b4996e679c0b..86e357d18f10 100644 --- a/arch/sparc/include/asm/hypervisor.h +++ b/arch/sparc/include/asm/hypervisor.h @@ -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 diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S index a5388b4b79df..8061686c69df 100644 --- a/arch/sparc/kernel/hvcalls.S +++ b/arch/sparc/kernel/hvcalls.S @@ -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 diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c index 9a623004efe6..26f9c7a8a812 100644 --- a/arch/sparc/kernel/sparc_ksyms_64.c +++ b/arch/sparc/kernel/sparc_ksyms_64.c @@ -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); -- 2.50.1