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