4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/errno.h>
30 #include <sys/types.h>
35 #include <sys/sunddi.h>
38 #include <sys/modctl.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/sysmacros.h>
48 extern void *ioat_statep
;
49 #define ptob64(x) (((uint64_t)(x)) << PAGESHIFT)
51 static int ioat_ioctl_rdreg(ioat_state_t
*state
, void *arg
, int mode
);
53 static int ioat_ioctl_wrreg(ioat_state_t
*state
, void *arg
, int mode
);
54 static int ioat_ioctl_test(ioat_state_t
*state
, void *arg
, int mode
);
62 ioat_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*cred
, int *rval
)
73 instance
= getminor(dev
);
77 state
= ddi_get_soft_state(ioat_statep
, instance
);
83 case IOAT_IOCTL_READ_REG
:
84 e
= ioat_ioctl_rdreg(state
, (void *)arg
, mode
);
87 case IOAT_IOCTL_WRITE_REG
:
88 e
= ioat_ioctl_wrreg(state
, (void *)arg
, mode
);
91 e
= ioat_ioctl_test(state
, (void *)arg
, mode
);
107 ioat_ioctl_rdreg(ioat_state_t
*state
, void *arg
, int mode
)
109 ioat_ioctl_rdreg_t rdreg
;
113 e
= ddi_copyin(arg
, &rdreg
, sizeof (ioat_ioctl_rdreg_t
), mode
);
119 * read a device register, where size is read size in bits, addr is
120 * the offset into MMIO registers.
122 switch (rdreg
.size
) {
124 rdreg
.data
= (uint64_t)ddi_get8(state
->is_reg_handle
,
125 (uint8_t *)&state
->is_genregs
[rdreg
.addr
]);
128 rdreg
.data
= (uint64_t)ddi_get16(state
->is_reg_handle
,
129 (uint16_t *)&state
->is_genregs
[rdreg
.addr
]);
132 rdreg
.data
= (uint64_t)ddi_get32(state
->is_reg_handle
,
133 (uint32_t *)&state
->is_genregs
[rdreg
.addr
]);
136 rdreg
.data
= (uint64_t)ddi_get64(state
->is_reg_handle
,
137 (uint64_t *)&state
->is_genregs
[rdreg
.addr
]);
143 e
= ddi_copyout(&rdreg
, arg
, sizeof (ioat_ioctl_rdreg_t
), mode
);
157 ioat_ioctl_wrreg(ioat_state_t
*state
, void *arg
, int mode
)
159 ioat_ioctl_wrreg_t wrreg
;
163 e
= ddi_copyin(arg
, &wrreg
, sizeof (ioat_ioctl_wrreg_t
), mode
);
169 * write a device register, where size is write size in bits, addr is
170 * the offset into MMIO registers.
172 switch (wrreg
.size
) {
174 ddi_put8(state
->is_reg_handle
,
175 (uint8_t *)&state
->is_genregs
[wrreg
.addr
],
176 (uint8_t)wrreg
.data
);
179 ddi_put16(state
->is_reg_handle
,
180 (uint16_t *)&state
->is_genregs
[wrreg
.addr
],
181 (uint16_t)wrreg
.data
);
184 ddi_put32(state
->is_reg_handle
,
185 (uint32_t *)&state
->is_genregs
[wrreg
.addr
],
186 (uint32_t)wrreg
.data
);
189 ddi_put64(state
->is_reg_handle
,
190 (uint64_t *)&state
->is_genregs
[wrreg
.addr
],
191 (uint64_t)wrreg
.data
);
206 ioat_ioctl_test(ioat_state_t
*state
, void *arg
, int mode
)
208 dcopy_handle_t channel
;
220 /* allocate 2 paged aligned 4k pages */
222 buf
= kmem_zalloc((buf_size
* 2) + 0x1000, KM_SLEEP
);
223 source
= (uint8_t *)(((uintptr_t)buf
+ PAGEOFFSET
) & PAGEMASK
);
224 dest
= source
+ buf_size
;
226 /* Init source buffer */
227 for (i
= 0; i
< buf_size
; i
++) {
228 source
[i
] = (uint8_t)(i
& 0xFF);
231 /* allocate a DMA channel */
232 e
= dcopy_alloc(DCOPY_SLEEP
, &channel
);
233 if (e
!= DCOPY_SUCCESS
) {
234 cmn_err(CE_CONT
, "dcopy_alloc() failed\n");
239 * post 32 DMA copy's from dest to dest. These will complete in order
240 * so they won't stomp on each other. We don't care about the data
241 * right now which is why we go dest to dest.
244 for (i
= 0; i
< 32; i
++) {
246 * if this is the second command, link the commands from here
247 * on out. We only want to keep track of the last command. We
248 * will poll on the last command completing (which infers that
249 * the other commands completed). If any of the previous
250 * commands fail, so will the last one. Linking the commands
251 * also allows us to only call free for the last command. free
252 * will free up the entire chain of commands.
255 flags
|= DCOPY_ALLOC_LINK
;
257 e
= dcopy_cmd_alloc(channel
, flags
, &cmd
);
258 if (e
!= DCOPY_SUCCESS
) {
259 cmn_err(CE_CONT
, "dcopy_cmd_alloc() failed\n");
263 ASSERT(cmd
->dp_version
== DCOPY_CMD_V0
);
264 cmd
->dp_cmd
= DCOPY_CMD_COPY
;
265 cmd
->dp_flags
= DCOPY_CMD_NOFLAGS
;
267 /* do a bunch of dest to dest DMA's */
268 cmd
->dp
.copy
.cc_source
= ptob64(hat_getpfnum(kas
.a_hat
,
269 (caddr_t
)source
)) + ((uintptr_t)dest
& PAGEOFFSET
);
270 cmd
->dp
.copy
.cc_dest
= ptob64(hat_getpfnum(kas
.a_hat
,
271 (caddr_t
)dest
)) + ((uintptr_t)dest
& PAGEOFFSET
);
272 cmd
->dp
.copy
.cc_size
= PAGESIZE
;
274 e
= dcopy_cmd_post(cmd
);
275 if (e
!= DCOPY_SUCCESS
) {
276 cmn_err(CE_CONT
, "dcopy_post() failed\n");
281 e
= dcopy_cmd_alloc(channel
, flags
, &cmd
);
282 if (e
!= DCOPY_SUCCESS
) {
283 cmn_err(CE_CONT
, "dcopy_cmd_alloc() failed\n");
287 /* now queue up the DMA we are going to check status and data for */
288 cmd
->dp_cmd
= DCOPY_CMD_COPY
;
289 cmd
->dp_flags
= DCOPY_CMD_INTR
;
290 cmd
->dp
.copy
.cc_source
= ptob64(hat_getpfnum(kas
.a_hat
,
291 (caddr_t
)source
)) + ((uintptr_t)source
& PAGEOFFSET
);
292 cmd
->dp
.copy
.cc_dest
= ptob64(hat_getpfnum(kas
.a_hat
,
293 (caddr_t
)dest
)) + ((uintptr_t)dest
& PAGEOFFSET
);
294 cmd
->dp
.copy
.cc_size
= PAGESIZE
;
295 e
= dcopy_cmd_post(cmd
);
296 if (e
!= DCOPY_SUCCESS
) {
297 cmn_err(CE_CONT
, "dcopy_post() failed\n");
301 /* check the status of the last command */
303 flags
= DCOPY_POLL_NOFLAGS
;
304 while ((e
= dcopy_cmd_poll(cmd
, flags
)) == DCOPY_PENDING
) {
306 if (poll_cnt
>= 16) {
307 flags
|= DCOPY_POLL_BLOCK
;
310 if (e
!= DCOPY_COMPLETED
) {
311 cmn_err(CE_CONT
, "dcopy_poll() failed\n");
315 /* since the cmd's are linked we only need to pass in the last cmd */
316 dcopy_cmd_free(&cmd
);
317 dcopy_free(&channel
);
319 /* verify the data */
320 for (i
= 0; i
< PAGESIZE
; i
++) {
321 if (dest
[i
] != (uint8_t)(i
& 0xFF)) {
323 "dcopy_data_compare() failed, %p[%d]: %x, %x\n",
324 (void *)dest
, i
, dest
[i
], i
& 0xFF);
329 kmem_free(buf
, (buf_size
* 2) + 0x1000);
333 testfail_data_compare
:
336 dcopy_cmd_free(&cmd
);
337 dcopy_free(&channel
);
339 kmem_free(buf
, (buf_size
* 2) + 0x1000);