#include <sys/errno.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/ddi.h>
#include <sys/stat.h>
#include <sys/sunddi.h>
#include <sys/file.h>
#include <sys/open.h>
#include <sys/modctl.h>
#include <sys/ddi_impldefs.h>
#include <sys/sysmacros.h>
#include <vm/hat.h>
#include <vm/as.h>
#include <sys/ioat.h>
extern void *ioat_statep;
#define ptob64(x) (((uint64_t)(x)) << PAGESHIFT)
static int ioat_ioctl_rdreg(ioat_state_t *state, void *arg, int mode);
#ifdef DEBUG
static int ioat_ioctl_wrreg(ioat_state_t *state, void *arg, int mode);
static int ioat_ioctl_test(ioat_state_t *state, void *arg, int mode);
#endif
int
ioat_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rval)
{
ioat_state_t *state;
int instance;
int e;
e = drv_priv(cred);
if (e != 0) {
return (EPERM);
}
instance = getminor(dev);
if (instance == -1) {
return (EBADF);
}
state = ddi_get_soft_state(ioat_statep, instance);
if (state == NULL) {
return (EBADF);
}
switch (cmd) {
case IOAT_IOCTL_READ_REG:
e = ioat_ioctl_rdreg(state, (void *)arg, mode);
break;
#ifdef DEBUG
case IOAT_IOCTL_WRITE_REG:
e = ioat_ioctl_wrreg(state, (void *)arg, mode);
break;
case IOAT_IOCTL_TEST:
e = ioat_ioctl_test(state, (void *)arg, mode);
break;
#endif
default:
e = ENXIO;
}
return (e);
}
static int
ioat_ioctl_rdreg(ioat_state_t *state, void *arg, int mode)
{
ioat_ioctl_rdreg_t rdreg;
int e;
e = ddi_copyin(arg, &rdreg, sizeof (ioat_ioctl_rdreg_t), mode);
if (e != 0) {
return (EFAULT);
}
switch (rdreg.size) {
case 8:
rdreg.data = (uint64_t)ddi_get8(state->is_reg_handle,
(uint8_t *)&state->is_genregs[rdreg.addr]);
break;
case 16:
rdreg.data = (uint64_t)ddi_get16(state->is_reg_handle,
(uint16_t *)&state->is_genregs[rdreg.addr]);
break;
case 32:
rdreg.data = (uint64_t)ddi_get32(state->is_reg_handle,
(uint32_t *)&state->is_genregs[rdreg.addr]);
break;
case 64:
rdreg.data = (uint64_t)ddi_get64(state->is_reg_handle,
(uint64_t *)&state->is_genregs[rdreg.addr]);
break;
default:
return (EFAULT);
}
e = ddi_copyout(&rdreg, arg, sizeof (ioat_ioctl_rdreg_t), mode);
if (e != 0) {
return (EFAULT);
}
return (0);
}
#ifdef DEBUG
static int
ioat_ioctl_wrreg(ioat_state_t *state, void *arg, int mode)
{
ioat_ioctl_wrreg_t wrreg;
int e;
e = ddi_copyin(arg, &wrreg, sizeof (ioat_ioctl_wrreg_t), mode);
if (e != 0) {
return (EFAULT);
}
switch (wrreg.size) {
case 8:
ddi_put8(state->is_reg_handle,
(uint8_t *)&state->is_genregs[wrreg.addr],
(uint8_t)wrreg.data);
break;
case 16:
ddi_put16(state->is_reg_handle,
(uint16_t *)&state->is_genregs[wrreg.addr],
(uint16_t)wrreg.data);
break;
case 32:
ddi_put32(state->is_reg_handle,
(uint32_t *)&state->is_genregs[wrreg.addr],
(uint32_t)wrreg.data);
break;
case 64:
ddi_put64(state->is_reg_handle,
(uint64_t *)&state->is_genregs[wrreg.addr],
(uint64_t)wrreg.data);
break;
default:
return (EFAULT);
}
return (0);
}
static int
ioat_ioctl_test(ioat_state_t *state, void *arg, int mode)
{
dcopy_handle_t channel;
dcopy_cmd_t cmd;
uint8_t *source;
uint_t buf_size;
uint_t poll_cnt;
uint8_t *dest;
uint8_t *buf;
int flags;
int i;
int e;
buf_size = 0x1000;
buf = kmem_zalloc((buf_size * 2) + 0x1000, KM_SLEEP);
source = (uint8_t *)(((uintptr_t)buf + PAGEOFFSET) & PAGEMASK);
dest = source + buf_size;
for (i = 0; i < buf_size; i++) {
source[i] = (uint8_t)(i & 0xFF);
}
e = dcopy_alloc(DCOPY_SLEEP, &channel);
if (e != DCOPY_SUCCESS) {
cmn_err(CE_CONT, "dcopy_alloc() failed\n");
goto testfail_alloc;
}
flags = DCOPY_SLEEP;
for (i = 0; i < 32; i++) {
if (i == 1) {
flags |= DCOPY_ALLOC_LINK;
}
e = dcopy_cmd_alloc(channel, flags, &cmd);
if (e != DCOPY_SUCCESS) {
cmn_err(CE_CONT, "dcopy_cmd_alloc() failed\n");
goto testfail_alloc;
}
ASSERT(cmd->dp_version == DCOPY_CMD_V0);
cmd->dp_cmd = DCOPY_CMD_COPY;
cmd->dp_flags = DCOPY_CMD_NOFLAGS;
cmd->dp.copy.cc_source = ptob64(hat_getpfnum(kas.a_hat,
(caddr_t)source)) + ((uintptr_t)dest & PAGEOFFSET);
cmd->dp.copy.cc_dest = ptob64(hat_getpfnum(kas.a_hat,
(caddr_t)dest)) + ((uintptr_t)dest & PAGEOFFSET);
cmd->dp.copy.cc_size = PAGESIZE;
e = dcopy_cmd_post(cmd);
if (e != DCOPY_SUCCESS) {
cmn_err(CE_CONT, "dcopy_post() failed\n");
goto testfail_post;
}
}
e = dcopy_cmd_alloc(channel, flags, &cmd);
if (e != DCOPY_SUCCESS) {
cmn_err(CE_CONT, "dcopy_cmd_alloc() failed\n");
goto testfail_alloc;
}
cmd->dp_cmd = DCOPY_CMD_COPY;
cmd->dp_flags = DCOPY_CMD_INTR;
cmd->dp.copy.cc_source = ptob64(hat_getpfnum(kas.a_hat,
(caddr_t)source)) + ((uintptr_t)source & PAGEOFFSET);
cmd->dp.copy.cc_dest = ptob64(hat_getpfnum(kas.a_hat,
(caddr_t)dest)) + ((uintptr_t)dest & PAGEOFFSET);
cmd->dp.copy.cc_size = PAGESIZE;
e = dcopy_cmd_post(cmd);
if (e != DCOPY_SUCCESS) {
cmn_err(CE_CONT, "dcopy_post() failed\n");
goto testfail_post;
}
poll_cnt = 0;
flags = DCOPY_POLL_NOFLAGS;
while ((e = dcopy_cmd_poll(cmd, flags)) == DCOPY_PENDING) {
poll_cnt++;
if (poll_cnt >= 16) {
flags |= DCOPY_POLL_BLOCK;
}
}
if (e != DCOPY_COMPLETED) {
cmn_err(CE_CONT, "dcopy_poll() failed\n");
goto testfail_poll;
}
dcopy_cmd_free(&cmd);
dcopy_free(&channel);
for (i = 0; i < PAGESIZE; i++) {
if (dest[i] != (uint8_t)(i & 0xFF)) {
cmn_err(CE_CONT,
"dcopy_data_compare() failed, %p[%d]: %x, %x\n",
(void *)dest, i, dest[i], i & 0xFF);
return (-1);
}
}
kmem_free(buf, (buf_size * 2) + 0x1000);
return (0);
testfail_poll:
testfail_post:
dcopy_cmd_free(&cmd);
dcopy_free(&channel);
testfail_alloc:
kmem_free(buf, (buf_size * 2) + 0x1000);
return (-1);
}
#endif