#include <sys/kmem.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/1394/h1394.h>
#include <sys/1394/ixl1394.h>
#include <sys/1394/adapters/hci1394.h>
#define HCI1394_IXL_PAGESIZE 8000
#define IXL1394_OP_INVALID (0 | IXL1394_OPTY_OTHER)
int hci1394_ixl_max_noadv_intrs = 8;
static void hci1394_compile_ixl_init(hci1394_comp_ixl_vars_t *wvp,
hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp,
ixl1394_command_t *ixlp);
static void hci1394_compile_ixl_endup(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_parse_ixl(hci1394_comp_ixl_vars_t *wvp,
ixl1394_command_t *ixlp);
static void hci1394_finalize_all_xfer_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_finalize_cur_xfer_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_recv_pkt_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_recv_buf_ppb_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_recv_buf_fill_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_xmit_pkt_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_xmit_buf_desc(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_bld_xmit_hdronly_nopkt_desc(hci1394_comp_ixl_vars_t *wvp);
static int hci1394_bld_dma_mem_desc_blk(hci1394_comp_ixl_vars_t *wvp,
caddr_t *dma_descpp, uint32_t *dma_desc_bound);
static void hci1394_set_xmit_pkt_hdr(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_set_xmit_skip_mode(hci1394_comp_ixl_vars_t *wvp);
static void hci1394_set_xmit_storevalue_desc(hci1394_comp_ixl_vars_t *wvp);
static int hci1394_set_next_xfer_buf(hci1394_comp_ixl_vars_t *wvp,
uint32_t bufp, uint16_t size);
static int hci1394_flush_end_desc_check(hci1394_comp_ixl_vars_t *wvp,
uint32_t count);
static int hci1394_flush_hci_cache(hci1394_comp_ixl_vars_t *wvp);
static uint32_t hci1394_alloc_storevalue_dma_mem(hci1394_comp_ixl_vars_t *wvp);
static hci1394_xfer_ctl_t *hci1394_alloc_xfer_ctl(hci1394_comp_ixl_vars_t *wvp,
uint32_t dmacnt);
static void *hci1394_alloc_dma_mem(hci1394_comp_ixl_vars_t *wvp,
uint32_t size, uint32_t *dma_bound);
static boolean_t hci1394_is_opcode_valid(uint16_t ixlopcode);
int
hci1394_compile_ixl(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp,
ixl1394_command_t *ixlp, int *resultp)
{
hci1394_comp_ixl_vars_t wv;
ASSERT(soft_statep != NULL);
ASSERT(ctxtp != NULL);
hci1394_compile_ixl_init(&wv, soft_statep, ctxtp, ixlp);
hci1394_parse_ixl(&wv, ixlp);
if (wv.dma_bld_error == 0) {
hci1394_finalize_all_xfer_desc(&wv);
}
hci1394_compile_ixl_endup(&wv);
*resultp = wv.dma_bld_error;
if (*resultp != 0)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static void
hci1394_compile_ixl_init(hci1394_comp_ixl_vars_t *wvp,
hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp,
ixl1394_command_t *ixlp)
{
wvp->soft_statep = soft_statep;
wvp->ctxtp = ctxtp;
ctxtp->dma_mem_execp = 0;
ctxtp->dma_firstp = NULL;
ctxtp->dma_last_time = 0;
ctxtp->xcs_firstp = NULL;
ctxtp->ixl_exec_depth = 0;
ctxtp->ixl_execp = NULL;
ctxtp->ixl_firstp = ixlp;
ctxtp->default_skipxferp = NULL;
ctxtp->max_noadv_intrs = hci1394_ixl_max_noadv_intrs;
wvp->xcs_firstp = NULL;
wvp->xcs_currentp = NULL;
wvp->dma_firstp = NULL;
wvp->dma_currentp = NULL;
wvp->dma_bld_error = 0;
wvp->ixl_io_mode = ctxtp->ctxt_flags;
wvp->ixl_cur_cmdp = NULL;
wvp->ixl_cur_xfer_stp = NULL;
wvp->ixl_cur_labelp = NULL;
wvp->ixl_xfer_st_cnt = 0;
wvp->xfer_state = XFER_NONE;
wvp->xfer_hci_flush = 0;
wvp->xfer_pktlen = 0;
wvp->xfer_bufcnt = 0;
wvp->descriptors = 0;
wvp->ixl_setsyncwait_cnt = 0;
wvp->ixl_settagsync_cmdp = NULL;
wvp->ixl_setskipmode_cmdp = NULL;
wvp->default_skipmode = ctxtp->default_skipmode;
wvp->default_skiplabelp = ctxtp->default_skiplabelp;
wvp->default_skipxferp = NULL;
wvp->skipmode = ctxtp->default_skipmode;
wvp->skiplabelp = NULL;
wvp->skipxferp = NULL;
wvp->default_tag = ctxtp->default_tag;
wvp->default_sync = ctxtp->default_sync;
wvp->storevalue_bufp = hci1394_alloc_storevalue_dma_mem(wvp);
wvp->storevalue_data = 0;
wvp->xmit_pkthdr1 = 0;
wvp->xmit_pkthdr2 = 0;
}
static void
hci1394_compile_ixl_endup(hci1394_comp_ixl_vars_t *wvp)
{
ixl1394_command_t *ixl_exec_stp;
hci1394_idma_desc_mem_t *dma_nextp;
int err;
if ((wvp->dma_bld_error == 0) && (wvp->ixl_xfer_st_cnt == 0)) {
wvp->dma_bld_error = IXL1394_ENO_DATA_PKTS;
}
if (wvp->dma_bld_error == 0) {
err = hci1394_ixl_find_next_exec_xfer(wvp->ctxtp->ixl_firstp,
NULL, &ixl_exec_stp);
if ((err == DDI_FAILURE) || (ixl_exec_stp == NULL)) {
wvp->dma_bld_error = IXL1394_ENO_DATA_PKTS;
}
}
dma_nextp = wvp->ctxtp->dma_firstp;
while (dma_nextp != NULL) {
err = ddi_dma_sync(dma_nextp->mem.bi_dma_handle,
(off_t)dma_nextp->mem.bi_kaddr, dma_nextp->mem.bi_length,
DDI_DMA_SYNC_FORDEV);
if (err != DDI_SUCCESS) {
wvp->dma_bld_error = IXL1394_EINTERNAL_ERROR;
break;
}
dma_nextp = dma_nextp->dma_nextp;
}
if (wvp->dma_bld_error != 0) {
wvp->ctxtp->xcs_firstp = (void *)wvp->xcs_firstp;
wvp->ctxtp->dma_firstp = wvp->dma_firstp;
hci1394_ixl_cleanup(wvp->soft_statep, wvp->ctxtp);
return;
}
wvp->ctxtp->default_skipxferp = wvp->default_skipxferp;
wvp->ctxtp->dma_mem_execp = 0;
wvp->ctxtp->dma_mem_execp = (uint32_t)((hci1394_xfer_ctl_t *)
ixl_exec_stp->compiler_privatep)->dma[0].dma_bound;
wvp->ctxtp->xcs_firstp = (void *)wvp->xcs_firstp;
wvp->ctxtp->dma_firstp = wvp->dma_firstp;
wvp->ctxtp->dma_last_time = 0;
wvp->ctxtp->ixl_exec_depth = 0;
wvp->ctxtp->ixl_execp = NULL;
}
static void
hci1394_parse_ixl(hci1394_comp_ixl_vars_t *wvp, ixl1394_command_t *ixlp)
{
ixl1394_command_t *ixlnextp = ixlp;
ixl1394_command_t *ixlcurp = NULL;
uint16_t ixlopcode = 0;
uint32_t pktsize;
uint32_t pktcnt;
while ((ixlnextp != NULL) && (wvp->dma_bld_error == 0)) {
wvp->ixl_cur_cmdp = ixlcurp = ixlnextp;
ixlnextp = ixlcurp->next_ixlp;
ixlopcode = ixlcurp->ixl_opcode;
ixlcurp->compiler_privatep = NULL;
ixlcurp->compiler_resv = 0;
if ((((wvp->ixl_io_mode & HCI1394_ISO_CTXT_RECV) != 0) &&
((ixlopcode & IXL1394_OPF_ONRECV) == 0)) ||
(((wvp->ixl_io_mode & HCI1394_ISO_CTXT_RECV) == 0) &&
((ixlopcode & IXL1394_OPF_ONXMIT) == 0))) {
if (hci1394_is_opcode_valid(ixlopcode) != B_TRUE) {
wvp->dma_bld_error = IXL1394_EBAD_IXL_OPCODE;
} else {
wvp->dma_bld_error = IXL1394_EWRONG_XR_CMD_MODE;
}
continue;
}
if ((ixlopcode & IXL1394_OPF_ENDSXFER) != 0) {
hci1394_finalize_cur_xfer_desc(wvp);
if (wvp->dma_bld_error != 0) {
continue;
}
}
switch (ixlopcode) {
case IXL1394_OP_RECV_BUF:
case IXL1394_OP_RECV_BUF_U: {
ixl1394_xfer_buf_t *cur_xfer_buf_ixlp;
cur_xfer_buf_ixlp = (ixl1394_xfer_buf_t *)ixlcurp;
wvp->xfer_state = XFER_BUF;
wvp->ixl_cur_xfer_stp = ixlcurp;
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_BFFILL) == 0) {
pktsize = cur_xfer_buf_ixlp->pkt_size;
pktcnt = 0;
if (pktsize != 0) {
pktcnt = cur_xfer_buf_ixlp->size /
pktsize;
}
if ((pktcnt == 0) || ((pktsize * pktcnt) !=
cur_xfer_buf_ixlp->size)) {
wvp->dma_bld_error =
IXL1394_EPKTSIZE_RATIO;
continue;
}
}
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_buf_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_buf_ixlp->size) != DDI_SUCCESS) {
continue;
}
break;
}
case IXL1394_OP_RECV_PKT_ST:
case IXL1394_OP_RECV_PKT_ST_U: {
ixl1394_xfer_pkt_t *cur_xfer_pkt_ixlp;
cur_xfer_pkt_ixlp = (ixl1394_xfer_pkt_t *)ixlcurp;
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_BFFILL) != 0) {
wvp->dma_bld_error = IXL1394_EWRONG_XR_CMD_MODE;
continue;
}
wvp->xfer_state = XFER_PKT;
wvp->ixl_cur_xfer_stp = ixlcurp;
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_pkt_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_pkt_ixlp->size) != DDI_SUCCESS) {
continue;
}
break;
}
case IXL1394_OP_RECV_PKT:
case IXL1394_OP_RECV_PKT_U: {
ixl1394_xfer_pkt_t *cur_xfer_pkt_ixlp;
cur_xfer_pkt_ixlp = (ixl1394_xfer_pkt_t *)ixlcurp;
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_BFFILL) != 0) {
wvp->dma_bld_error = IXL1394_EWRONG_XR_CMD_MODE;
continue;
}
if (wvp->xfer_state != XFER_PKT) {
wvp->dma_bld_error = IXL1394_EMISPLACED_RECV;
continue;
}
ixlcurp->compiler_privatep = (void *)
wvp->ixl_cur_xfer_stp;
ixlcurp->compiler_resv = wvp->xfer_bufcnt;
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_pkt_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_pkt_ixlp->size) != DDI_SUCCESS) {
continue;
}
if ((ixlopcode & IXL1394_OPF_UPDATE) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_XFER;
}
break;
}
case IXL1394_OP_SEND_BUF:
case IXL1394_OP_SEND_BUF_U: {
ixl1394_xfer_buf_t *cur_xfer_buf_ixlp;
cur_xfer_buf_ixlp = (ixl1394_xfer_buf_t *)ixlcurp;
wvp->xfer_state = XFER_BUF;
wvp->ixl_cur_xfer_stp = ixlcurp;
pktsize = cur_xfer_buf_ixlp->pkt_size;
pktcnt = 0;
if (pktsize != 0) {
pktcnt = cur_xfer_buf_ixlp->size / pktsize;
}
if ((pktcnt == 0) || ((pktsize * pktcnt) !=
cur_xfer_buf_ixlp->size)) {
wvp->dma_bld_error = IXL1394_EPKTSIZE_RATIO;
continue;
}
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_buf_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_buf_ixlp->size) != DDI_SUCCESS) {
continue;
}
break;
}
case IXL1394_OP_SEND_PKT_ST:
case IXL1394_OP_SEND_PKT_ST_U: {
ixl1394_xfer_pkt_t *cur_xfer_pkt_ixlp;
cur_xfer_pkt_ixlp = (ixl1394_xfer_pkt_t *)ixlcurp;
wvp->xfer_state = XFER_PKT;
wvp->ixl_cur_xfer_stp = ixlcurp;
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_pkt_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_pkt_ixlp->size) != DDI_SUCCESS) {
continue;
}
break;
}
case IXL1394_OP_SEND_PKT_WHDR_ST:
case IXL1394_OP_SEND_PKT_WHDR_ST_U: {
ixl1394_xfer_pkt_t *cur_xfer_pkt_ixlp;
cur_xfer_pkt_ixlp = (ixl1394_xfer_pkt_t *)ixlcurp;
wvp->xfer_state = XFER_PKT;
wvp->ixl_cur_xfer_stp = ixlcurp;
if (cur_xfer_pkt_ixlp->size < 4) {
wvp->dma_bld_error = IXL1394_EPKT_HDR_MISSING;
continue;
}
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_pkt_ixlp->ixl_buf.ixldmac_addr + 4,
cur_xfer_pkt_ixlp->size - 4) != DDI_SUCCESS) {
continue;
}
break;
}
case IXL1394_OP_SEND_PKT:
case IXL1394_OP_SEND_PKT_U: {
ixl1394_xfer_pkt_t *cur_xfer_pkt_ixlp;
cur_xfer_pkt_ixlp = (ixl1394_xfer_pkt_t *)ixlcurp;
if (wvp->xfer_state != XFER_PKT) {
wvp->dma_bld_error = IXL1394_EMISPLACED_SEND;
continue;
}
ixlcurp->compiler_privatep = (void *)
wvp->ixl_cur_xfer_stp;
ixlcurp->compiler_resv = wvp->xfer_bufcnt;
if (hci1394_set_next_xfer_buf(wvp,
cur_xfer_pkt_ixlp->ixl_buf.ixldmac_addr,
cur_xfer_pkt_ixlp->size) != DDI_SUCCESS) {
continue;
}
if ((ixlopcode & IXL1394_OPF_UPDATE) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_XFER;
}
break;
}
case IXL1394_OP_SEND_HDR_ONLY:
wvp->xfer_state = XMIT_HDRONLY;
wvp->ixl_cur_xfer_stp = ixlcurp;
break;
case IXL1394_OP_SEND_NO_PKT:
wvp->xfer_state = XMIT_NOPKT;
wvp->ixl_cur_xfer_stp = ixlcurp;
break;
case IXL1394_OP_JUMP:
case IXL1394_OP_JUMP_U: {
ixl1394_jump_t *cur_jump_ixlp;
cur_jump_ixlp = (ixl1394_jump_t *)ixlcurp;
if ((cur_jump_ixlp->label != NULL) &&
(cur_jump_ixlp->label->ixl_opcode !=
IXL1394_OP_LABEL)) {
wvp->dma_bld_error = IXL1394_EJUMP_NOT_TO_LABEL;
continue;
}
break;
}
case IXL1394_OP_LABEL:
wvp->ixl_cur_labelp = ixlcurp;
wvp->xfer_hci_flush |= INITIATING_LBL;
break;
case IXL1394_OP_CALLBACK:
case IXL1394_OP_CALLBACK_U:
case IXL1394_OP_STORE_TIMESTAMP:
break;
case IXL1394_OP_SET_SKIPMODE:
case IXL1394_OP_SET_SKIPMODE_U:
if (wvp->ixl_setskipmode_cmdp != NULL) {
wvp->dma_bld_error = IXL1394_EDUPLICATE_SET_CMD;
continue;
}
wvp->ixl_setskipmode_cmdp = (ixl1394_set_skipmode_t *)
ixlcurp;
if ((wvp->ixl_setskipmode_cmdp->skipmode !=
IXL1394_SKIP_TO_NEXT) &&
(wvp->ixl_setskipmode_cmdp->skipmode !=
IXL1394_SKIP_TO_SELF) &&
(wvp->ixl_setskipmode_cmdp->skipmode !=
IXL1394_SKIP_TO_STOP) &&
(wvp->ixl_setskipmode_cmdp->skipmode !=
IXL1394_SKIP_TO_LABEL)) {
wvp->dma_bld_error = IXL1394_EBAD_SKIPMODE;
continue;
}
if ((wvp->ixl_setskipmode_cmdp->skipmode ==
IXL1394_SKIP_TO_LABEL) &&
((wvp->ixl_setskipmode_cmdp->label == NULL) ||
(wvp->ixl_setskipmode_cmdp->label->ixl_opcode !=
IXL1394_OP_LABEL))) {
wvp->dma_bld_error = IXL1394_EJUMP_NOT_TO_LABEL;
continue;
}
if ((ixlopcode & IXL1394_OPF_UPDATE) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_SET;
}
break;
case IXL1394_OP_SET_TAGSYNC:
case IXL1394_OP_SET_TAGSYNC_U:
if (wvp->ixl_settagsync_cmdp != NULL) {
wvp->dma_bld_error = IXL1394_EDUPLICATE_SET_CMD;
continue;
}
wvp->ixl_settagsync_cmdp =
(ixl1394_set_tagsync_t *)ixlcurp;
if ((ixlopcode & IXL1394_OPF_UPDATE) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_SET;
}
break;
case IXL1394_OP_SET_SYNCWAIT:
wvp->ixl_setsyncwait_cnt++;
break;
default:
wvp->dma_bld_error = IXL1394_EBAD_IXL_OPCODE;
continue;
}
}
wvp->ixl_cur_cmdp = NULL;
if (wvp->dma_bld_error == 0) {
hci1394_finalize_cur_xfer_desc(wvp);
}
}
static void
hci1394_finalize_all_xfer_desc(hci1394_comp_ixl_vars_t *wvp)
{
ixl1394_command_t *ixlcurp;
ixl1394_command_t *ixlnextp;
ixl1394_command_t *ixlexecnext;
hci1394_xfer_ctl_t *xferctl_curp;
hci1394_xfer_ctl_t *xferctl_nxtp;
hci1394_desc_t *hcidescp;
ddi_acc_handle_t acc_hdl;
uint32_t temp;
uint32_t dma_execnext_addr;
uint32_t dma_skiplabel_addr;
uint32_t dma_skip_addr;
uint32_t callback_cnt;
uint16_t repcnt;
uint16_t ixlopcode;
int ii;
int err;
if (((wvp->ixl_io_mode & HCI1394_ISO_CTXT_RECV) == 0) &&
(wvp->ctxtp->default_skipmode == IXL1394_SKIP_TO_LABEL)) {
err = hci1394_ixl_find_next_exec_xfer(wvp->default_skiplabelp,
NULL, &wvp->default_skipxferp);
if (err == DDI_FAILURE) {
wvp->dma_bld_error = IXL1394_ENO_DATA_PKTS;
return;
}
}
ixlnextp = wvp->ctxtp->ixl_firstp;
while ((ixlnextp != NULL) && (wvp->dma_bld_error == 0)) {
ixlcurp = ixlnextp;
ixlnextp = ixlcurp->next_ixlp;
ixlopcode = ixlcurp->ixl_opcode & ~IXL1394_OPF_UPDATE;
if (((ixlopcode & IXL1394_OPF_ISXFER) == 0) ||
((ixlopcode & IXL1394_OPTY_MASK) == 0)) {
continue;
}
xferctl_curp = (hci1394_xfer_ctl_t *)ixlcurp->compiler_privatep;
repcnt = xferctl_curp->cnt;
if ((xferctl_curp->ctl_flags & XCTL_LABELLED) != 0) {
hcidescp = (hci1394_desc_t *)
xferctl_curp->dma[0].dma_descp;
acc_hdl = xferctl_curp->dma[0].dma_buf->bi_handle;
temp = ddi_get32(acc_hdl, &hcidescp->hdr);
temp |= DESC_INTR_ENBL;
ddi_put32(acc_hdl, &hcidescp->hdr, temp);
}
err = hci1394_ixl_find_next_exec_xfer(ixlcurp->next_ixlp,
&callback_cnt, &ixlexecnext);
if (err == DDI_FAILURE) {
wvp->dma_bld_error = IXL1394_ENO_DATA_PKTS;
continue;
}
xferctl_curp->execp = ixlexecnext;
if (callback_cnt != 0) {
hcidescp = (hci1394_desc_t *)
xferctl_curp->dma[repcnt - 1].dma_descp;
acc_hdl =
xferctl_curp->dma[repcnt - 1].dma_buf->bi_handle;
temp = ddi_get32(acc_hdl, &hcidescp->hdr);
temp |= DESC_INTR_ENBL;
ddi_put32(acc_hdl, &hcidescp->hdr, temp);
}
dma_execnext_addr = 0;
if (ixlexecnext != NULL) {
xferctl_nxtp = (hci1394_xfer_ctl_t *)
ixlexecnext->compiler_privatep;
dma_execnext_addr = xferctl_nxtp->dma[0].dma_bound;
} else {
hcidescp = (hci1394_desc_t *)
xferctl_curp->dma[repcnt - 1].dma_descp;
acc_hdl =
xferctl_curp->dma[repcnt - 1].dma_buf->bi_handle;
temp = ddi_get32(acc_hdl, &hcidescp->hdr);
temp |= DESC_INTR_ENBL;
ddi_put32(acc_hdl, &hcidescp->hdr, temp);
}
hcidescp = (hci1394_desc_t *)
xferctl_curp->dma[repcnt - 1].dma_descp;
acc_hdl = xferctl_curp->dma[repcnt - 1].dma_buf->bi_handle;
ddi_put32(acc_hdl, &hcidescp->branch, dma_execnext_addr);
for (ii = 0; ii < repcnt - 1; ii++) {
hcidescp = (hci1394_desc_t *)
xferctl_curp->dma[ii].dma_descp;
acc_hdl = xferctl_curp->dma[ii].dma_buf->bi_handle;
ddi_put32(acc_hdl, &hcidescp->branch,
xferctl_curp->dma[ii + 1].dma_bound);
}
if ((ixlopcode & IXL1394_OPF_ONXMIT) != 0) {
wvp->ixl_setskipmode_cmdp = xferctl_curp->skipmodep;
hci1394_set_xmit_skip_mode(wvp);
dma_skiplabel_addr = 0;
if ((wvp->skipmode == IXL1394_SKIP_TO_LABEL) &&
(wvp->skipxferp != NULL)) {
xferctl_nxtp = (hci1394_xfer_ctl_t *)
wvp->skipxferp->compiler_privatep;
dma_skiplabel_addr =
xferctl_nxtp->dma[0].dma_bound;
}
for (ii = 0; ii < repcnt; ii++) {
switch (wvp->skipmode) {
case IXL1394_SKIP_TO_LABEL:
dma_skip_addr = dma_skiplabel_addr;
break;
case IXL1394_SKIP_TO_NEXT:
if (ii < repcnt - 1) {
dma_skip_addr = xferctl_curp->
dma[ii + 1].dma_bound;
} else {
dma_skip_addr =
dma_execnext_addr;
}
break;
case IXL1394_SKIP_TO_SELF:
dma_skip_addr =
xferctl_curp->dma[ii].dma_bound;
break;
case IXL1394_SKIP_TO_STOP:
default:
dma_skip_addr = 0;
break;
}
hcidescp = ((hci1394_desc_t *)
xferctl_curp->dma[ii].dma_descp);
acc_hdl =
xferctl_curp->dma[ii].dma_buf->bi_handle;
hcidescp -= ((xferctl_curp->dma[ii].dma_bound &
DESC_Z_MASK) - 1);
if (ixlopcode == IXL1394_OP_SEND_HDR_ONLY) {
hcidescp++;
}
ddi_put32(acc_hdl, &hcidescp->branch,
dma_skip_addr);
}
}
}
}
static void
hci1394_finalize_cur_xfer_desc(hci1394_comp_ixl_vars_t *wvp)
{
uint16_t ixlopcode;
uint16_t ixlopraw;
if (wvp->ixl_cur_cmdp != NULL) {
ixlopcode = wvp->ixl_cur_cmdp->ixl_opcode;
ixlopraw = ixlopcode & ~IXL1394_OPF_UPDATE;
} else {
ixlopcode = ixlopraw = IXL1394_OP_INVALID;
}
if (wvp->xfer_state == XFER_NONE) {
if ((ixlopraw == IXL1394_OP_JUMP) ||
(ixlopraw == IXL1394_OP_LABEL) ||
(wvp->ixl_cur_cmdp == NULL) ||
(wvp->ixl_cur_cmdp->next_ixlp == NULL)) {
if ((wvp->ixl_settagsync_cmdp != NULL) ||
(wvp->ixl_setskipmode_cmdp != NULL) ||
(wvp->ixl_setsyncwait_cnt != 0)) {
wvp->dma_bld_error = IXL1394_EUNAPPLIED_SET_CMD;
return;
}
}
if (ixlopcode == IXL1394_OP_JUMP_U) {
wvp->dma_bld_error = IXL1394_EUPDATE_DISALLOWED;
return;
}
return;
}
wvp->ixl_xfer_st_cnt++;
if ((wvp->ixl_cur_xfer_stp->ixl_opcode & IXL1394_OPF_UPDATE) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_XFER;
}
if ((ixlopcode == IXL1394_OP_JUMP_U) != 0) {
wvp->xfer_hci_flush |= UPDATEABLE_JUMP;
}
if (wvp->xfer_hci_flush != 0) {
if (((wvp->ixl_cur_xfer_stp->ixl_opcode &
IXL1394_OPTY_XFER_PKT_ST) != 0) || ((wvp->xfer_hci_flush &
(UPDATEABLE_XFER | UPDATEABLE_SET | INITIATING_LBL)) !=
0)) {
if (hci1394_flush_hci_cache(wvp) != DDI_SUCCESS) {
return;
}
}
}
switch (wvp->xfer_state) {
case XFER_PKT:
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_RECV) != 0) {
hci1394_bld_recv_pkt_desc(wvp);
} else {
hci1394_bld_xmit_pkt_desc(wvp);
}
break;
case XFER_BUF:
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_RECV) != 0) {
if ((wvp->ixl_io_mode & HCI1394_ISO_CTXT_BFFILL) != 0) {
hci1394_bld_recv_buf_fill_desc(wvp);
} else {
hci1394_bld_recv_buf_ppb_desc(wvp);
}
} else {
hci1394_bld_xmit_buf_desc(wvp);
}
break;
case XMIT_HDRONLY:
case XMIT_NOPKT:
hci1394_bld_xmit_hdronly_nopkt_desc(wvp);
break;
default:
wvp->dma_bld_error = IXL1394_EINTERNAL_ERROR;
}
if (wvp->dma_bld_error != 0) {
return;
}
if (ixlopraw == IXL1394_OP_JUMP) {
wvp->ixl_cur_cmdp->compiler_privatep =
(void *)wvp->ixl_cur_xfer_stp;
}
if (wvp->ixl_cur_labelp != NULL) {
((hci1394_xfer_ctl_t *)
(wvp->ixl_cur_xfer_stp->compiler_privatep))->ctl_flags |=
XCTL_LABELLED;
wvp->ixl_cur_labelp = NULL;
}
if (wvp->ixl_setskipmode_cmdp != NULL) {
((hci1394_xfer_ctl_t *)
(wvp->ixl_cur_xfer_stp->compiler_privatep))->skipmodep =
wvp->ixl_setskipmode_cmdp;
}
wvp->ixl_cur_xfer_stp = NULL;
wvp->ixl_settagsync_cmdp = NULL;
wvp->ixl_setskipmode_cmdp = NULL;
wvp->ixl_setsyncwait_cnt = 0;
wvp->descriptors = 0;
wvp->xfer_pktlen = 0;
wvp->xfer_bufcnt = 0;
wvp->xfer_hci_flush = 0;
wvp->xfer_state = XFER_NONE;
}
static void
hci1394_bld_recv_pkt_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t wait_for_sync;
uint32_t ii;
hci1394_desc_t *wv_descp;
if ((wvp->descriptors + wvp->xfer_bufcnt) > HCI1394_DESC_MAX_Z) {
wvp->dma_bld_error = IXL1394_EFRAGMENT_OFLO;
return;
}
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, 1)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
wvp->ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
if (wvp->ixl_setsyncwait_cnt > 0) {
wvp->ixl_setsyncwait_cnt = 1;
wait_for_sync = DESC_W_ENBL;
} else {
wait_for_sync = DESC_W_DSABL;
}
for (ii = 0; ii < wvp->xfer_bufcnt; ii++) {
wv_descp = &wvp->descriptor_block[wvp->descriptors];
if (ii == (wvp->xfer_bufcnt - 1)) {
HCI1394_INIT_IR_PPB_ILAST(wv_descp, DESC_HDR_STAT_ENBL,
DESC_INTR_DSABL, wait_for_sync, wvp->xfer_size[ii]);
} else {
HCI1394_INIT_IR_PPB_IMORE(wv_descp, wait_for_sync,
wvp->xfer_size[ii]);
}
wv_descp->data_addr = wvp->xfer_bufp[ii];
wv_descp->branch = 0;
wv_descp->status = (wvp->xfer_size[ii] <<
DESC_ST_RESCOUNT_SHIFT) & DESC_ST_RESCOUNT_MASK;
wvp->descriptors++;
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp, &dma_desc_bound) !=
DDI_SUCCESS) {
return;
}
xctlp->dma[0].dma_bound = dma_desc_bound;
xctlp->dma[0].dma_descp =
dma_descp + (wvp->xfer_bufcnt - 1) * sizeof (hci1394_desc_t);
xctlp->dma[0].dma_buf = &wvp->dma_currentp->mem;
}
static void
hci1394_bld_recv_buf_ppb_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
ixl1394_xfer_buf_t *local_ixl_cur_xfer_stp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t pktsize;
uint32_t pktcnt;
uint32_t wait_for_sync;
uint32_t ii;
hci1394_desc_t *wv_descp;
local_ixl_cur_xfer_stp = (ixl1394_xfer_buf_t *)wvp->ixl_cur_xfer_stp;
pktsize = local_ixl_cur_xfer_stp->pkt_size;
pktcnt = local_ixl_cur_xfer_stp->size / pktsize;
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, pktcnt)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
local_ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
if (wvp->ixl_setsyncwait_cnt > 0) {
wvp->ixl_setsyncwait_cnt = 1;
wait_for_sync = DESC_W_ENBL;
} else {
wait_for_sync = DESC_W_DSABL;
}
wv_descp = &wvp->descriptor_block[wvp->descriptors];
HCI1394_INIT_IR_PPB_ILAST(wv_descp, DESC_HDR_STAT_ENBL, DESC_INTR_DSABL,
wait_for_sync, pktsize);
wv_descp->data_addr = local_ixl_cur_xfer_stp->ixl_buf.ixldmac_addr;
wv_descp->branch = 0;
wv_descp->status = (pktsize << DESC_ST_RESCOUNT_SHIFT) &
DESC_ST_RESCOUNT_MASK;
wvp->descriptors++;
for (ii = 0; ii < pktcnt; ii++) {
if (ii == (pktcnt - 1)) {
if (hci1394_flush_end_desc_check(wvp, ii) !=
DDI_SUCCESS) {
return;
}
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp,
&dma_desc_bound) != DDI_SUCCESS) {
return;
}
xctlp->dma[ii].dma_bound = dma_desc_bound;
xctlp->dma[ii].dma_descp = dma_descp;
xctlp->dma[ii].dma_buf = &wvp->dma_currentp->mem;
wvp->descriptor_block[wvp->descriptors - 1].data_addr +=
pktsize;
}
}
static void
hci1394_bld_recv_buf_fill_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t wait_for_sync;
ixl1394_xfer_buf_t *local_ixl_cur_xfer_stp;
local_ixl_cur_xfer_stp = (ixl1394_xfer_buf_t *)wvp->ixl_cur_xfer_stp;
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, 1)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
local_ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
if (wvp->ixl_setsyncwait_cnt > 0) {
wvp->ixl_setsyncwait_cnt = 1;
wait_for_sync = DESC_W_ENBL;
} else {
wait_for_sync = DESC_W_DSABL;
}
HCI1394_INIT_IR_BF_IMORE(&wvp->descriptor_block[wvp->descriptors],
DESC_INTR_DSABL, wait_for_sync, local_ixl_cur_xfer_stp->size);
wvp->descriptor_block[wvp->descriptors].data_addr =
local_ixl_cur_xfer_stp->ixl_buf.ixldmac_addr;
wvp->descriptor_block[wvp->descriptors].branch = 0;
wvp->descriptor_block[wvp->descriptors].status =
(local_ixl_cur_xfer_stp->size << DESC_ST_RESCOUNT_SHIFT) &
DESC_ST_RESCOUNT_MASK;
wvp->descriptors++;
if (hci1394_flush_end_desc_check(wvp, 0) != DDI_SUCCESS) {
return;
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp, &dma_desc_bound)
!= DDI_SUCCESS) {
return;
}
xctlp->dma[0].dma_bound = dma_desc_bound;
xctlp->dma[0].dma_descp = dma_descp;
xctlp->dma[0].dma_buf = &wvp->dma_currentp->mem;
}
static void
hci1394_bld_xmit_pkt_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
hci1394_output_more_imm_t *wv_omi_descp;
hci1394_desc_t *wv_descp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t ii;
if ((wvp->descriptors + 2 + wvp->xfer_bufcnt) > HCI1394_DESC_MAX_Z) {
wvp->dma_bld_error = IXL1394_EFRAGMENT_OFLO;
return;
}
if (wvp->xfer_pktlen > 0xFFFF) {
wvp->dma_bld_error = IXL1394_EPKTSIZE_MAX_OFLO;
return;
}
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, 1)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
wvp->ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
hci1394_set_xmit_pkt_hdr(wvp);
wv_omi_descp = (hci1394_output_more_imm_t *)
(&wvp->descriptor_block[wvp->descriptors]);
HCI1394_INIT_IT_OMORE_IMM(wv_omi_descp);
wv_omi_descp->data_addr = 0;
wv_omi_descp->branch = 0;
wv_omi_descp->status = 0;
wv_omi_descp->q1 = wvp->xmit_pkthdr1;
wv_omi_descp->q2 = wvp->xmit_pkthdr2;
wv_omi_descp->q3 = 0;
wv_omi_descp->q4 = 0;
wvp->descriptors += 2;
for (ii = 0; ii < wvp->xfer_bufcnt; ii++) {
wv_descp = &wvp->descriptor_block[wvp->descriptors];
if (ii == (wvp->xfer_bufcnt - 1)) {
HCI1394_INIT_IT_OLAST(wv_descp, DESC_HDR_STAT_ENBL,
DESC_INTR_DSABL, wvp->xfer_size[ii]);
} else {
HCI1394_INIT_IT_OMORE(wv_descp, wvp->xfer_size[ii]);
}
wv_descp->data_addr = wvp->xfer_bufp[ii];
wv_descp->branch = 0;
wv_descp->status = 0;
wvp->descriptors++;
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp, &dma_desc_bound) !=
DDI_SUCCESS) {
return;
}
xctlp->dma[0].dma_bound = dma_desc_bound;
xctlp->dma[0].dma_descp =
dma_descp + (wvp->xfer_bufcnt + 1) * sizeof (hci1394_desc_t);
xctlp->dma[0].dma_buf = &wvp->dma_currentp->mem;
}
static void
hci1394_bld_xmit_buf_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
ixl1394_xfer_buf_t *local_ixl_cur_xfer_stp;
hci1394_output_more_imm_t *wv_omi_descp;
hci1394_desc_t *wv_descp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t pktsize;
uint32_t pktcnt;
uint32_t ii;
local_ixl_cur_xfer_stp = (ixl1394_xfer_buf_t *)wvp->ixl_cur_xfer_stp;
pktsize = local_ixl_cur_xfer_stp->pkt_size;
pktcnt = local_ixl_cur_xfer_stp->size / pktsize;
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, pktcnt)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
local_ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
wvp->xfer_pktlen = pktsize;
hci1394_set_xmit_pkt_hdr(wvp);
wv_omi_descp = (hci1394_output_more_imm_t *)
&wvp->descriptor_block[wvp->descriptors];
HCI1394_INIT_IT_OMORE_IMM(wv_omi_descp);
wv_omi_descp->data_addr = 0;
wv_omi_descp->branch = 0;
wv_omi_descp->status = 0;
wv_omi_descp->q1 = wvp->xmit_pkthdr1;
wv_omi_descp->q2 = wvp->xmit_pkthdr2;
wv_omi_descp->q3 = 0;
wv_omi_descp->q4 = 0;
wvp->descriptors += 2;
wv_descp = &wvp->descriptor_block[wvp->descriptors];
HCI1394_INIT_IT_OLAST(wv_descp, DESC_HDR_STAT_ENBL, DESC_INTR_DSABL,
pktsize);
wv_descp->data_addr = local_ixl_cur_xfer_stp->ixl_buf.ixldmac_addr;
wv_descp->branch = 0;
wv_descp->status = 0;
wvp->descriptors++;
for (ii = 0; ii < pktcnt; ii++) {
if (ii == (pktcnt - 1)) {
if (hci1394_flush_end_desc_check(wvp, ii) !=
DDI_SUCCESS) {
return;
}
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp,
&dma_desc_bound) != DDI_SUCCESS) {
return;
}
xctlp->dma[ii].dma_bound = dma_desc_bound;
xctlp->dma[ii].dma_descp = dma_descp + 2 *
sizeof (hci1394_desc_t);
xctlp->dma[ii].dma_buf = &wvp->dma_currentp->mem;
wvp->descriptor_block[wvp->descriptors - 1].data_addr +=
pktsize;
}
}
static void
hci1394_bld_xmit_hdronly_nopkt_desc(hci1394_comp_ixl_vars_t *wvp)
{
hci1394_xfer_ctl_t *xctlp;
hci1394_output_last_t *wv_ol_descp;
hci1394_output_last_imm_t *wv_oli_descp;
caddr_t dma_descp;
uint32_t dma_desc_bound;
uint32_t repcnt;
uint32_t ii;
repcnt = ((ixl1394_xmit_special_t *)wvp->ixl_cur_xfer_stp)->count;
if ((xctlp = hci1394_alloc_xfer_ctl(wvp, repcnt)) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return;
}
wvp->ixl_cur_xfer_stp->compiler_privatep = (void *)xctlp;
hci1394_set_xmit_storevalue_desc(wvp);
if ((wvp->ixl_cur_xfer_stp->ixl_opcode & ~IXL1394_OPF_UPDATE) ==
IXL1394_OP_SEND_HDR_ONLY) {
hci1394_set_xmit_pkt_hdr(wvp);
wv_oli_descp = (hci1394_output_last_imm_t *)
&wvp->descriptor_block[wvp->descriptors];
HCI1394_INIT_IT_OLAST_IMM(wv_oli_descp, DESC_HDR_STAT_ENBL,
DESC_INTR_DSABL);
wv_oli_descp->data_addr = 0;
wv_oli_descp->branch = 0;
wv_oli_descp->status = 0;
wv_oli_descp->q1 = wvp->xmit_pkthdr1;
wv_oli_descp->q2 = wvp->xmit_pkthdr2;
wv_oli_descp->q3 = 0;
wv_oli_descp->q4 = 0;
wvp->descriptors += 2;
} else {
wv_ol_descp = &wvp->descriptor_block[wvp->descriptors];
HCI1394_INIT_IT_OLAST(wv_ol_descp, DESC_HDR_STAT_ENBL,
DESC_INTR_DSABL, 0);
wv_ol_descp->data_addr = 0;
wv_ol_descp->branch = 0;
wv_ol_descp->status = 0;
wvp->descriptors++;
}
for (ii = 0; ii < repcnt; ii++) {
if (ii == (repcnt - 1)) {
if (hci1394_flush_end_desc_check(wvp, ii) !=
DDI_SUCCESS) {
return;
}
}
if (hci1394_bld_dma_mem_desc_blk(wvp, &dma_descp,
&dma_desc_bound) != DDI_SUCCESS) {
return;
}
xctlp->dma[ii].dma_bound = dma_desc_bound;
xctlp->dma[ii].dma_descp = dma_descp + sizeof (hci1394_desc_t);
xctlp->dma[ii].dma_buf = &wvp->dma_currentp->mem;
}
}
static int
hci1394_bld_dma_mem_desc_blk(hci1394_comp_ixl_vars_t *wvp, caddr_t *dma_descpp,
uint32_t *dma_desc_bound)
{
uint32_t dma_bound;
if (wvp->descriptors == 0) {
wvp->dma_bld_error = IXL1394_EINTERNAL_ERROR;
return (DDI_FAILURE);
}
*dma_descpp = (caddr_t)hci1394_alloc_dma_mem(wvp, wvp->descriptors *
sizeof (hci1394_desc_t), &dma_bound);
if (*dma_descpp == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return (DDI_FAILURE);
}
#ifdef _KERNEL
ddi_rep_put32(wvp->dma_currentp->mem.bi_handle,
(uint_t *)wvp->descriptor_block, (uint_t *)*dma_descpp,
wvp->descriptors * (sizeof (hci1394_desc_t) >> 2),
DDI_DEV_AUTOINCR);
#else
bcopy(wvp->descriptor_block, *dma_descpp,
wvp->descriptors * sizeof (hci1394_desc_t));
#endif
*dma_desc_bound = (dma_bound & ~DESC_Z_MASK) | wvp->descriptors;
return (DDI_SUCCESS);
}
static void
hci1394_set_xmit_pkt_hdr(hci1394_comp_ixl_vars_t *wvp)
{
uint16_t tag;
uint16_t sync;
if (wvp->ixl_settagsync_cmdp == NULL) {
tag = wvp->default_tag;
sync = wvp->default_sync;
} else {
tag = wvp->ixl_settagsync_cmdp->tag;
sync = wvp->ixl_settagsync_cmdp->sync;
wvp->ixl_settagsync_cmdp = NULL;
}
tag &= (DESC_PKT_TAG_MASK >> DESC_PKT_TAG_SHIFT);
sync &= (DESC_PKT_SY_MASK >> DESC_PKT_SY_SHIFT);
wvp->xmit_pkthdr1 = (wvp->ctxtp->isospd << DESC_PKT_SPD_SHIFT) |
(tag << DESC_PKT_TAG_SHIFT) | (wvp->ctxtp->isochan <<
DESC_PKT_CHAN_SHIFT) | (IEEE1394_TCODE_ISOCH <<
DESC_PKT_TCODE_SHIFT) | (sync << DESC_PKT_SY_SHIFT);
wvp->xmit_pkthdr2 = wvp->xfer_pktlen << DESC_PKT_DATALEN_SHIFT;
}
static void
hci1394_set_xmit_skip_mode(hci1394_comp_ixl_vars_t *wvp)
{
int err;
if (wvp->ixl_setskipmode_cmdp == NULL) {
wvp->skipmode = wvp->default_skipmode;
wvp->skiplabelp = wvp->default_skiplabelp;
wvp->skipxferp = wvp->default_skipxferp;
} else {
wvp->skipmode = wvp->ixl_setskipmode_cmdp->skipmode;
wvp->skiplabelp = wvp->ixl_setskipmode_cmdp->label;
wvp->skipxferp = NULL;
if (wvp->skipmode == IXL1394_SKIP_TO_LABEL) {
err = hci1394_ixl_find_next_exec_xfer(wvp->skiplabelp,
NULL, &wvp->skipxferp);
if (err == DDI_FAILURE) {
wvp->skipxferp = NULL;
wvp->dma_bld_error = IXL1394_ENO_DATA_PKTS;
}
}
wvp->ixl_setskipmode_cmdp->compiler_privatep =
(void *)wvp->skipxferp;
}
}
static void
hci1394_set_xmit_storevalue_desc(hci1394_comp_ixl_vars_t *wvp)
{
wvp->descriptors++;
HCI1394_INIT_IT_STORE(&wvp->descriptor_block[wvp->descriptors - 1],
wvp->storevalue_data);
wvp->descriptor_block[wvp->descriptors - 1].data_addr =
wvp->storevalue_bufp;
wvp->descriptor_block[wvp->descriptors - 1].branch = 0;
wvp->descriptor_block[wvp->descriptors - 1].status = 0;
}
static int
hci1394_set_next_xfer_buf(hci1394_comp_ixl_vars_t *wvp, uint32_t bufp,
uint16_t size)
{
if (bufp == 0) {
wvp->dma_bld_error = IXL1394_ENULL_BUFFER_ADDR;
return (DDI_FAILURE);
}
wvp->xfer_bufcnt++;
if (wvp->xfer_bufcnt > HCI1394_DESC_MAX_Z) {
wvp->dma_bld_error = IXL1394_EFRAGMENT_OFLO;
return (DDI_FAILURE);
}
wvp->xfer_bufp[wvp->xfer_bufcnt - 1] = bufp;
wvp->xfer_size[wvp->xfer_bufcnt - 1] = size;
wvp->xfer_pktlen += size;
return (DDI_SUCCESS);
}
static int
hci1394_flush_end_desc_check(hci1394_comp_ixl_vars_t *wvp, uint32_t count)
{
if ((count != 0) ||
((wvp->xfer_hci_flush & (UPDATEABLE_XFER | UPDATEABLE_SET |
INITIATING_LBL)) == 0)) {
if (wvp->xfer_hci_flush & UPDATEABLE_JUMP) {
if (hci1394_flush_hci_cache(wvp) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
static int
hci1394_flush_hci_cache(hci1394_comp_ixl_vars_t *wvp)
{
uint32_t dma_bound;
if (hci1394_alloc_dma_mem(wvp, sizeof (hci1394_desc_t), &dma_bound) ==
NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static uint32_t
hci1394_alloc_storevalue_dma_mem(hci1394_comp_ixl_vars_t *wvp)
{
uint32_t dma_bound;
if (hci1394_alloc_dma_mem(wvp, sizeof (hci1394_desc_t),
&dma_bound) == NULL) {
wvp->dma_bld_error = IXL1394_EMEM_ALLOC_FAIL;
return (0);
}
return (dma_bound);
}
static hci1394_xfer_ctl_t *
hci1394_alloc_xfer_ctl(hci1394_comp_ixl_vars_t *wvp, uint32_t dmacnt)
{
hci1394_xfer_ctl_t *xcsp;
#ifdef _KERNEL
if ((xcsp = (hci1394_xfer_ctl_t *)kmem_zalloc(
(sizeof (hci1394_xfer_ctl_t) + (dmacnt - 1) *
sizeof (hci1394_xfer_ctl_dma_t)), KM_NOSLEEP)) == NULL) {
return (NULL);
}
#else
if ((xcsp = (hci1394_xfer_ctl_t *)calloc(1,
sizeof (hci1394_xfer_ctl_t) + (dmacnt - 1) *
sizeof (hci1394_xfer_ctl_dma_t))) == NULL) {
return (NULL);
}
#endif
xcsp->cnt = dmacnt;
if (wvp->xcs_firstp == NULL) {
wvp->xcs_firstp = wvp->xcs_currentp = xcsp;
} else {
wvp->xcs_currentp->ctl_nextp = xcsp;
wvp->xcs_currentp = xcsp;
}
return (xcsp);
}
static void *
hci1394_alloc_dma_mem(hci1394_comp_ixl_vars_t *wvp, uint32_t size,
uint32_t *dma_bound)
{
hci1394_idma_desc_mem_t *dma_new;
hci1394_buf_parms_t parms;
hci1394_buf_info_t *memp;
void *dma_mem_ret;
int ret;
if ((wvp->dma_currentp == NULL) ||
(size > (wvp->dma_currentp->mem.bi_cookie.dmac_size -
wvp->dma_currentp->used))) {
#ifdef _KERNEL
if ((dma_new = (hci1394_idma_desc_mem_t *)
kmem_zalloc(sizeof (hci1394_idma_desc_mem_t),
KM_NOSLEEP)) == NULL) {
return (NULL);
}
if (wvp->dma_currentp != NULL) {
memp = &wvp->dma_currentp->mem;
dma_new->mem = *memp;
dma_new->offset = wvp->dma_currentp->offset +
memp->bi_cookie.dmac_size;
for (; memp->bi_cookie_count > 1;
memp->bi_cookie_count--) {
ddi_dma_nextcookie(memp->bi_dma_handle,
&dma_new->mem.bi_cookie);
if (dma_new->mem.bi_cookie.dmac_size >= size) {
dma_new->mem_handle =
wvp->dma_currentp->mem_handle;
wvp->dma_currentp->mem_handle = NULL;
dma_new->mem.bi_cookie_count--;
break;
}
dma_new->offset +=
dma_new->mem.bi_cookie.dmac_size;
}
}
if (dma_new->mem_handle == NULL) {
parms.bp_length = HCI1394_IXL_PAGESIZE;
parms.bp_max_cookies = OHCI_MAX_COOKIE;
parms.bp_alignment = 16;
ret = hci1394_buf_alloc(&wvp->soft_statep->drvinfo,
&parms, &dma_new->mem, &dma_new->mem_handle);
if (ret != DDI_SUCCESS) {
kmem_free(dma_new,
sizeof (hci1394_idma_desc_mem_t));
return (NULL);
}
if (dma_new->mem.bi_cookie.dmac_size < size) {
hci1394_buf_free(&dma_new->mem_handle);
kmem_free(dma_new,
sizeof (hci1394_idma_desc_mem_t));
return (NULL);
}
dma_new->offset = 0;
}
#else
if ((dma_new = (hci1394_idma_desc_mem_t *)
calloc(1, sizeof (hci1394_idma_desc_mem_t))) == NULL) {
return (NULL);
}
dma_new->mem.bi_dma_handle = NULL;
dma_new->mem.bi_handle = NULL;
if ((dma_new->mem.bi_kaddr = (caddr_t)calloc(1,
HCI1394_IXL_PAGESIZE)) == NULL) {
return (NULL);
}
dma_new->mem.bi_cookie.dmac_address =
(unsigned long)dma_new->mem.bi_kaddr;
dma_new->mem.bi_real_length = HCI1394_IXL_PAGESIZE;
dma_new->mem.bi_cookie_count = 1;
#endif
if (wvp->dma_currentp != NULL) {
wvp->dma_currentp->dma_nextp = dma_new;
wvp->dma_currentp = dma_new;
} else {
wvp->dma_currentp = wvp->dma_firstp = dma_new;
}
}
dma_mem_ret = wvp->dma_currentp->mem.bi_kaddr +
wvp->dma_currentp->offset + wvp->dma_currentp->used;
*dma_bound = wvp->dma_currentp->mem.bi_cookie.dmac_address +
wvp->dma_currentp->used;
wvp->dma_currentp->used += size;
return (dma_mem_ret);
}
static boolean_t
hci1394_is_opcode_valid(uint16_t ixlopcode)
{
switch (ixlopcode) {
case IXL1394_OP_LABEL:
case IXL1394_OP_JUMP:
case IXL1394_OP_CALLBACK:
case IXL1394_OP_RECV_PKT:
case IXL1394_OP_RECV_PKT_ST:
case IXL1394_OP_RECV_BUF:
case IXL1394_OP_SEND_PKT:
case IXL1394_OP_SEND_PKT_ST:
case IXL1394_OP_SEND_PKT_WHDR_ST:
case IXL1394_OP_SEND_BUF:
case IXL1394_OP_SEND_HDR_ONLY:
case IXL1394_OP_SEND_NO_PKT:
case IXL1394_OP_STORE_TIMESTAMP:
case IXL1394_OP_SET_TAGSYNC:
case IXL1394_OP_SET_SKIPMODE:
case IXL1394_OP_SET_SYNCWAIT:
case IXL1394_OP_JUMP_U:
case IXL1394_OP_CALLBACK_U:
case IXL1394_OP_RECV_PKT_U:
case IXL1394_OP_RECV_PKT_ST_U:
case IXL1394_OP_RECV_BUF_U:
case IXL1394_OP_SEND_PKT_U:
case IXL1394_OP_SEND_PKT_ST_U:
case IXL1394_OP_SEND_PKT_WHDR_ST_U:
case IXL1394_OP_SEND_BUF_U:
case IXL1394_OP_SET_TAGSYNC_U:
case IXL1394_OP_SET_SKIPMODE_U:
return (B_TRUE);
default:
return (B_FALSE);
}
}