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 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 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 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 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