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