xref: /OK3568_Linux_fs/kernel/drivers/sbus/char/oradax.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun /*
7*4882a593Smuzhiyun  * Oracle Data Analytics Accelerator (DAX)
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * DAX is a coprocessor which resides on the SPARC M7 (DAX1) and M8
10*4882a593Smuzhiyun  * (DAX2) processor chips, and has direct access to the CPU's L3
11*4882a593Smuzhiyun  * caches as well as physical memory. It can perform several
12*4882a593Smuzhiyun  * operations on data streams with various input and output formats.
13*4882a593Smuzhiyun  * The driver provides a transport mechanism only and has limited
14*4882a593Smuzhiyun  * knowledge of the various opcodes and data formats. A user space
15*4882a593Smuzhiyun  * library provides high level services and translates these into low
16*4882a593Smuzhiyun  * level commands which are then passed into the driver and
17*4882a593Smuzhiyun  * subsequently the hypervisor and the coprocessor.  The library is
18*4882a593Smuzhiyun  * the recommended way for applications to use the coprocessor, and
19*4882a593Smuzhiyun  * the driver interface is not intended for general use.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * See Documentation/sparc/oradax/oracle-dax.rst for more details.
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <linux/uaccess.h>
25*4882a593Smuzhiyun #include <linux/module.h>
26*4882a593Smuzhiyun #include <linux/delay.h>
27*4882a593Smuzhiyun #include <linux/cdev.h>
28*4882a593Smuzhiyun #include <linux/slab.h>
29*4882a593Smuzhiyun #include <linux/mm.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <asm/hypervisor.h>
32*4882a593Smuzhiyun #include <asm/mdesc.h>
33*4882a593Smuzhiyun #include <asm/oradax.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun MODULE_LICENSE("GPL");
36*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for Oracle Data Analytics Accelerator");
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define	DAX_DBG_FLG_BASIC	0x01
39*4882a593Smuzhiyun #define	DAX_DBG_FLG_STAT	0x02
40*4882a593Smuzhiyun #define	DAX_DBG_FLG_INFO	0x04
41*4882a593Smuzhiyun #define	DAX_DBG_FLG_ALL		0xff
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define	dax_err(fmt, ...)      pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__)
44*4882a593Smuzhiyun #define	dax_info(fmt, ...)     pr_info("%s: " fmt "\n", __func__, ##__VA_ARGS__)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define	dax_dbg(fmt, ...)	do {					\
47*4882a593Smuzhiyun 					if (dax_debug & DAX_DBG_FLG_BASIC)\
48*4882a593Smuzhiyun 						dax_info(fmt, ##__VA_ARGS__); \
49*4882a593Smuzhiyun 				} while (0)
50*4882a593Smuzhiyun #define	dax_stat_dbg(fmt, ...)	do {					\
51*4882a593Smuzhiyun 					if (dax_debug & DAX_DBG_FLG_STAT) \
52*4882a593Smuzhiyun 						dax_info(fmt, ##__VA_ARGS__); \
53*4882a593Smuzhiyun 				} while (0)
54*4882a593Smuzhiyun #define	dax_info_dbg(fmt, ...)	do { \
55*4882a593Smuzhiyun 					if (dax_debug & DAX_DBG_FLG_INFO) \
56*4882a593Smuzhiyun 						dax_info(fmt, ##__VA_ARGS__); \
57*4882a593Smuzhiyun 				} while (0)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define	DAX1_MINOR		1
60*4882a593Smuzhiyun #define	DAX1_MAJOR		1
61*4882a593Smuzhiyun #define	DAX2_MINOR		0
62*4882a593Smuzhiyun #define	DAX2_MAJOR		2
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define	DAX1_STR    "ORCL,sun4v-dax"
65*4882a593Smuzhiyun #define	DAX2_STR    "ORCL,sun4v-dax2"
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define	DAX_CA_ELEMS		(DAX_MMAP_LEN / sizeof(struct dax_cca))
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define	DAX_CCB_USEC		100
70*4882a593Smuzhiyun #define	DAX_CCB_RETRIES		10000
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* stream types */
73*4882a593Smuzhiyun enum {
74*4882a593Smuzhiyun 	OUT,
75*4882a593Smuzhiyun 	PRI,
76*4882a593Smuzhiyun 	SEC,
77*4882a593Smuzhiyun 	TBL,
78*4882a593Smuzhiyun 	NUM_STREAM_TYPES
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /* completion status */
82*4882a593Smuzhiyun #define	CCA_STAT_NOT_COMPLETED	0
83*4882a593Smuzhiyun #define	CCA_STAT_COMPLETED	1
84*4882a593Smuzhiyun #define	CCA_STAT_FAILED		2
85*4882a593Smuzhiyun #define	CCA_STAT_KILLED		3
86*4882a593Smuzhiyun #define	CCA_STAT_NOT_RUN	4
87*4882a593Smuzhiyun #define	CCA_STAT_PIPE_OUT	5
88*4882a593Smuzhiyun #define	CCA_STAT_PIPE_SRC	6
89*4882a593Smuzhiyun #define	CCA_STAT_PIPE_DST	7
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /* completion err */
92*4882a593Smuzhiyun #define	CCA_ERR_SUCCESS		0x0	/* no error */
93*4882a593Smuzhiyun #define	CCA_ERR_OVERFLOW	0x1	/* buffer overflow */
94*4882a593Smuzhiyun #define	CCA_ERR_DECODE		0x2	/* CCB decode error */
95*4882a593Smuzhiyun #define	CCA_ERR_PAGE_OVERFLOW	0x3	/* page overflow */
96*4882a593Smuzhiyun #define	CCA_ERR_KILLED		0x7	/* command was killed */
97*4882a593Smuzhiyun #define	CCA_ERR_TIMEOUT		0x8	/* Timeout */
98*4882a593Smuzhiyun #define	CCA_ERR_ADI		0x9	/* ADI error */
99*4882a593Smuzhiyun #define	CCA_ERR_DATA_FMT	0xA	/* data format error */
100*4882a593Smuzhiyun #define	CCA_ERR_OTHER_NO_RETRY	0xE	/* Other error, do not retry */
101*4882a593Smuzhiyun #define	CCA_ERR_OTHER_RETRY	0xF	/* Other error, retry */
102*4882a593Smuzhiyun #define	CCA_ERR_PARTIAL_SYMBOL	0x80	/* QP partial symbol warning */
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /* CCB address types */
105*4882a593Smuzhiyun #define	DAX_ADDR_TYPE_NONE	0
106*4882a593Smuzhiyun #define	DAX_ADDR_TYPE_VA_ALT	1	/* secondary context */
107*4882a593Smuzhiyun #define	DAX_ADDR_TYPE_RA	2	/* real address */
108*4882a593Smuzhiyun #define	DAX_ADDR_TYPE_VA	3	/* virtual address */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun /* dax_header_t opcode */
111*4882a593Smuzhiyun #define	DAX_OP_SYNC_NOP		0x0
112*4882a593Smuzhiyun #define	DAX_OP_EXTRACT		0x1
113*4882a593Smuzhiyun #define	DAX_OP_SCAN_VALUE	0x2
114*4882a593Smuzhiyun #define	DAX_OP_SCAN_RANGE	0x3
115*4882a593Smuzhiyun #define	DAX_OP_TRANSLATE	0x4
116*4882a593Smuzhiyun #define	DAX_OP_SELECT		0x5
117*4882a593Smuzhiyun #define	DAX_OP_INVERT		0x10	/* OR with translate, scan opcodes */
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun struct dax_header {
120*4882a593Smuzhiyun 	u32 ccb_version:4;	/* 31:28 CCB Version */
121*4882a593Smuzhiyun 				/* 27:24 Sync Flags */
122*4882a593Smuzhiyun 	u32 pipe:1;		/* Pipeline */
123*4882a593Smuzhiyun 	u32 longccb:1;		/* Longccb. Set for scan with lu2, lu3, lu4. */
124*4882a593Smuzhiyun 	u32 cond:1;		/* Conditional */
125*4882a593Smuzhiyun 	u32 serial:1;		/* Serial */
126*4882a593Smuzhiyun 	u32 opcode:8;		/* 23:16 Opcode */
127*4882a593Smuzhiyun 				/* 15:0 Address Type. */
128*4882a593Smuzhiyun 	u32 reserved:3;		/* 15:13 reserved */
129*4882a593Smuzhiyun 	u32 table_addr_type:2;	/* 12:11 Huffman Table Address Type */
130*4882a593Smuzhiyun 	u32 out_addr_type:3;	/* 10:8 Destination Address Type */
131*4882a593Smuzhiyun 	u32 sec_addr_type:3;	/* 7:5 Secondary Source Address Type */
132*4882a593Smuzhiyun 	u32 pri_addr_type:3;	/* 4:2 Primary Source Address Type */
133*4882a593Smuzhiyun 	u32 cca_addr_type:2;	/* 1:0 Completion Address Type */
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun struct dax_control {
137*4882a593Smuzhiyun 	u32 pri_fmt:4;		/* 31:28 Primary Input Format */
138*4882a593Smuzhiyun 	u32 pri_elem_size:5;	/* 27:23 Primary Input Element Size(less1) */
139*4882a593Smuzhiyun 	u32 pri_offset:3;	/* 22:20 Primary Input Starting Offset */
140*4882a593Smuzhiyun 	u32 sec_encoding:1;	/* 19    Secondary Input Encoding */
141*4882a593Smuzhiyun 				/*	 (must be 0 for Select) */
142*4882a593Smuzhiyun 	u32 sec_offset:3;	/* 18:16 Secondary Input Starting Offset */
143*4882a593Smuzhiyun 	u32 sec_elem_size:2;	/* 15:14 Secondary Input Element Size */
144*4882a593Smuzhiyun 				/*	 (must be 0 for Select) */
145*4882a593Smuzhiyun 	u32 out_fmt:2;		/* 13:12 Output Format */
146*4882a593Smuzhiyun 	u32 out_elem_size:2;	/* 11:10 Output Element Size */
147*4882a593Smuzhiyun 	u32 misc:10;		/* 9:0 Opcode specific info */
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun struct dax_data_access {
151*4882a593Smuzhiyun 	u64 flow_ctrl:2;	/* 63:62 Flow Control Type */
152*4882a593Smuzhiyun 	u64 pipe_target:2;	/* 61:60 Pipeline Target */
153*4882a593Smuzhiyun 	u64 out_buf_size:20;	/* 59:40 Output Buffer Size */
154*4882a593Smuzhiyun 				/*	 (cachelines less 1) */
155*4882a593Smuzhiyun 	u64 unused1:8;		/* 39:32 Reserved, Set to 0 */
156*4882a593Smuzhiyun 	u64 out_alloc:5;	/* 31:27 Output Allocation */
157*4882a593Smuzhiyun 	u64 unused2:1;		/* 26	 Reserved */
158*4882a593Smuzhiyun 	u64 pri_len_fmt:2;	/* 25:24 Input Length Format */
159*4882a593Smuzhiyun 	u64 pri_len:24;		/* 23:0  Input Element/Byte/Bit Count */
160*4882a593Smuzhiyun 				/*	 (less 1) */
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun struct dax_ccb {
164*4882a593Smuzhiyun 	struct dax_header hdr;	/* CCB Header */
165*4882a593Smuzhiyun 	struct dax_control ctrl;/* Control Word */
166*4882a593Smuzhiyun 	void *ca;		/* Completion Address */
167*4882a593Smuzhiyun 	void *pri;		/* Primary Input Address */
168*4882a593Smuzhiyun 	struct dax_data_access dac; /* Data Access Control */
169*4882a593Smuzhiyun 	void *sec;		/* Secondary Input Address */
170*4882a593Smuzhiyun 	u64 dword5;		/* depends on opcode */
171*4882a593Smuzhiyun 	void *out;		/* Output Address */
172*4882a593Smuzhiyun 	void *tbl;		/* Table Address or bitmap */
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun struct dax_cca {
176*4882a593Smuzhiyun 	u8	status;		/* user may mwait on this address */
177*4882a593Smuzhiyun 	u8	err;		/* user visible error notification */
178*4882a593Smuzhiyun 	u8	rsvd[2];	/* reserved */
179*4882a593Smuzhiyun 	u32	n_remaining;	/* for QP partial symbol warning */
180*4882a593Smuzhiyun 	u32	output_sz;	/* output in bytes */
181*4882a593Smuzhiyun 	u32	rsvd2;		/* reserved */
182*4882a593Smuzhiyun 	u64	run_cycles;	/* run time in OCND2 cycles */
183*4882a593Smuzhiyun 	u64	run_stats;	/* nothing reported in version 1.0 */
184*4882a593Smuzhiyun 	u32	n_processed;	/* number input elements */
185*4882a593Smuzhiyun 	u32	rsvd3[5];	/* reserved */
186*4882a593Smuzhiyun 	u64	retval;		/* command return value */
187*4882a593Smuzhiyun 	u64	rsvd4[8];	/* reserved */
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /* per thread CCB context */
191*4882a593Smuzhiyun struct dax_ctx {
192*4882a593Smuzhiyun 	struct dax_ccb		*ccb_buf;
193*4882a593Smuzhiyun 	u64			ccb_buf_ra;	/* cached RA of ccb_buf  */
194*4882a593Smuzhiyun 	struct dax_cca		*ca_buf;
195*4882a593Smuzhiyun 	u64			ca_buf_ra;	/* cached RA of ca_buf   */
196*4882a593Smuzhiyun 	struct page		*pages[DAX_CA_ELEMS][NUM_STREAM_TYPES];
197*4882a593Smuzhiyun 						/* array of locked pages */
198*4882a593Smuzhiyun 	struct task_struct	*owner;		/* thread that owns ctx  */
199*4882a593Smuzhiyun 	struct task_struct	*client;	/* requesting thread     */
200*4882a593Smuzhiyun 	union ccb_result	result;
201*4882a593Smuzhiyun 	u32			ccb_count;
202*4882a593Smuzhiyun 	u32			fail_count;
203*4882a593Smuzhiyun };
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun /* driver public entry points */
206*4882a593Smuzhiyun static int dax_open(struct inode *inode, struct file *file);
207*4882a593Smuzhiyun static ssize_t dax_read(struct file *filp, char __user *buf,
208*4882a593Smuzhiyun 			size_t count, loff_t *ppos);
209*4882a593Smuzhiyun static ssize_t dax_write(struct file *filp, const char __user *buf,
210*4882a593Smuzhiyun 			 size_t count, loff_t *ppos);
211*4882a593Smuzhiyun static int dax_devmap(struct file *f, struct vm_area_struct *vma);
212*4882a593Smuzhiyun static int dax_close(struct inode *i, struct file *f);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun static const struct file_operations dax_fops = {
215*4882a593Smuzhiyun 	.owner	=	THIS_MODULE,
216*4882a593Smuzhiyun 	.open	=	dax_open,
217*4882a593Smuzhiyun 	.read	=	dax_read,
218*4882a593Smuzhiyun 	.write	=	dax_write,
219*4882a593Smuzhiyun 	.mmap	=	dax_devmap,
220*4882a593Smuzhiyun 	.release =	dax_close,
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun static int dax_ccb_exec(struct dax_ctx *ctx, const char __user *buf,
224*4882a593Smuzhiyun 			size_t count, loff_t *ppos);
225*4882a593Smuzhiyun static int dax_ccb_info(u64 ca, struct ccb_info_result *info);
226*4882a593Smuzhiyun static int dax_ccb_kill(u64 ca, u16 *kill_res);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun static struct cdev c_dev;
229*4882a593Smuzhiyun static struct class *cl;
230*4882a593Smuzhiyun static dev_t first;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun static int max_ccb_version;
233*4882a593Smuzhiyun static int dax_debug;
234*4882a593Smuzhiyun module_param(dax_debug, int, 0644);
235*4882a593Smuzhiyun MODULE_PARM_DESC(dax_debug, "Debug flags");
236*4882a593Smuzhiyun 
dax_attach(void)237*4882a593Smuzhiyun static int __init dax_attach(void)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	unsigned long dummy, hv_rv, major, minor, minor_requested, max_ccbs;
240*4882a593Smuzhiyun 	struct mdesc_handle *hp = mdesc_grab();
241*4882a593Smuzhiyun 	char *prop, *dax_name;
242*4882a593Smuzhiyun 	bool found = false;
243*4882a593Smuzhiyun 	int len, ret = 0;
244*4882a593Smuzhiyun 	u64 pn;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (hp == NULL) {
247*4882a593Smuzhiyun 		dax_err("Unable to grab mdesc");
248*4882a593Smuzhiyun 		return -ENODEV;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	mdesc_for_each_node_by_name(hp, pn, "virtual-device") {
252*4882a593Smuzhiyun 		prop = (char *)mdesc_get_property(hp, pn, "name", &len);
253*4882a593Smuzhiyun 		if (prop == NULL)
254*4882a593Smuzhiyun 			continue;
255*4882a593Smuzhiyun 		if (strncmp(prop, "dax", strlen("dax")))
256*4882a593Smuzhiyun 			continue;
257*4882a593Smuzhiyun 		dax_dbg("Found node 0x%llx = %s", pn, prop);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		prop = (char *)mdesc_get_property(hp, pn, "compatible", &len);
260*4882a593Smuzhiyun 		if (prop == NULL)
261*4882a593Smuzhiyun 			continue;
262*4882a593Smuzhiyun 		dax_dbg("Found node 0x%llx = %s", pn, prop);
263*4882a593Smuzhiyun 		found = true;
264*4882a593Smuzhiyun 		break;
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (!found) {
268*4882a593Smuzhiyun 		dax_err("No DAX device found");
269*4882a593Smuzhiyun 		ret = -ENODEV;
270*4882a593Smuzhiyun 		goto done;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (strncmp(prop, DAX2_STR, strlen(DAX2_STR)) == 0) {
274*4882a593Smuzhiyun 		dax_name = DAX_NAME "2";
275*4882a593Smuzhiyun 		major = DAX2_MAJOR;
276*4882a593Smuzhiyun 		minor_requested = DAX2_MINOR;
277*4882a593Smuzhiyun 		max_ccb_version = 1;
278*4882a593Smuzhiyun 		dax_dbg("MD indicates DAX2 coprocessor");
279*4882a593Smuzhiyun 	} else if (strncmp(prop, DAX1_STR, strlen(DAX1_STR)) == 0) {
280*4882a593Smuzhiyun 		dax_name = DAX_NAME "1";
281*4882a593Smuzhiyun 		major = DAX1_MAJOR;
282*4882a593Smuzhiyun 		minor_requested = DAX1_MINOR;
283*4882a593Smuzhiyun 		max_ccb_version = 0;
284*4882a593Smuzhiyun 		dax_dbg("MD indicates DAX1 coprocessor");
285*4882a593Smuzhiyun 	} else {
286*4882a593Smuzhiyun 		dax_err("Unknown dax type: %s", prop);
287*4882a593Smuzhiyun 		ret = -ENODEV;
288*4882a593Smuzhiyun 		goto done;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	minor = minor_requested;
292*4882a593Smuzhiyun 	dax_dbg("Registering DAX HV api with major %ld minor %ld", major,
293*4882a593Smuzhiyun 		minor);
294*4882a593Smuzhiyun 	if (sun4v_hvapi_register(HV_GRP_DAX, major, &minor)) {
295*4882a593Smuzhiyun 		dax_err("hvapi_register failed");
296*4882a593Smuzhiyun 		ret = -ENODEV;
297*4882a593Smuzhiyun 		goto done;
298*4882a593Smuzhiyun 	} else {
299*4882a593Smuzhiyun 		dax_dbg("Max minor supported by HV = %ld (major %ld)", minor,
300*4882a593Smuzhiyun 			major);
301*4882a593Smuzhiyun 		minor = min(minor, minor_requested);
302*4882a593Smuzhiyun 		dax_dbg("registered DAX major %ld minor %ld", major, minor);
303*4882a593Smuzhiyun 	}
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	/* submit a zero length ccb array to query coprocessor queue size */
306*4882a593Smuzhiyun 	hv_rv = sun4v_ccb_submit(0, 0, HV_CCB_QUERY_CMD, 0, &max_ccbs, &dummy);
307*4882a593Smuzhiyun 	if (hv_rv != 0) {
308*4882a593Smuzhiyun 		dax_err("get_hwqueue_size failed with status=%ld and max_ccbs=%ld",
309*4882a593Smuzhiyun 			hv_rv, max_ccbs);
310*4882a593Smuzhiyun 		ret = -ENODEV;
311*4882a593Smuzhiyun 		goto done;
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (max_ccbs != DAX_MAX_CCBS) {
315*4882a593Smuzhiyun 		dax_err("HV reports unsupported max_ccbs=%ld", max_ccbs);
316*4882a593Smuzhiyun 		ret = -ENODEV;
317*4882a593Smuzhiyun 		goto done;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (alloc_chrdev_region(&first, 0, 1, DAX_NAME) < 0) {
321*4882a593Smuzhiyun 		dax_err("alloc_chrdev_region failed");
322*4882a593Smuzhiyun 		ret = -ENXIO;
323*4882a593Smuzhiyun 		goto done;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	cl = class_create(THIS_MODULE, DAX_NAME);
327*4882a593Smuzhiyun 	if (IS_ERR(cl)) {
328*4882a593Smuzhiyun 		dax_err("class_create failed");
329*4882a593Smuzhiyun 		ret = PTR_ERR(cl);
330*4882a593Smuzhiyun 		goto class_error;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (device_create(cl, NULL, first, NULL, dax_name) == NULL) {
334*4882a593Smuzhiyun 		dax_err("device_create failed");
335*4882a593Smuzhiyun 		ret = -ENXIO;
336*4882a593Smuzhiyun 		goto device_error;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	cdev_init(&c_dev, &dax_fops);
340*4882a593Smuzhiyun 	if (cdev_add(&c_dev, first, 1) == -1) {
341*4882a593Smuzhiyun 		dax_err("cdev_add failed");
342*4882a593Smuzhiyun 		ret = -ENXIO;
343*4882a593Smuzhiyun 		goto cdev_error;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	pr_info("Attached DAX module\n");
347*4882a593Smuzhiyun 	goto done;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun cdev_error:
350*4882a593Smuzhiyun 	device_destroy(cl, first);
351*4882a593Smuzhiyun device_error:
352*4882a593Smuzhiyun 	class_destroy(cl);
353*4882a593Smuzhiyun class_error:
354*4882a593Smuzhiyun 	unregister_chrdev_region(first, 1);
355*4882a593Smuzhiyun done:
356*4882a593Smuzhiyun 	mdesc_release(hp);
357*4882a593Smuzhiyun 	return ret;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun module_init(dax_attach);
360*4882a593Smuzhiyun 
dax_detach(void)361*4882a593Smuzhiyun static void __exit dax_detach(void)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	pr_info("Cleaning up DAX module\n");
364*4882a593Smuzhiyun 	cdev_del(&c_dev);
365*4882a593Smuzhiyun 	device_destroy(cl, first);
366*4882a593Smuzhiyun 	class_destroy(cl);
367*4882a593Smuzhiyun 	unregister_chrdev_region(first, 1);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun module_exit(dax_detach);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun /* map completion area */
dax_devmap(struct file * f,struct vm_area_struct * vma)372*4882a593Smuzhiyun static int dax_devmap(struct file *f, struct vm_area_struct *vma)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	struct dax_ctx *ctx = (struct dax_ctx *)f->private_data;
375*4882a593Smuzhiyun 	size_t len = vma->vm_end - vma->vm_start;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	dax_dbg("len=0x%lx, flags=0x%lx", len, vma->vm_flags);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (ctx->owner != current) {
380*4882a593Smuzhiyun 		dax_dbg("devmap called from wrong thread");
381*4882a593Smuzhiyun 		return -EINVAL;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (len != DAX_MMAP_LEN) {
385*4882a593Smuzhiyun 		dax_dbg("len(%lu) != DAX_MMAP_LEN(%d)", len, DAX_MMAP_LEN);
386*4882a593Smuzhiyun 		return -EINVAL;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/* completion area is mapped read-only for user */
390*4882a593Smuzhiyun 	if (vma->vm_flags & VM_WRITE)
391*4882a593Smuzhiyun 		return -EPERM;
392*4882a593Smuzhiyun 	vma->vm_flags &= ~VM_MAYWRITE;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	if (remap_pfn_range(vma, vma->vm_start, ctx->ca_buf_ra >> PAGE_SHIFT,
395*4882a593Smuzhiyun 			    len, vma->vm_page_prot))
396*4882a593Smuzhiyun 		return -EAGAIN;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	dax_dbg("mmapped completion area at uva 0x%lx", vma->vm_start);
399*4882a593Smuzhiyun 	return 0;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun /* Unlock user pages. Called during dequeue or device close */
dax_unlock_pages(struct dax_ctx * ctx,int ccb_index,int nelem)403*4882a593Smuzhiyun static void dax_unlock_pages(struct dax_ctx *ctx, int ccb_index, int nelem)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	int i, j;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	for (i = ccb_index; i < ccb_index + nelem; i++) {
408*4882a593Smuzhiyun 		for (j = 0; j < NUM_STREAM_TYPES; j++) {
409*4882a593Smuzhiyun 			struct page *p = ctx->pages[i][j];
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 			if (p) {
412*4882a593Smuzhiyun 				dax_dbg("freeing page %p", p);
413*4882a593Smuzhiyun 				unpin_user_pages_dirty_lock(&p, 1, j == OUT);
414*4882a593Smuzhiyun 				ctx->pages[i][j] = NULL;
415*4882a593Smuzhiyun 			}
416*4882a593Smuzhiyun 		}
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
dax_lock_page(void * va,struct page ** p)420*4882a593Smuzhiyun static int dax_lock_page(void *va, struct page **p)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	int ret;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	dax_dbg("uva %p", va);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	ret = pin_user_pages_fast((unsigned long)va, 1, FOLL_WRITE, p);
427*4882a593Smuzhiyun 	if (ret == 1) {
428*4882a593Smuzhiyun 		dax_dbg("locked page %p, for VA %p", *p, va);
429*4882a593Smuzhiyun 		return 0;
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	dax_dbg("pin_user_pages failed, va=%p, ret=%d", va, ret);
433*4882a593Smuzhiyun 	return -1;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
dax_lock_pages(struct dax_ctx * ctx,int idx,int nelem,u64 * err_va)436*4882a593Smuzhiyun static int dax_lock_pages(struct dax_ctx *ctx, int idx,
437*4882a593Smuzhiyun 			  int nelem, u64 *err_va)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	int i;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	for (i = 0; i < nelem; i++) {
442*4882a593Smuzhiyun 		struct dax_ccb *ccbp = &ctx->ccb_buf[i];
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 		/*
445*4882a593Smuzhiyun 		 * For each address in the CCB whose type is virtual,
446*4882a593Smuzhiyun 		 * lock the page and change the type to virtual alternate
447*4882a593Smuzhiyun 		 * context. On error, return the offending address in
448*4882a593Smuzhiyun 		 * err_va.
449*4882a593Smuzhiyun 		 */
450*4882a593Smuzhiyun 		if (ccbp->hdr.out_addr_type == DAX_ADDR_TYPE_VA) {
451*4882a593Smuzhiyun 			dax_dbg("output");
452*4882a593Smuzhiyun 			if (dax_lock_page(ccbp->out,
453*4882a593Smuzhiyun 					  &ctx->pages[i + idx][OUT]) != 0) {
454*4882a593Smuzhiyun 				*err_va = (u64)ccbp->out;
455*4882a593Smuzhiyun 				goto error;
456*4882a593Smuzhiyun 			}
457*4882a593Smuzhiyun 			ccbp->hdr.out_addr_type = DAX_ADDR_TYPE_VA_ALT;
458*4882a593Smuzhiyun 		}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 		if (ccbp->hdr.pri_addr_type == DAX_ADDR_TYPE_VA) {
461*4882a593Smuzhiyun 			dax_dbg("input");
462*4882a593Smuzhiyun 			if (dax_lock_page(ccbp->pri,
463*4882a593Smuzhiyun 					  &ctx->pages[i + idx][PRI]) != 0) {
464*4882a593Smuzhiyun 				*err_va = (u64)ccbp->pri;
465*4882a593Smuzhiyun 				goto error;
466*4882a593Smuzhiyun 			}
467*4882a593Smuzhiyun 			ccbp->hdr.pri_addr_type = DAX_ADDR_TYPE_VA_ALT;
468*4882a593Smuzhiyun 		}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		if (ccbp->hdr.sec_addr_type == DAX_ADDR_TYPE_VA) {
471*4882a593Smuzhiyun 			dax_dbg("sec input");
472*4882a593Smuzhiyun 			if (dax_lock_page(ccbp->sec,
473*4882a593Smuzhiyun 					  &ctx->pages[i + idx][SEC]) != 0) {
474*4882a593Smuzhiyun 				*err_va = (u64)ccbp->sec;
475*4882a593Smuzhiyun 				goto error;
476*4882a593Smuzhiyun 			}
477*4882a593Smuzhiyun 			ccbp->hdr.sec_addr_type = DAX_ADDR_TYPE_VA_ALT;
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 		if (ccbp->hdr.table_addr_type == DAX_ADDR_TYPE_VA) {
481*4882a593Smuzhiyun 			dax_dbg("tbl");
482*4882a593Smuzhiyun 			if (dax_lock_page(ccbp->tbl,
483*4882a593Smuzhiyun 					  &ctx->pages[i + idx][TBL]) != 0) {
484*4882a593Smuzhiyun 				*err_va = (u64)ccbp->tbl;
485*4882a593Smuzhiyun 				goto error;
486*4882a593Smuzhiyun 			}
487*4882a593Smuzhiyun 			ccbp->hdr.table_addr_type = DAX_ADDR_TYPE_VA_ALT;
488*4882a593Smuzhiyun 		}
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 		/* skip over 2nd 64 bytes of long CCB */
491*4882a593Smuzhiyun 		if (ccbp->hdr.longccb)
492*4882a593Smuzhiyun 			i++;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 	return DAX_SUBMIT_OK;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun error:
497*4882a593Smuzhiyun 	dax_unlock_pages(ctx, idx, nelem);
498*4882a593Smuzhiyun 	return DAX_SUBMIT_ERR_NOACCESS;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
dax_ccb_wait(struct dax_ctx * ctx,int idx)501*4882a593Smuzhiyun static void dax_ccb_wait(struct dax_ctx *ctx, int idx)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	int ret, nretries;
504*4882a593Smuzhiyun 	u16 kill_res;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	dax_dbg("idx=%d", idx);
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	for (nretries = 0; nretries < DAX_CCB_RETRIES; nretries++) {
509*4882a593Smuzhiyun 		if (ctx->ca_buf[idx].status == CCA_STAT_NOT_COMPLETED)
510*4882a593Smuzhiyun 			udelay(DAX_CCB_USEC);
511*4882a593Smuzhiyun 		else
512*4882a593Smuzhiyun 			return;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 	dax_dbg("ctx (%p): CCB[%d] timed out, wait usec=%d, retries=%d. Killing ccb",
515*4882a593Smuzhiyun 		(void *)ctx, idx, DAX_CCB_USEC, DAX_CCB_RETRIES);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	ret = dax_ccb_kill(ctx->ca_buf_ra + idx * sizeof(struct dax_cca),
518*4882a593Smuzhiyun 			   &kill_res);
519*4882a593Smuzhiyun 	dax_dbg("Kill CCB[%d] %s", idx, ret ? "failed" : "succeeded");
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
dax_close(struct inode * ino,struct file * f)522*4882a593Smuzhiyun static int dax_close(struct inode *ino, struct file *f)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun 	struct dax_ctx *ctx = (struct dax_ctx *)f->private_data;
525*4882a593Smuzhiyun 	int i;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	f->private_data = NULL;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	for (i = 0; i < DAX_CA_ELEMS; i++) {
530*4882a593Smuzhiyun 		if (ctx->ca_buf[i].status == CCA_STAT_NOT_COMPLETED) {
531*4882a593Smuzhiyun 			dax_dbg("CCB[%d] not completed", i);
532*4882a593Smuzhiyun 			dax_ccb_wait(ctx, i);
533*4882a593Smuzhiyun 		}
534*4882a593Smuzhiyun 		dax_unlock_pages(ctx, i, 1);
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	kfree(ctx->ccb_buf);
538*4882a593Smuzhiyun 	kfree(ctx->ca_buf);
539*4882a593Smuzhiyun 	dax_stat_dbg("CCBs: %d good, %d bad", ctx->ccb_count, ctx->fail_count);
540*4882a593Smuzhiyun 	kfree(ctx);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	return 0;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
dax_read(struct file * f,char __user * buf,size_t count,loff_t * ppos)545*4882a593Smuzhiyun static ssize_t dax_read(struct file *f, char __user *buf,
546*4882a593Smuzhiyun 			size_t count, loff_t *ppos)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct dax_ctx *ctx = f->private_data;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	if (ctx->client != current)
551*4882a593Smuzhiyun 		return -EUSERS;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	ctx->client = NULL;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	if (count != sizeof(union ccb_result))
556*4882a593Smuzhiyun 		return -EINVAL;
557*4882a593Smuzhiyun 	if (copy_to_user(buf, &ctx->result, sizeof(union ccb_result)))
558*4882a593Smuzhiyun 		return -EFAULT;
559*4882a593Smuzhiyun 	return count;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
dax_write(struct file * f,const char __user * buf,size_t count,loff_t * ppos)562*4882a593Smuzhiyun static ssize_t dax_write(struct file *f, const char __user *buf,
563*4882a593Smuzhiyun 			 size_t count, loff_t *ppos)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun 	struct dax_ctx *ctx = f->private_data;
566*4882a593Smuzhiyun 	struct dax_command hdr;
567*4882a593Smuzhiyun 	unsigned long ca;
568*4882a593Smuzhiyun 	int i, idx, ret;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	if (ctx->client != NULL)
571*4882a593Smuzhiyun 		return -EINVAL;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	if (count == 0 || count > DAX_MAX_CCBS * sizeof(struct dax_ccb))
574*4882a593Smuzhiyun 		return -EINVAL;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	if (count % sizeof(struct dax_ccb) == 0)
577*4882a593Smuzhiyun 		return dax_ccb_exec(ctx, buf, count, ppos); /* CCB EXEC */
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (count != sizeof(struct dax_command))
580*4882a593Smuzhiyun 		return -EINVAL;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	/* immediate command */
583*4882a593Smuzhiyun 	if (ctx->owner != current)
584*4882a593Smuzhiyun 		return -EUSERS;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	if (copy_from_user(&hdr, buf, sizeof(hdr)))
587*4882a593Smuzhiyun 		return -EFAULT;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	ca = ctx->ca_buf_ra + hdr.ca_offset;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	switch (hdr.command) {
592*4882a593Smuzhiyun 	case CCB_KILL:
593*4882a593Smuzhiyun 		if (hdr.ca_offset >= DAX_MMAP_LEN) {
594*4882a593Smuzhiyun 			dax_dbg("invalid ca_offset (%d) >= ca_buflen (%d)",
595*4882a593Smuzhiyun 				hdr.ca_offset, DAX_MMAP_LEN);
596*4882a593Smuzhiyun 			return -EINVAL;
597*4882a593Smuzhiyun 		}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 		ret = dax_ccb_kill(ca, &ctx->result.kill.action);
600*4882a593Smuzhiyun 		if (ret != 0) {
601*4882a593Smuzhiyun 			dax_dbg("dax_ccb_kill failed (ret=%d)", ret);
602*4882a593Smuzhiyun 			return ret;
603*4882a593Smuzhiyun 		}
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 		dax_info_dbg("killed (ca_offset %d)", hdr.ca_offset);
606*4882a593Smuzhiyun 		idx = hdr.ca_offset / sizeof(struct dax_cca);
607*4882a593Smuzhiyun 		ctx->ca_buf[idx].status = CCA_STAT_KILLED;
608*4882a593Smuzhiyun 		ctx->ca_buf[idx].err = CCA_ERR_KILLED;
609*4882a593Smuzhiyun 		ctx->client = current;
610*4882a593Smuzhiyun 		return count;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	case CCB_INFO:
613*4882a593Smuzhiyun 		if (hdr.ca_offset >= DAX_MMAP_LEN) {
614*4882a593Smuzhiyun 			dax_dbg("invalid ca_offset (%d) >= ca_buflen (%d)",
615*4882a593Smuzhiyun 				hdr.ca_offset, DAX_MMAP_LEN);
616*4882a593Smuzhiyun 			return -EINVAL;
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 		ret = dax_ccb_info(ca, &ctx->result.info);
620*4882a593Smuzhiyun 		if (ret != 0) {
621*4882a593Smuzhiyun 			dax_dbg("dax_ccb_info failed (ret=%d)", ret);
622*4882a593Smuzhiyun 			return ret;
623*4882a593Smuzhiyun 		}
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 		dax_info_dbg("info succeeded on ca_offset %d", hdr.ca_offset);
626*4882a593Smuzhiyun 		ctx->client = current;
627*4882a593Smuzhiyun 		return count;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	case CCB_DEQUEUE:
630*4882a593Smuzhiyun 		for (i = 0; i < DAX_CA_ELEMS; i++) {
631*4882a593Smuzhiyun 			if (ctx->ca_buf[i].status !=
632*4882a593Smuzhiyun 			    CCA_STAT_NOT_COMPLETED)
633*4882a593Smuzhiyun 				dax_unlock_pages(ctx, i, 1);
634*4882a593Smuzhiyun 		}
635*4882a593Smuzhiyun 		return count;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	default:
638*4882a593Smuzhiyun 		return -EINVAL;
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun 
dax_open(struct inode * inode,struct file * f)642*4882a593Smuzhiyun static int dax_open(struct inode *inode, struct file *f)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun 	struct dax_ctx *ctx = NULL;
645*4882a593Smuzhiyun 	int i;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
648*4882a593Smuzhiyun 	if (ctx == NULL)
649*4882a593Smuzhiyun 		goto done;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	ctx->ccb_buf = kcalloc(DAX_MAX_CCBS, sizeof(struct dax_ccb),
652*4882a593Smuzhiyun 			       GFP_KERNEL);
653*4882a593Smuzhiyun 	if (ctx->ccb_buf == NULL)
654*4882a593Smuzhiyun 		goto done;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	ctx->ccb_buf_ra = virt_to_phys(ctx->ccb_buf);
657*4882a593Smuzhiyun 	dax_dbg("ctx->ccb_buf=0x%p, ccb_buf_ra=0x%llx",
658*4882a593Smuzhiyun 		(void *)ctx->ccb_buf, ctx->ccb_buf_ra);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	/* allocate CCB completion area buffer */
661*4882a593Smuzhiyun 	ctx->ca_buf = kzalloc(DAX_MMAP_LEN, GFP_KERNEL);
662*4882a593Smuzhiyun 	if (ctx->ca_buf == NULL)
663*4882a593Smuzhiyun 		goto alloc_error;
664*4882a593Smuzhiyun 	for (i = 0; i < DAX_CA_ELEMS; i++)
665*4882a593Smuzhiyun 		ctx->ca_buf[i].status = CCA_STAT_COMPLETED;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	ctx->ca_buf_ra = virt_to_phys(ctx->ca_buf);
668*4882a593Smuzhiyun 	dax_dbg("ctx=0x%p, ctx->ca_buf=0x%p, ca_buf_ra=0x%llx",
669*4882a593Smuzhiyun 		(void *)ctx, (void *)ctx->ca_buf, ctx->ca_buf_ra);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	ctx->owner = current;
672*4882a593Smuzhiyun 	f->private_data = ctx;
673*4882a593Smuzhiyun 	return 0;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun alloc_error:
676*4882a593Smuzhiyun 	kfree(ctx->ccb_buf);
677*4882a593Smuzhiyun done:
678*4882a593Smuzhiyun 	kfree(ctx);
679*4882a593Smuzhiyun 	return -ENOMEM;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
dax_hv_errno(unsigned long hv_ret,int * ret)682*4882a593Smuzhiyun static char *dax_hv_errno(unsigned long hv_ret, int *ret)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	switch (hv_ret) {
685*4882a593Smuzhiyun 	case HV_EBADALIGN:
686*4882a593Smuzhiyun 		*ret = -EFAULT;
687*4882a593Smuzhiyun 		return "HV_EBADALIGN";
688*4882a593Smuzhiyun 	case HV_ENORADDR:
689*4882a593Smuzhiyun 		*ret = -EFAULT;
690*4882a593Smuzhiyun 		return "HV_ENORADDR";
691*4882a593Smuzhiyun 	case HV_EINVAL:
692*4882a593Smuzhiyun 		*ret = -EINVAL;
693*4882a593Smuzhiyun 		return "HV_EINVAL";
694*4882a593Smuzhiyun 	case HV_EWOULDBLOCK:
695*4882a593Smuzhiyun 		*ret = -EAGAIN;
696*4882a593Smuzhiyun 		return "HV_EWOULDBLOCK";
697*4882a593Smuzhiyun 	case HV_ENOACCESS:
698*4882a593Smuzhiyun 		*ret = -EPERM;
699*4882a593Smuzhiyun 		return "HV_ENOACCESS";
700*4882a593Smuzhiyun 	default:
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	}
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	*ret = -EIO;
705*4882a593Smuzhiyun 	return "UNKNOWN";
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun 
dax_ccb_kill(u64 ca,u16 * kill_res)708*4882a593Smuzhiyun static int dax_ccb_kill(u64 ca, u16 *kill_res)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun 	unsigned long hv_ret;
711*4882a593Smuzhiyun 	int count, ret = 0;
712*4882a593Smuzhiyun 	char *err_str;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	for (count = 0; count < DAX_CCB_RETRIES; count++) {
715*4882a593Smuzhiyun 		dax_dbg("attempting kill on ca_ra 0x%llx", ca);
716*4882a593Smuzhiyun 		hv_ret = sun4v_ccb_kill(ca, kill_res);
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 		if (hv_ret == HV_EOK) {
719*4882a593Smuzhiyun 			dax_info_dbg("HV_EOK (ca_ra 0x%llx): %d", ca,
720*4882a593Smuzhiyun 				     *kill_res);
721*4882a593Smuzhiyun 		} else {
722*4882a593Smuzhiyun 			err_str = dax_hv_errno(hv_ret, &ret);
723*4882a593Smuzhiyun 			dax_dbg("%s (ca_ra 0x%llx)", err_str, ca);
724*4882a593Smuzhiyun 		}
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 		if (ret != -EAGAIN)
727*4882a593Smuzhiyun 			return ret;
728*4882a593Smuzhiyun 		dax_info_dbg("ccb_kill count = %d", count);
729*4882a593Smuzhiyun 		udelay(DAX_CCB_USEC);
730*4882a593Smuzhiyun 	}
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	return -EAGAIN;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun 
dax_ccb_info(u64 ca,struct ccb_info_result * info)735*4882a593Smuzhiyun static int dax_ccb_info(u64 ca, struct ccb_info_result *info)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun 	unsigned long hv_ret;
738*4882a593Smuzhiyun 	char *err_str;
739*4882a593Smuzhiyun 	int ret = 0;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	dax_dbg("attempting info on ca_ra 0x%llx", ca);
742*4882a593Smuzhiyun 	hv_ret = sun4v_ccb_info(ca, info);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	if (hv_ret == HV_EOK) {
745*4882a593Smuzhiyun 		dax_info_dbg("HV_EOK (ca_ra 0x%llx): %d", ca, info->state);
746*4882a593Smuzhiyun 		if (info->state == DAX_CCB_ENQUEUED) {
747*4882a593Smuzhiyun 			dax_info_dbg("dax_unit %d, queue_num %d, queue_pos %d",
748*4882a593Smuzhiyun 				     info->inst_num, info->q_num, info->q_pos);
749*4882a593Smuzhiyun 		}
750*4882a593Smuzhiyun 	} else {
751*4882a593Smuzhiyun 		err_str = dax_hv_errno(hv_ret, &ret);
752*4882a593Smuzhiyun 		dax_dbg("%s (ca_ra 0x%llx)", err_str, ca);
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	return ret;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun 
dax_prt_ccbs(struct dax_ccb * ccb,int nelem)758*4882a593Smuzhiyun static void dax_prt_ccbs(struct dax_ccb *ccb, int nelem)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun 	int i, j;
761*4882a593Smuzhiyun 	u64 *ccbp;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	dax_dbg("ccb buffer:");
764*4882a593Smuzhiyun 	for (i = 0; i < nelem; i++) {
765*4882a593Smuzhiyun 		ccbp = (u64 *)&ccb[i];
766*4882a593Smuzhiyun 		dax_dbg(" %sccb[%d]", ccb[i].hdr.longccb ? "long " : "",  i);
767*4882a593Smuzhiyun 		for (j = 0; j < 8; j++)
768*4882a593Smuzhiyun 			dax_dbg("\tccb[%d].dwords[%d]=0x%llx",
769*4882a593Smuzhiyun 				i, j, *(ccbp + j));
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun /*
774*4882a593Smuzhiyun  * Validates user CCB content.  Also sets completion address and address types
775*4882a593Smuzhiyun  * for all addresses contained in CCB.
776*4882a593Smuzhiyun  */
dax_preprocess_usr_ccbs(struct dax_ctx * ctx,int idx,int nelem)777*4882a593Smuzhiyun static int dax_preprocess_usr_ccbs(struct dax_ctx *ctx, int idx, int nelem)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun 	int i;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/*
782*4882a593Smuzhiyun 	 * The user is not allowed to specify real address types in
783*4882a593Smuzhiyun 	 * the CCB header.  This must be enforced by the kernel before
784*4882a593Smuzhiyun 	 * submitting the CCBs to HV.  The only allowed values for all
785*4882a593Smuzhiyun 	 * address fields are VA or IMM
786*4882a593Smuzhiyun 	 */
787*4882a593Smuzhiyun 	for (i = 0; i < nelem; i++) {
788*4882a593Smuzhiyun 		struct dax_ccb *ccbp = &ctx->ccb_buf[i];
789*4882a593Smuzhiyun 		unsigned long ca_offset;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 		if (ccbp->hdr.ccb_version > max_ccb_version)
792*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 		switch (ccbp->hdr.opcode) {
795*4882a593Smuzhiyun 		case DAX_OP_SYNC_NOP:
796*4882a593Smuzhiyun 		case DAX_OP_EXTRACT:
797*4882a593Smuzhiyun 		case DAX_OP_SCAN_VALUE:
798*4882a593Smuzhiyun 		case DAX_OP_SCAN_RANGE:
799*4882a593Smuzhiyun 		case DAX_OP_TRANSLATE:
800*4882a593Smuzhiyun 		case DAX_OP_SCAN_VALUE | DAX_OP_INVERT:
801*4882a593Smuzhiyun 		case DAX_OP_SCAN_RANGE | DAX_OP_INVERT:
802*4882a593Smuzhiyun 		case DAX_OP_TRANSLATE | DAX_OP_INVERT:
803*4882a593Smuzhiyun 		case DAX_OP_SELECT:
804*4882a593Smuzhiyun 			break;
805*4882a593Smuzhiyun 		default:
806*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
807*4882a593Smuzhiyun 		}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 		if (ccbp->hdr.out_addr_type != DAX_ADDR_TYPE_VA &&
810*4882a593Smuzhiyun 		    ccbp->hdr.out_addr_type != DAX_ADDR_TYPE_NONE) {
811*4882a593Smuzhiyun 			dax_dbg("invalid out_addr_type in user CCB[%d]", i);
812*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
813*4882a593Smuzhiyun 		}
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 		if (ccbp->hdr.pri_addr_type != DAX_ADDR_TYPE_VA &&
816*4882a593Smuzhiyun 		    ccbp->hdr.pri_addr_type != DAX_ADDR_TYPE_NONE) {
817*4882a593Smuzhiyun 			dax_dbg("invalid pri_addr_type in user CCB[%d]", i);
818*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
819*4882a593Smuzhiyun 		}
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 		if (ccbp->hdr.sec_addr_type != DAX_ADDR_TYPE_VA &&
822*4882a593Smuzhiyun 		    ccbp->hdr.sec_addr_type != DAX_ADDR_TYPE_NONE) {
823*4882a593Smuzhiyun 			dax_dbg("invalid sec_addr_type in user CCB[%d]", i);
824*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
825*4882a593Smuzhiyun 		}
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 		if (ccbp->hdr.table_addr_type != DAX_ADDR_TYPE_VA &&
828*4882a593Smuzhiyun 		    ccbp->hdr.table_addr_type != DAX_ADDR_TYPE_NONE) {
829*4882a593Smuzhiyun 			dax_dbg("invalid table_addr_type in user CCB[%d]", i);
830*4882a593Smuzhiyun 			return DAX_SUBMIT_ERR_CCB_INVAL;
831*4882a593Smuzhiyun 		}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 		/* set completion (real) address and address type */
834*4882a593Smuzhiyun 		ccbp->hdr.cca_addr_type = DAX_ADDR_TYPE_RA;
835*4882a593Smuzhiyun 		ca_offset = (idx + i) * sizeof(struct dax_cca);
836*4882a593Smuzhiyun 		ccbp->ca = (void *)ctx->ca_buf_ra + ca_offset;
837*4882a593Smuzhiyun 		memset(&ctx->ca_buf[idx + i], 0, sizeof(struct dax_cca));
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 		dax_dbg("ccb[%d]=%p, ca_offset=0x%lx, compl RA=0x%llx",
840*4882a593Smuzhiyun 			i, ccbp, ca_offset, ctx->ca_buf_ra + ca_offset);
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 		/* skip over 2nd 64 bytes of long CCB */
843*4882a593Smuzhiyun 		if (ccbp->hdr.longccb)
844*4882a593Smuzhiyun 			i++;
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	return DAX_SUBMIT_OK;
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun 
dax_ccb_exec(struct dax_ctx * ctx,const char __user * buf,size_t count,loff_t * ppos)850*4882a593Smuzhiyun static int dax_ccb_exec(struct dax_ctx *ctx, const char __user *buf,
851*4882a593Smuzhiyun 			size_t count, loff_t *ppos)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun 	unsigned long accepted_len, hv_rv;
854*4882a593Smuzhiyun 	int i, idx, nccbs, naccepted;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	ctx->client = current;
857*4882a593Smuzhiyun 	idx = *ppos;
858*4882a593Smuzhiyun 	nccbs = count / sizeof(struct dax_ccb);
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	if (ctx->owner != current) {
861*4882a593Smuzhiyun 		dax_dbg("wrong thread");
862*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_THR_INIT;
863*4882a593Smuzhiyun 		return 0;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun 	dax_dbg("args: ccb_buf_len=%ld, idx=%d", count, idx);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	/* for given index and length, verify ca_buf range exists */
868*4882a593Smuzhiyun 	if (idx < 0 || idx > (DAX_CA_ELEMS - nccbs)) {
869*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_NO_CA_AVAIL;
870*4882a593Smuzhiyun 		return 0;
871*4882a593Smuzhiyun 	}
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	/*
874*4882a593Smuzhiyun 	 * Copy CCBs into kernel buffer to prevent modification by the
875*4882a593Smuzhiyun 	 * user in between validation and submission.
876*4882a593Smuzhiyun 	 */
877*4882a593Smuzhiyun 	if (copy_from_user(ctx->ccb_buf, buf, count)) {
878*4882a593Smuzhiyun 		dax_dbg("copyin of user CCB buffer failed");
879*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_CCB_ARR_MMU_MISS;
880*4882a593Smuzhiyun 		return 0;
881*4882a593Smuzhiyun 	}
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	/* check to see if ca_buf[idx] .. ca_buf[idx + nccbs] are available */
884*4882a593Smuzhiyun 	for (i = idx; i < idx + nccbs; i++) {
885*4882a593Smuzhiyun 		if (ctx->ca_buf[i].status == CCA_STAT_NOT_COMPLETED) {
886*4882a593Smuzhiyun 			dax_dbg("CA range not available, dequeue needed");
887*4882a593Smuzhiyun 			ctx->result.exec.status = DAX_SUBMIT_ERR_NO_CA_AVAIL;
888*4882a593Smuzhiyun 			return 0;
889*4882a593Smuzhiyun 		}
890*4882a593Smuzhiyun 	}
891*4882a593Smuzhiyun 	dax_unlock_pages(ctx, idx, nccbs);
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	ctx->result.exec.status = dax_preprocess_usr_ccbs(ctx, idx, nccbs);
894*4882a593Smuzhiyun 	if (ctx->result.exec.status != DAX_SUBMIT_OK)
895*4882a593Smuzhiyun 		return 0;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	ctx->result.exec.status = dax_lock_pages(ctx, idx, nccbs,
898*4882a593Smuzhiyun 						 &ctx->result.exec.status_data);
899*4882a593Smuzhiyun 	if (ctx->result.exec.status != DAX_SUBMIT_OK)
900*4882a593Smuzhiyun 		return 0;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	if (dax_debug & DAX_DBG_FLG_BASIC)
903*4882a593Smuzhiyun 		dax_prt_ccbs(ctx->ccb_buf, nccbs);
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	hv_rv = sun4v_ccb_submit(ctx->ccb_buf_ra, count,
906*4882a593Smuzhiyun 				 HV_CCB_QUERY_CMD | HV_CCB_VA_SECONDARY, 0,
907*4882a593Smuzhiyun 				 &accepted_len, &ctx->result.exec.status_data);
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	switch (hv_rv) {
910*4882a593Smuzhiyun 	case HV_EOK:
911*4882a593Smuzhiyun 		/*
912*4882a593Smuzhiyun 		 * Hcall succeeded with no errors but the accepted
913*4882a593Smuzhiyun 		 * length may be less than the requested length.  The
914*4882a593Smuzhiyun 		 * only way the driver can resubmit the remainder is
915*4882a593Smuzhiyun 		 * to wait for completion of the submitted CCBs since
916*4882a593Smuzhiyun 		 * there is no way to guarantee the ordering semantics
917*4882a593Smuzhiyun 		 * required by the client applications.  Therefore we
918*4882a593Smuzhiyun 		 * let the user library deal with resubmissions.
919*4882a593Smuzhiyun 		 */
920*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_OK;
921*4882a593Smuzhiyun 		break;
922*4882a593Smuzhiyun 	case HV_EWOULDBLOCK:
923*4882a593Smuzhiyun 		/*
924*4882a593Smuzhiyun 		 * This is a transient HV API error. The user library
925*4882a593Smuzhiyun 		 * can retry.
926*4882a593Smuzhiyun 		 */
927*4882a593Smuzhiyun 		dax_dbg("hcall returned HV_EWOULDBLOCK");
928*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_WOULDBLOCK;
929*4882a593Smuzhiyun 		break;
930*4882a593Smuzhiyun 	case HV_ENOMAP:
931*4882a593Smuzhiyun 		/*
932*4882a593Smuzhiyun 		 * HV was unable to translate a VA. The VA it could
933*4882a593Smuzhiyun 		 * not translate is returned in the status_data param.
934*4882a593Smuzhiyun 		 */
935*4882a593Smuzhiyun 		dax_dbg("hcall returned HV_ENOMAP");
936*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_NOMAP;
937*4882a593Smuzhiyun 		break;
938*4882a593Smuzhiyun 	case HV_EINVAL:
939*4882a593Smuzhiyun 		/*
940*4882a593Smuzhiyun 		 * This is the result of an invalid user CCB as HV is
941*4882a593Smuzhiyun 		 * validating some of the user CCB fields.  Pass this
942*4882a593Smuzhiyun 		 * error back to the user. There is no supporting info
943*4882a593Smuzhiyun 		 * to isolate the invalid field.
944*4882a593Smuzhiyun 		 */
945*4882a593Smuzhiyun 		dax_dbg("hcall returned HV_EINVAL");
946*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_CCB_INVAL;
947*4882a593Smuzhiyun 		break;
948*4882a593Smuzhiyun 	case HV_ENOACCESS:
949*4882a593Smuzhiyun 		/*
950*4882a593Smuzhiyun 		 * HV found a VA that did not have the appropriate
951*4882a593Smuzhiyun 		 * permissions (such as the w bit). The VA in question
952*4882a593Smuzhiyun 		 * is returned in status_data param.
953*4882a593Smuzhiyun 		 */
954*4882a593Smuzhiyun 		dax_dbg("hcall returned HV_ENOACCESS");
955*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_NOACCESS;
956*4882a593Smuzhiyun 		break;
957*4882a593Smuzhiyun 	case HV_EUNAVAILABLE:
958*4882a593Smuzhiyun 		/*
959*4882a593Smuzhiyun 		 * The requested CCB operation could not be performed
960*4882a593Smuzhiyun 		 * at this time. Return the specific unavailable code
961*4882a593Smuzhiyun 		 * in the status_data field.
962*4882a593Smuzhiyun 		 */
963*4882a593Smuzhiyun 		dax_dbg("hcall returned HV_EUNAVAILABLE");
964*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_UNAVAIL;
965*4882a593Smuzhiyun 		break;
966*4882a593Smuzhiyun 	default:
967*4882a593Smuzhiyun 		ctx->result.exec.status = DAX_SUBMIT_ERR_INTERNAL;
968*4882a593Smuzhiyun 		dax_dbg("unknown hcall return value (%ld)", hv_rv);
969*4882a593Smuzhiyun 		break;
970*4882a593Smuzhiyun 	}
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	/* unlock pages associated with the unaccepted CCBs */
973*4882a593Smuzhiyun 	naccepted = accepted_len / sizeof(struct dax_ccb);
974*4882a593Smuzhiyun 	dax_unlock_pages(ctx, idx + naccepted, nccbs - naccepted);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	/* mark unaccepted CCBs as not completed */
977*4882a593Smuzhiyun 	for (i = idx + naccepted; i < idx + nccbs; i++)
978*4882a593Smuzhiyun 		ctx->ca_buf[i].status = CCA_STAT_COMPLETED;
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	ctx->ccb_count += naccepted;
981*4882a593Smuzhiyun 	ctx->fail_count += nccbs - naccepted;
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	dax_dbg("hcall rv=%ld, accepted_len=%ld, status_data=0x%llx, ret status=%d",
984*4882a593Smuzhiyun 		hv_rv, accepted_len, ctx->result.exec.status_data,
985*4882a593Smuzhiyun 		ctx->result.exec.status);
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	if (count == accepted_len)
988*4882a593Smuzhiyun 		ctx->client = NULL; /* no read needed to complete protocol */
989*4882a593Smuzhiyun 	return accepted_len;
990*4882a593Smuzhiyun }
991