xref: /titanic_50/usr/src/uts/i86pc/io/ioat/ioat_ioctl.c (revision 17169044f903cb92234f23d0ba0ce43449614a4d)
1*17169044Sbrutus /*
2*17169044Sbrutus  * CDDL HEADER START
3*17169044Sbrutus  *
4*17169044Sbrutus  * The contents of this file are subject to the terms of the
5*17169044Sbrutus  * Common Development and Distribution License (the "License").
6*17169044Sbrutus  * You may not use this file except in compliance with the License.
7*17169044Sbrutus  *
8*17169044Sbrutus  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*17169044Sbrutus  * or http://www.opensolaris.org/os/licensing.
10*17169044Sbrutus  * See the License for the specific language governing permissions
11*17169044Sbrutus  * and limitations under the License.
12*17169044Sbrutus  *
13*17169044Sbrutus  * When distributing Covered Code, include this CDDL HEADER in each
14*17169044Sbrutus  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*17169044Sbrutus  * If applicable, add the following below this CDDL HEADER, with the
16*17169044Sbrutus  * fields enclosed by brackets "[]" replaced with your own identifying
17*17169044Sbrutus  * information: Portions Copyright [yyyy] [name of copyright owner]
18*17169044Sbrutus  *
19*17169044Sbrutus  * CDDL HEADER END
20*17169044Sbrutus  */
21*17169044Sbrutus 
22*17169044Sbrutus /*
23*17169044Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*17169044Sbrutus  * Use is subject to license terms.
25*17169044Sbrutus  */
26*17169044Sbrutus 
27*17169044Sbrutus #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*17169044Sbrutus 
29*17169044Sbrutus #include <sys/errno.h>
30*17169044Sbrutus #include <sys/types.h>
31*17169044Sbrutus #include <sys/conf.h>
32*17169044Sbrutus #include <sys/kmem.h>
33*17169044Sbrutus #include <sys/ddi.h>
34*17169044Sbrutus #include <sys/stat.h>
35*17169044Sbrutus #include <sys/sunddi.h>
36*17169044Sbrutus #include <sys/file.h>
37*17169044Sbrutus #include <sys/open.h>
38*17169044Sbrutus #include <sys/modctl.h>
39*17169044Sbrutus #include <sys/ddi_impldefs.h>
40*17169044Sbrutus #include <sys/sysmacros.h>
41*17169044Sbrutus 
42*17169044Sbrutus #include <vm/hat.h>
43*17169044Sbrutus #include <vm/as.h>
44*17169044Sbrutus 
45*17169044Sbrutus #include <sys/ioat.h>
46*17169044Sbrutus 
47*17169044Sbrutus 
48*17169044Sbrutus extern void *ioat_statep;
49*17169044Sbrutus #define	ptob64(x)	(((uint64_t)(x)) << PAGESHIFT)
50*17169044Sbrutus 
51*17169044Sbrutus static int ioat_ioctl_rdreg(ioat_state_t *state, void *arg, int mode);
52*17169044Sbrutus #ifdef	DEBUG
53*17169044Sbrutus static int ioat_ioctl_wrreg(ioat_state_t *state, void *arg, int mode);
54*17169044Sbrutus static int ioat_ioctl_test(ioat_state_t *state, void *arg, int mode);
55*17169044Sbrutus #endif
56*17169044Sbrutus 
57*17169044Sbrutus /*
58*17169044Sbrutus  * ioat_ioctl()
59*17169044Sbrutus  */
60*17169044Sbrutus /*ARGSUSED*/
61*17169044Sbrutus int
ioat_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred,int * rval)62*17169044Sbrutus ioat_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rval)
63*17169044Sbrutus {
64*17169044Sbrutus 	ioat_state_t *state;
65*17169044Sbrutus 	int instance;
66*17169044Sbrutus 	int e;
67*17169044Sbrutus 
68*17169044Sbrutus 
69*17169044Sbrutus 	e = drv_priv(cred);
70*17169044Sbrutus 	if (e != 0) {
71*17169044Sbrutus 		return (EPERM);
72*17169044Sbrutus 	}
73*17169044Sbrutus 	instance = getminor(dev);
74*17169044Sbrutus 	if (instance == -1) {
75*17169044Sbrutus 		return (EBADF);
76*17169044Sbrutus 	}
77*17169044Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
78*17169044Sbrutus 	if (state == NULL) {
79*17169044Sbrutus 		return (EBADF);
80*17169044Sbrutus 	}
81*17169044Sbrutus 
82*17169044Sbrutus 	switch (cmd) {
83*17169044Sbrutus 	case IOAT_IOCTL_READ_REG:
84*17169044Sbrutus 		e = ioat_ioctl_rdreg(state, (void *)arg, mode);
85*17169044Sbrutus 		break;
86*17169044Sbrutus #ifdef	DEBUG
87*17169044Sbrutus 	case IOAT_IOCTL_WRITE_REG:
88*17169044Sbrutus 		e = ioat_ioctl_wrreg(state, (void *)arg, mode);
89*17169044Sbrutus 		break;
90*17169044Sbrutus 	case IOAT_IOCTL_TEST:
91*17169044Sbrutus 		e = ioat_ioctl_test(state, (void *)arg, mode);
92*17169044Sbrutus 		break;
93*17169044Sbrutus #endif
94*17169044Sbrutus 
95*17169044Sbrutus 	default:
96*17169044Sbrutus 		e = ENXIO;
97*17169044Sbrutus 	}
98*17169044Sbrutus 
99*17169044Sbrutus 	return (e);
100*17169044Sbrutus }
101*17169044Sbrutus 
102*17169044Sbrutus 
103*17169044Sbrutus /*
104*17169044Sbrutus  * ioat_ioctl_rdreg()
105*17169044Sbrutus  */
106*17169044Sbrutus static int
ioat_ioctl_rdreg(ioat_state_t * state,void * arg,int mode)107*17169044Sbrutus ioat_ioctl_rdreg(ioat_state_t *state, void *arg, int mode)
108*17169044Sbrutus {
109*17169044Sbrutus 	ioat_ioctl_rdreg_t rdreg;
110*17169044Sbrutus 	int e;
111*17169044Sbrutus 
112*17169044Sbrutus 
113*17169044Sbrutus 	e = ddi_copyin(arg, &rdreg, sizeof (ioat_ioctl_rdreg_t), mode);
114*17169044Sbrutus 	if (e != 0) {
115*17169044Sbrutus 		return (EFAULT);
116*17169044Sbrutus 	}
117*17169044Sbrutus 
118*17169044Sbrutus 	/*
119*17169044Sbrutus 	 * read a device register, where size is read size in bits, addr is
120*17169044Sbrutus 	 * the offset into MMIO registers.
121*17169044Sbrutus 	 */
122*17169044Sbrutus 	switch (rdreg.size) {
123*17169044Sbrutus 	case 8:
124*17169044Sbrutus 		rdreg.data = (uint64_t)ddi_get8(state->is_reg_handle,
125*17169044Sbrutus 		    (uint8_t *)&state->is_genregs[rdreg.addr]);
126*17169044Sbrutus 		break;
127*17169044Sbrutus 	case 16:
128*17169044Sbrutus 		rdreg.data = (uint64_t)ddi_get16(state->is_reg_handle,
129*17169044Sbrutus 		    (uint16_t *)&state->is_genregs[rdreg.addr]);
130*17169044Sbrutus 		break;
131*17169044Sbrutus 	case 32:
132*17169044Sbrutus 		rdreg.data = (uint64_t)ddi_get32(state->is_reg_handle,
133*17169044Sbrutus 		    (uint32_t *)&state->is_genregs[rdreg.addr]);
134*17169044Sbrutus 		break;
135*17169044Sbrutus 	case 64:
136*17169044Sbrutus 		rdreg.data = (uint64_t)ddi_get64(state->is_reg_handle,
137*17169044Sbrutus 		    (uint64_t *)&state->is_genregs[rdreg.addr]);
138*17169044Sbrutus 		break;
139*17169044Sbrutus 	default:
140*17169044Sbrutus 		return (EFAULT);
141*17169044Sbrutus 	}
142*17169044Sbrutus 
143*17169044Sbrutus 	e = ddi_copyout(&rdreg, arg, sizeof (ioat_ioctl_rdreg_t), mode);
144*17169044Sbrutus 	if (e != 0) {
145*17169044Sbrutus 		return (EFAULT);
146*17169044Sbrutus 	}
147*17169044Sbrutus 
148*17169044Sbrutus 	return (0);
149*17169044Sbrutus }
150*17169044Sbrutus 
151*17169044Sbrutus 
152*17169044Sbrutus #ifdef	DEBUG
153*17169044Sbrutus /*
154*17169044Sbrutus  * ioat_ioctl_wrreg()
155*17169044Sbrutus  */
156*17169044Sbrutus static int
ioat_ioctl_wrreg(ioat_state_t * state,void * arg,int mode)157*17169044Sbrutus ioat_ioctl_wrreg(ioat_state_t *state, void *arg, int mode)
158*17169044Sbrutus {
159*17169044Sbrutus 	ioat_ioctl_wrreg_t wrreg;
160*17169044Sbrutus 	int e;
161*17169044Sbrutus 
162*17169044Sbrutus 
163*17169044Sbrutus 	e = ddi_copyin(arg, &wrreg, sizeof (ioat_ioctl_wrreg_t), mode);
164*17169044Sbrutus 	if (e != 0) {
165*17169044Sbrutus 		return (EFAULT);
166*17169044Sbrutus 	}
167*17169044Sbrutus 
168*17169044Sbrutus 	/*
169*17169044Sbrutus 	 * write a device register, where size is write size in bits, addr is
170*17169044Sbrutus 	 * the offset into MMIO registers.
171*17169044Sbrutus 	 */
172*17169044Sbrutus 	switch (wrreg.size) {
173*17169044Sbrutus 	case 8:
174*17169044Sbrutus 		ddi_put8(state->is_reg_handle,
175*17169044Sbrutus 		    (uint8_t *)&state->is_genregs[wrreg.addr],
176*17169044Sbrutus 		    (uint8_t)wrreg.data);
177*17169044Sbrutus 		break;
178*17169044Sbrutus 	case 16:
179*17169044Sbrutus 		ddi_put16(state->is_reg_handle,
180*17169044Sbrutus 		    (uint16_t *)&state->is_genregs[wrreg.addr],
181*17169044Sbrutus 		    (uint16_t)wrreg.data);
182*17169044Sbrutus 		break;
183*17169044Sbrutus 	case 32:
184*17169044Sbrutus 		ddi_put32(state->is_reg_handle,
185*17169044Sbrutus 		    (uint32_t *)&state->is_genregs[wrreg.addr],
186*17169044Sbrutus 		    (uint32_t)wrreg.data);
187*17169044Sbrutus 		break;
188*17169044Sbrutus 	case 64:
189*17169044Sbrutus 		ddi_put64(state->is_reg_handle,
190*17169044Sbrutus 		    (uint64_t *)&state->is_genregs[wrreg.addr],
191*17169044Sbrutus 		    (uint64_t)wrreg.data);
192*17169044Sbrutus 		break;
193*17169044Sbrutus 	default:
194*17169044Sbrutus 		return (EFAULT);
195*17169044Sbrutus 	}
196*17169044Sbrutus 
197*17169044Sbrutus 	return (0);
198*17169044Sbrutus }
199*17169044Sbrutus 
200*17169044Sbrutus 
201*17169044Sbrutus /*
202*17169044Sbrutus  * ioat_ioctl_test()
203*17169044Sbrutus  */
204*17169044Sbrutus /*ARGSUSED*/
205*17169044Sbrutus static int
ioat_ioctl_test(ioat_state_t * state,void * arg,int mode)206*17169044Sbrutus ioat_ioctl_test(ioat_state_t *state, void *arg, int mode)
207*17169044Sbrutus {
208*17169044Sbrutus 	dcopy_handle_t channel;
209*17169044Sbrutus 	dcopy_cmd_t cmd;
210*17169044Sbrutus 	uint8_t *source;
211*17169044Sbrutus 	uint_t buf_size;
212*17169044Sbrutus 	uint_t poll_cnt;
213*17169044Sbrutus 	uint8_t *dest;
214*17169044Sbrutus 	uint8_t *buf;
215*17169044Sbrutus 	int flags;
216*17169044Sbrutus 	int i;
217*17169044Sbrutus 	int e;
218*17169044Sbrutus 
219*17169044Sbrutus 
220*17169044Sbrutus 	/* allocate 2 paged aligned 4k pages */
221*17169044Sbrutus 	buf_size = 0x1000;
222*17169044Sbrutus 	buf = kmem_zalloc((buf_size * 2) + 0x1000, KM_SLEEP);
223*17169044Sbrutus 	source = (uint8_t *)(((uintptr_t)buf + PAGEOFFSET) & PAGEMASK);
224*17169044Sbrutus 	dest = source + buf_size;
225*17169044Sbrutus 
226*17169044Sbrutus 	/* Init source buffer */
227*17169044Sbrutus 	for (i = 0; i < buf_size; i++) {
228*17169044Sbrutus 		source[i] = (uint8_t)(i & 0xFF);
229*17169044Sbrutus 	}
230*17169044Sbrutus 
231*17169044Sbrutus 	/* allocate a DMA channel */
232*17169044Sbrutus 	e = dcopy_alloc(DCOPY_SLEEP, &channel);
233*17169044Sbrutus 	if (e != DCOPY_SUCCESS) {
234*17169044Sbrutus 		cmn_err(CE_CONT, "dcopy_alloc() failed\n");
235*17169044Sbrutus 		goto testfail_alloc;
236*17169044Sbrutus 	}
237*17169044Sbrutus 
238*17169044Sbrutus 	/*
239*17169044Sbrutus 	 * post 32 DMA copy's from dest to dest.  These will complete in order
240*17169044Sbrutus 	 * so they won't stomp on each other. We don't care about the data
241*17169044Sbrutus 	 * right now which is why we go dest to dest.
242*17169044Sbrutus 	 */
243*17169044Sbrutus 	flags = DCOPY_SLEEP;
244*17169044Sbrutus 	for (i = 0; i < 32; i++) {
245*17169044Sbrutus 		/*
246*17169044Sbrutus 		 * if this is the second command, link the commands from here
247*17169044Sbrutus 		 * on out. We only want to keep track of the last command. We
248*17169044Sbrutus 		 * will poll on the last command completing (which infers that
249*17169044Sbrutus 		 * the other commands completed). If any of the previous
250*17169044Sbrutus 		 * commands fail, so will the last one. Linking the commands
251*17169044Sbrutus 		 * also allows us to only call free for the last command. free
252*17169044Sbrutus 		 * will free up the entire chain of commands.
253*17169044Sbrutus 		 */
254*17169044Sbrutus 		if (i == 1) {
255*17169044Sbrutus 			flags |= DCOPY_ALLOC_LINK;
256*17169044Sbrutus 		}
257*17169044Sbrutus 		e = dcopy_cmd_alloc(channel, flags, &cmd);
258*17169044Sbrutus 		if (e != DCOPY_SUCCESS) {
259*17169044Sbrutus 			cmn_err(CE_CONT, "dcopy_cmd_alloc() failed\n");
260*17169044Sbrutus 			goto testfail_alloc;
261*17169044Sbrutus 		}
262*17169044Sbrutus 
263*17169044Sbrutus 		ASSERT(cmd->dp_version == DCOPY_CMD_V0);
264*17169044Sbrutus 		cmd->dp_cmd = DCOPY_CMD_COPY;
265*17169044Sbrutus 		cmd->dp_flags = DCOPY_CMD_NOFLAGS;
266*17169044Sbrutus 
267*17169044Sbrutus 		/* do a bunch of dest to dest DMA's */
268*17169044Sbrutus 		cmd->dp.copy.cc_source = ptob64(hat_getpfnum(kas.a_hat,
269*17169044Sbrutus 		    (caddr_t)source)) + ((uintptr_t)dest & PAGEOFFSET);
270*17169044Sbrutus 		cmd->dp.copy.cc_dest = ptob64(hat_getpfnum(kas.a_hat,
271*17169044Sbrutus 		    (caddr_t)dest)) + ((uintptr_t)dest & PAGEOFFSET);
272*17169044Sbrutus 		cmd->dp.copy.cc_size = PAGESIZE;
273*17169044Sbrutus 
274*17169044Sbrutus 		e = dcopy_cmd_post(cmd);
275*17169044Sbrutus 		if (e != DCOPY_SUCCESS) {
276*17169044Sbrutus 			cmn_err(CE_CONT, "dcopy_post() failed\n");
277*17169044Sbrutus 			goto testfail_post;
278*17169044Sbrutus 		}
279*17169044Sbrutus 	}
280*17169044Sbrutus 
281*17169044Sbrutus 	e = dcopy_cmd_alloc(channel, flags, &cmd);
282*17169044Sbrutus 	if (e != DCOPY_SUCCESS) {
283*17169044Sbrutus 		cmn_err(CE_CONT, "dcopy_cmd_alloc() failed\n");
284*17169044Sbrutus 		goto testfail_alloc;
285*17169044Sbrutus 	}
286*17169044Sbrutus 
287*17169044Sbrutus 	/* now queue up the DMA we are going to check status and data for  */
288*17169044Sbrutus 	cmd->dp_cmd = DCOPY_CMD_COPY;
289*17169044Sbrutus 	cmd->dp_flags = DCOPY_CMD_INTR;
290*17169044Sbrutus 	cmd->dp.copy.cc_source = ptob64(hat_getpfnum(kas.a_hat,
291*17169044Sbrutus 	    (caddr_t)source)) + ((uintptr_t)source & PAGEOFFSET);
292*17169044Sbrutus 	cmd->dp.copy.cc_dest = ptob64(hat_getpfnum(kas.a_hat,
293*17169044Sbrutus 	    (caddr_t)dest)) + ((uintptr_t)dest & PAGEOFFSET);
294*17169044Sbrutus 	cmd->dp.copy.cc_size = PAGESIZE;
295*17169044Sbrutus 	e = dcopy_cmd_post(cmd);
296*17169044Sbrutus 	if (e != DCOPY_SUCCESS) {
297*17169044Sbrutus 		cmn_err(CE_CONT, "dcopy_post() failed\n");
298*17169044Sbrutus 		goto testfail_post;
299*17169044Sbrutus 	}
300*17169044Sbrutus 
301*17169044Sbrutus 	/* check the status of the last command */
302*17169044Sbrutus 	poll_cnt = 0;
303*17169044Sbrutus 	flags = DCOPY_POLL_NOFLAGS;
304*17169044Sbrutus 	while ((e = dcopy_cmd_poll(cmd, flags)) == DCOPY_PENDING) {
305*17169044Sbrutus 		poll_cnt++;
306*17169044Sbrutus 		if (poll_cnt >= 16) {
307*17169044Sbrutus 			flags |= DCOPY_POLL_BLOCK;
308*17169044Sbrutus 		}
309*17169044Sbrutus 	}
310*17169044Sbrutus 	if (e != DCOPY_COMPLETED) {
311*17169044Sbrutus 		cmn_err(CE_CONT, "dcopy_poll() failed\n");
312*17169044Sbrutus 		goto testfail_poll;
313*17169044Sbrutus 	}
314*17169044Sbrutus 
315*17169044Sbrutus 	/* since the cmd's are linked we only need to pass in the last cmd */
316*17169044Sbrutus 	dcopy_cmd_free(&cmd);
317*17169044Sbrutus 	dcopy_free(&channel);
318*17169044Sbrutus 
319*17169044Sbrutus 	/* verify the data */
320*17169044Sbrutus 	for (i = 0; i < PAGESIZE; i++) {
321*17169044Sbrutus 		if (dest[i] != (uint8_t)(i & 0xFF)) {
322*17169044Sbrutus 			cmn_err(CE_CONT,
323*17169044Sbrutus 			    "dcopy_data_compare() failed, %p[%d]: %x, %x\n",
324*17169044Sbrutus 			    (void *)dest, i, dest[i], i & 0xFF);
325*17169044Sbrutus 			return (-1);
326*17169044Sbrutus 		}
327*17169044Sbrutus 	}
328*17169044Sbrutus 
329*17169044Sbrutus 	kmem_free(buf, (buf_size * 2) + 0x1000);
330*17169044Sbrutus 
331*17169044Sbrutus 	return (0);
332*17169044Sbrutus 
333*17169044Sbrutus testfail_data_compare:
334*17169044Sbrutus testfail_poll:
335*17169044Sbrutus testfail_post:
336*17169044Sbrutus 	dcopy_cmd_free(&cmd);
337*17169044Sbrutus 	dcopy_free(&channel);
338*17169044Sbrutus testfail_alloc:
339*17169044Sbrutus 	kmem_free(buf, (buf_size * 2) + 0x1000);
340*17169044Sbrutus 
341*17169044Sbrutus 	return (-1);
342*17169044Sbrutus }
343*17169044Sbrutus #endif
344