17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
23*ef7b5c7bSap * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*ef7b5c7bSap * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * hci1394_q.c
297c478bd9Sstevel@tonic-gate * This code decouples some of the OpenHCI async descriptor logic/structures
307c478bd9Sstevel@tonic-gate * from the async processing. The goal was to combine as much of the
317c478bd9Sstevel@tonic-gate * duplicate code as possible for the different type of async transfers
327c478bd9Sstevel@tonic-gate * without going too overboard.
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * There are two parts to the Q, the descriptor buffer and the data buffer.
357c478bd9Sstevel@tonic-gate * For the most part, data to be transmitted and data which is received go
367c478bd9Sstevel@tonic-gate * in the data buffers. The information of where to get the data and put
377c478bd9Sstevel@tonic-gate * the data reside in the descriptor buffers. There are exceptions to this.
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/conf.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
487c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
497c478bd9Sstevel@tonic-gate #include <sys/note.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #include <sys/1394/adapters/hci1394.h>
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate static int hci1394_q_reserve(hci1394_q_buf_t *qbuf, uint_t size,
557c478bd9Sstevel@tonic-gate uint32_t *io_addr);
567c478bd9Sstevel@tonic-gate static void hci1394_q_unreserve(hci1394_q_buf_t *qbuf);
577c478bd9Sstevel@tonic-gate static void hci1394_q_buf_setup(hci1394_q_buf_t *qbuf);
587c478bd9Sstevel@tonic-gate static void hci1394_q_reset(hci1394_q_handle_t q_handle);
597c478bd9Sstevel@tonic-gate static void hci1394_q_next_buf(hci1394_q_buf_t *qbuf);
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate static void hci1394_q_at_write_OLI(hci1394_q_handle_t q_handle,
627c478bd9Sstevel@tonic-gate hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd, hci1394_basic_pkt_t *hdr,
637c478bd9Sstevel@tonic-gate uint_t hdrsize);
647c478bd9Sstevel@tonic-gate static void hci1394_q_at_write_OMI(hci1394_q_handle_t q_handle,
657c478bd9Sstevel@tonic-gate hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd, hci1394_basic_pkt_t *hdr,
667c478bd9Sstevel@tonic-gate uint_t hdrsize);
677c478bd9Sstevel@tonic-gate static void hci1394_q_at_write_OL(hci1394_q_handle_t q_handle,
687c478bd9Sstevel@tonic-gate hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd, uint32_t io_addr,
697c478bd9Sstevel@tonic-gate uint_t datasize);
707c478bd9Sstevel@tonic-gate static void hci1394_q_at_rep_put8(hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd,
717c478bd9Sstevel@tonic-gate uint8_t *data, uint_t datasize);
727c478bd9Sstevel@tonic-gate static void hci1394_q_at_copy_from_mblk(hci1394_q_buf_t *qbuf,
737c478bd9Sstevel@tonic-gate hci1394_q_cmd_t *cmd, h1394_mblk_t *mblk);
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate static void hci1394_q_ar_write_IM(hci1394_q_handle_t q_handle,
767c478bd9Sstevel@tonic-gate hci1394_q_buf_t *qbuf, uint32_t io_addr, uint_t datasize);
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * hci1394_q_init()
827c478bd9Sstevel@tonic-gate * Initialize a Q. A Q consists of a descriptor buffer and a data buffer and
837c478bd9Sstevel@tonic-gate * can be either an AT or AR Q. hci1394_q_init() returns a handle which
847c478bd9Sstevel@tonic-gate * should be used for the reset of the hci1394_q_* calls.
857c478bd9Sstevel@tonic-gate */
867c478bd9Sstevel@tonic-gate int
hci1394_q_init(hci1394_drvinfo_t * drvinfo,hci1394_ohci_handle_t ohci_handle,hci1394_q_info_t * qinfo,hci1394_q_handle_t * q_handle)877c478bd9Sstevel@tonic-gate hci1394_q_init(hci1394_drvinfo_t *drvinfo,
887c478bd9Sstevel@tonic-gate hci1394_ohci_handle_t ohci_handle, hci1394_q_info_t *qinfo,
897c478bd9Sstevel@tonic-gate hci1394_q_handle_t *q_handle)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate hci1394_q_buf_t *desc;
927c478bd9Sstevel@tonic-gate hci1394_q_buf_t *data;
937c478bd9Sstevel@tonic-gate hci1394_buf_parms_t parms;
947c478bd9Sstevel@tonic-gate hci1394_q_t *q;
957c478bd9Sstevel@tonic-gate int status;
967c478bd9Sstevel@tonic-gate int index;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate ASSERT(drvinfo != NULL);
1007c478bd9Sstevel@tonic-gate ASSERT(qinfo != NULL);
1017c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate * allocate the memory to track this Q. Initialize the internal Q
1057c478bd9Sstevel@tonic-gate * structure.
1067c478bd9Sstevel@tonic-gate */
1077c478bd9Sstevel@tonic-gate q = kmem_alloc(sizeof (hci1394_q_t), KM_SLEEP);
1087c478bd9Sstevel@tonic-gate q->q_drvinfo = drvinfo;
1097c478bd9Sstevel@tonic-gate q->q_info = *qinfo;
1107c478bd9Sstevel@tonic-gate q->q_ohci = ohci_handle;
1117c478bd9Sstevel@tonic-gate mutex_init(&q->q_mutex, NULL, MUTEX_DRIVER, drvinfo->di_iblock_cookie);
1127c478bd9Sstevel@tonic-gate desc = &q->q_desc;
1137c478bd9Sstevel@tonic-gate data = &q->q_data;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate * Allocate the Descriptor buffer.
1177c478bd9Sstevel@tonic-gate *
1187c478bd9Sstevel@tonic-gate * XXX - Only want 1 cookie for now. Change this to OHCI_MAX_COOKIE
1197c478bd9Sstevel@tonic-gate * after we have tested the multiple cookie code on x86.
1207c478bd9Sstevel@tonic-gate */
1217c478bd9Sstevel@tonic-gate parms.bp_length = qinfo->qi_desc_size;
1227c478bd9Sstevel@tonic-gate parms.bp_max_cookies = 1;
1237c478bd9Sstevel@tonic-gate parms.bp_alignment = 16;
1247c478bd9Sstevel@tonic-gate status = hci1394_buf_alloc(drvinfo, &parms, &desc->qb_buf,
1257c478bd9Sstevel@tonic-gate &desc->qb_buf_handle);
1267c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
1277c478bd9Sstevel@tonic-gate mutex_destroy(&q->q_mutex);
1287c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (hci1394_q_t));
1297c478bd9Sstevel@tonic-gate *q_handle = NULL;
1307c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate /* Copy in buffer cookies into our local cookie array */
1347c478bd9Sstevel@tonic-gate desc->qb_cookie[0] = desc->qb_buf.bi_cookie;
1357c478bd9Sstevel@tonic-gate for (index = 1; index < desc->qb_buf.bi_cookie_count; index++) {
1367c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(desc->qb_buf.bi_dma_handle,
1377c478bd9Sstevel@tonic-gate &desc->qb_buf.bi_cookie);
1387c478bd9Sstevel@tonic-gate desc->qb_cookie[index] = desc->qb_buf.bi_cookie;
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate * Allocate the Data buffer.
1437c478bd9Sstevel@tonic-gate *
1447c478bd9Sstevel@tonic-gate * XXX - Only want 1 cookie for now. Change this to OHCI_MAX_COOKIE
1457c478bd9Sstevel@tonic-gate * after we have tested the multiple cookie code on x86.
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate parms.bp_length = qinfo->qi_data_size;
1487c478bd9Sstevel@tonic-gate parms.bp_max_cookies = 1;
1497c478bd9Sstevel@tonic-gate parms.bp_alignment = 16;
1507c478bd9Sstevel@tonic-gate status = hci1394_buf_alloc(drvinfo, &parms, &data->qb_buf,
1517c478bd9Sstevel@tonic-gate &data->qb_buf_handle);
1527c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
153*ef7b5c7bSap /* Free the allocated Descriptor buffer */
154*ef7b5c7bSap hci1394_buf_free(&desc->qb_buf_handle);
155*ef7b5c7bSap
1567c478bd9Sstevel@tonic-gate mutex_destroy(&q->q_mutex);
1577c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (hci1394_q_t));
1587c478bd9Sstevel@tonic-gate *q_handle = NULL;
1597c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate * We must have at least 2 ARQ data buffers, If we only have one, we
1647c478bd9Sstevel@tonic-gate * will artificially create 2. We must have 2 so that we always have a
1657c478bd9Sstevel@tonic-gate * descriptor with free data space to write AR data to. When one is
1667c478bd9Sstevel@tonic-gate * empty, it will take us a bit to get a new descriptor back into the
1677c478bd9Sstevel@tonic-gate * chain.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate if ((qinfo->qi_mode == HCI1394_ARQ) &&
1707c478bd9Sstevel@tonic-gate (data->qb_buf.bi_cookie_count == 1)) {
1717c478bd9Sstevel@tonic-gate data->qb_buf.bi_cookie_count = 2;
1727c478bd9Sstevel@tonic-gate data->qb_cookie[0] = data->qb_buf.bi_cookie;
1737c478bd9Sstevel@tonic-gate data->qb_cookie[0].dmac_size /= 2;
1747c478bd9Sstevel@tonic-gate data->qb_cookie[1] = data->qb_cookie[0];
1757c478bd9Sstevel@tonic-gate data->qb_cookie[1].dmac_laddress =
1767c478bd9Sstevel@tonic-gate data->qb_cookie[0].dmac_laddress +
1777c478bd9Sstevel@tonic-gate data->qb_cookie[0].dmac_size;
1787c478bd9Sstevel@tonic-gate data->qb_cookie[1].dmac_address =
1797c478bd9Sstevel@tonic-gate data->qb_cookie[0].dmac_address +
1807c478bd9Sstevel@tonic-gate data->qb_cookie[0].dmac_size;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate /* We have more than 1 cookie or we are an AT Q */
1837c478bd9Sstevel@tonic-gate } else {
1847c478bd9Sstevel@tonic-gate /* Copy in buffer cookies into our local cookie array */
1857c478bd9Sstevel@tonic-gate data->qb_cookie[0] = data->qb_buf.bi_cookie;
1867c478bd9Sstevel@tonic-gate for (index = 1; index < data->qb_buf.bi_cookie_count; index++) {
1877c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(data->qb_buf.bi_dma_handle,
1887c478bd9Sstevel@tonic-gate &data->qb_buf.bi_cookie);
1897c478bd9Sstevel@tonic-gate data->qb_cookie[index] = data->qb_buf.bi_cookie;
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /* The top and bottom of the Q are only set once */
1947c478bd9Sstevel@tonic-gate desc->qb_ptrs.qp_top = desc->qb_buf.bi_kaddr;
1957c478bd9Sstevel@tonic-gate desc->qb_ptrs.qp_bottom = desc->qb_buf.bi_kaddr +
1967c478bd9Sstevel@tonic-gate desc->qb_buf.bi_real_length - 1;
1977c478bd9Sstevel@tonic-gate data->qb_ptrs.qp_top = data->qb_buf.bi_kaddr;
1987c478bd9Sstevel@tonic-gate data->qb_ptrs.qp_bottom = data->qb_buf.bi_kaddr +
1997c478bd9Sstevel@tonic-gate data->qb_buf.bi_real_length - 1;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate * reset the Q pointers to their original settings. Setup IM
2037c478bd9Sstevel@tonic-gate * descriptors if this is an AR Q.
2047c478bd9Sstevel@tonic-gate */
2057c478bd9Sstevel@tonic-gate hci1394_q_reset(q);
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /* if this is an AT Q, create a queued list for the AT descriptors */
2087c478bd9Sstevel@tonic-gate if (qinfo->qi_mode == HCI1394_ATQ) {
2097c478bd9Sstevel@tonic-gate hci1394_tlist_init(drvinfo, NULL, &q->q_queued_list);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate *q_handle = q;
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate * hci1394_q_fini()
2207c478bd9Sstevel@tonic-gate * Cleanup after a successful hci1394_q_init(). Notice that a pointer to the
2217c478bd9Sstevel@tonic-gate * handle is used for the parameter. fini() will set your handle to NULL
2227c478bd9Sstevel@tonic-gate * before returning.
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate void
hci1394_q_fini(hci1394_q_handle_t * q_handle)2257c478bd9Sstevel@tonic-gate hci1394_q_fini(hci1394_q_handle_t *q_handle)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate hci1394_q_t *q;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate q = *q_handle;
2327c478bd9Sstevel@tonic-gate if (q->q_info.qi_mode == HCI1394_ATQ) {
2337c478bd9Sstevel@tonic-gate hci1394_tlist_fini(&q->q_queued_list);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate mutex_destroy(&q->q_mutex);
2367c478bd9Sstevel@tonic-gate hci1394_buf_free(&q->q_desc.qb_buf_handle);
2377c478bd9Sstevel@tonic-gate hci1394_buf_free(&q->q_data.qb_buf_handle);
2387c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (hci1394_q_t));
2397c478bd9Sstevel@tonic-gate *q_handle = NULL;
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate * hci1394_q_buf_setup()
2457c478bd9Sstevel@tonic-gate * Initialization of buffer pointers which are present in both the descriptor
2467c478bd9Sstevel@tonic-gate * buffer and data buffer (No reason to duplicate the code)
2477c478bd9Sstevel@tonic-gate */
2487c478bd9Sstevel@tonic-gate static void
hci1394_q_buf_setup(hci1394_q_buf_t * qbuf)2497c478bd9Sstevel@tonic-gate hci1394_q_buf_setup(hci1394_q_buf_t *qbuf)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate /* start with the first cookie */
2547c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf = 0;
2557c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin = qbuf->qb_ptrs.qp_top;
2567c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_end = qbuf->qb_ptrs.qp_begin +
2577c478bd9Sstevel@tonic-gate qbuf->qb_cookie[qbuf->qb_ptrs.qp_current_buf].dmac_size - 1;
2587c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current = qbuf->qb_ptrs.qp_begin;
2597c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = 0;
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate * The free_buf and free pointer will change everytime an ACK (of some
2637c478bd9Sstevel@tonic-gate * type) is processed. Free is the last byte in the last cookie.
2647c478bd9Sstevel@tonic-gate */
2657c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_free_buf = qbuf->qb_buf.bi_cookie_count - 1;
2667c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_free = qbuf->qb_ptrs.qp_bottom;
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate * Start with no space to write descriptors. We first need to call
2707c478bd9Sstevel@tonic-gate * hci1394_q_reserve() before calling hci1394_q_at_write_O*().
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = 0;
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate * hci1394_q_reset()
2787c478bd9Sstevel@tonic-gate * Resets the buffers to an initial state. This should be called during
2797c478bd9Sstevel@tonic-gate * attach and resume.
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate static void
hci1394_q_reset(hci1394_q_handle_t q_handle)2827c478bd9Sstevel@tonic-gate hci1394_q_reset(hci1394_q_handle_t q_handle)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate hci1394_q_buf_t *desc;
2857c478bd9Sstevel@tonic-gate hci1394_q_buf_t *data;
2867c478bd9Sstevel@tonic-gate int index;
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
2917c478bd9Sstevel@tonic-gate desc = &q_handle->q_desc;
2927c478bd9Sstevel@tonic-gate data = &q_handle->q_data;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate hci1394_q_buf_setup(desc);
2957c478bd9Sstevel@tonic-gate hci1394_q_buf_setup(data);
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /* DMA starts off stopped, no previous descriptor to link from */
2987c478bd9Sstevel@tonic-gate q_handle->q_dma_running = B_FALSE;
2997c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
3007c478bd9Sstevel@tonic-gate q_handle->q_previous = NULL;
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate /* If this is an AR Q, setup IM's for the data buffers that we have */
3037c478bd9Sstevel@tonic-gate if (q_handle->q_info.qi_mode == HCI1394_ARQ) {
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * This points to where to find the first IM descriptor. Since
3067c478bd9Sstevel@tonic-gate * we just reset the pointers in hci1394_q_buf_setup(), the
3077c478bd9Sstevel@tonic-gate * first IM we write below will be found at the top of the Q.
3087c478bd9Sstevel@tonic-gate */
3097c478bd9Sstevel@tonic-gate q_handle->q_head = desc->qb_ptrs.qp_top;
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate for (index = 0; index < data->qb_buf.bi_cookie_count; index++) {
3127c478bd9Sstevel@tonic-gate hci1394_q_ar_write_IM(q_handle, desc,
3137c478bd9Sstevel@tonic-gate data->qb_cookie[index].dmac_address,
3147c478bd9Sstevel@tonic-gate data->qb_cookie[index].dmac_size);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * The space left in the current IM is the size of the buffer.
3197c478bd9Sstevel@tonic-gate * The current buffer is the first buffer added to the AR Q.
3207c478bd9Sstevel@tonic-gate */
3217c478bd9Sstevel@tonic-gate q_handle->q_space_left = data->qb_cookie[0].dmac_size;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate /*
3297c478bd9Sstevel@tonic-gate * hci1394_q_resume()
3307c478bd9Sstevel@tonic-gate * This is called during a resume (after a successful suspend). Currently
3317c478bd9Sstevel@tonic-gate * we only call reset. Since this is not a time critical function, we will
3327c478bd9Sstevel@tonic-gate * leave this as a separate function to increase readability.
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate void
hci1394_q_resume(hci1394_q_handle_t q_handle)3357c478bd9Sstevel@tonic-gate hci1394_q_resume(hci1394_q_handle_t q_handle)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
3387c478bd9Sstevel@tonic-gate hci1394_q_reset(q_handle);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate * hci1394_q_stop()
3447c478bd9Sstevel@tonic-gate * This call informs us that a DMA engine has been stopped. It does not
3457c478bd9Sstevel@tonic-gate * perform the actual stop. We need to know this so that when we add a
3467c478bd9Sstevel@tonic-gate * new descriptor, we do a start instead of a wake.
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate void
hci1394_q_stop(hci1394_q_handle_t q_handle)3497c478bd9Sstevel@tonic-gate hci1394_q_stop(hci1394_q_handle_t q_handle)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
3527c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
3537c478bd9Sstevel@tonic-gate q_handle->q_dma_running = B_FALSE;
3547c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate * hci1394_q_reserve()
3607c478bd9Sstevel@tonic-gate * Reserve space in the AT descriptor or data buffer. This ensures that we
3617c478bd9Sstevel@tonic-gate * can get a contiguous buffer. Descriptors have to be in a contiguous
3627c478bd9Sstevel@tonic-gate * buffer. Data does not have to be in a contiguous buffer but we do this to
3637c478bd9Sstevel@tonic-gate * reduce complexity. For systems with small page sizes (e.g. x86), this
3647c478bd9Sstevel@tonic-gate * could result in inefficient use of the data buffers when sending large
3657c478bd9Sstevel@tonic-gate * data blocks (this only applies to non-physical block write ATREQs and
3667c478bd9Sstevel@tonic-gate * block read ATRESP). Since it looks like most protocols that use large data
3677c478bd9Sstevel@tonic-gate * blocks (like SPB-2), use physical transfers to do this (due to their
3687c478bd9Sstevel@tonic-gate * efficiency), this will probably not be a real world problem. If it turns
3697c478bd9Sstevel@tonic-gate * out to be a problem, the options are to force a single cookie for the data
3707c478bd9Sstevel@tonic-gate * buffer, allow multiple cookies and have a larger data space, or change the
3717c478bd9Sstevel@tonic-gate * data code to use a OMI, OM, OL descriptor sequence (instead of OMI, OL).
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate static int
hci1394_q_reserve(hci1394_q_buf_t * qbuf,uint_t size,uint32_t * io_addr)3747c478bd9Sstevel@tonic-gate hci1394_q_reserve(hci1394_q_buf_t *qbuf, uint_t size, uint32_t *io_addr)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate uint_t aligned_size;
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate /* Save backup of pointers in case we have to unreserve */
3827c478bd9Sstevel@tonic-gate qbuf->qb_backup_ptrs = qbuf->qb_ptrs;
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate * Make sure all alloc's are quadlet aligned. The data doesn't have to
3867c478bd9Sstevel@tonic-gate * be, so we will force it to be.
3877c478bd9Sstevel@tonic-gate */
3887c478bd9Sstevel@tonic-gate aligned_size = HCI1394_ALIGN_QUAD(size);
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate * if the free pointer is in the current buffer and the free pointer
3927c478bd9Sstevel@tonic-gate * is below the current pointer (i.e. has not wrapped around)
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gate if ((qbuf->qb_ptrs.qp_current_buf == qbuf->qb_ptrs.qp_free_buf) &&
3957c478bd9Sstevel@tonic-gate (qbuf->qb_ptrs.qp_free >= qbuf->qb_ptrs.qp_current)) {
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * The free pointer is in this buffer below the current pointer.
3987c478bd9Sstevel@tonic-gate * Check to see if we have enough free space left.
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate if ((qbuf->qb_ptrs.qp_current + aligned_size) <=
4017c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_free) {
4027c478bd9Sstevel@tonic-gate /* Setup up our reserved size, return the IO address */
4037c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = aligned_size;
4047c478bd9Sstevel@tonic-gate *io_addr = (uint32_t)(qbuf->qb_cookie[
4057c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf].dmac_address +
4067c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset);
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate * The free pointer is in this buffer below the current pointer.
4107c478bd9Sstevel@tonic-gate * We do not have enough free space for the alloc. Return
4117c478bd9Sstevel@tonic-gate * failure.
4127c478bd9Sstevel@tonic-gate */
4137c478bd9Sstevel@tonic-gate } else {
4147c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = 0;
4157c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * If there is not enough room to fit in the current buffer (not
4207c478bd9Sstevel@tonic-gate * including wrap around), we will go to the next buffer and check
4217c478bd9Sstevel@tonic-gate * there. If we only have one buffer (i.e. one cookie), we will end up
4227c478bd9Sstevel@tonic-gate * staying at the current buffer and wrapping the address back to the
4237c478bd9Sstevel@tonic-gate * top.
4247c478bd9Sstevel@tonic-gate */
4257c478bd9Sstevel@tonic-gate } else if ((qbuf->qb_ptrs.qp_current + aligned_size) >
4267c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_end) {
4277c478bd9Sstevel@tonic-gate /* Go to the next buffer (or the top of ours for one cookie) */
4287c478bd9Sstevel@tonic-gate hci1394_q_next_buf(qbuf);
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate /* If the free pointer is in the new current buffer */
4317c478bd9Sstevel@tonic-gate if (qbuf->qb_ptrs.qp_current_buf == qbuf->qb_ptrs.qp_free_buf) {
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * The free pointer is in this buffer. If we do not have
4347c478bd9Sstevel@tonic-gate * enough free space for the alloc. Return failure.
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate if ((qbuf->qb_ptrs.qp_current + aligned_size) >
4377c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_free) {
4387c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = 0;
4397c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * The free pointer is in this buffer. We have enough
4427c478bd9Sstevel@tonic-gate * free space left.
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate } else {
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate * Setup up our reserved size, return the IO
4477c478bd9Sstevel@tonic-gate * address
4487c478bd9Sstevel@tonic-gate */
4497c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = aligned_size;
4507c478bd9Sstevel@tonic-gate *io_addr = (uint32_t)(qbuf->qb_cookie[
4517c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf].dmac_address +
4527c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset);
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate * We switched buffers and the free pointer is still in another
4577c478bd9Sstevel@tonic-gate * buffer. We have sufficient space in this buffer for the alloc
4587c478bd9Sstevel@tonic-gate * after changing buffers.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate } else {
4617c478bd9Sstevel@tonic-gate /* Setup up our reserved size, return the IO address */
4627c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = aligned_size;
4637c478bd9Sstevel@tonic-gate *io_addr = (uint32_t)(qbuf->qb_cookie[
4647c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf].dmac_address +
4657c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * The free pointer is in another buffer. We have sufficient space in
4697c478bd9Sstevel@tonic-gate * this buffer for the alloc.
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate } else {
4727c478bd9Sstevel@tonic-gate /* Setup up our reserved size, return the IO address */
4737c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = aligned_size;
4747c478bd9Sstevel@tonic-gate *io_addr = (uint32_t)(qbuf->qb_cookie[
4757c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf].dmac_address +
4767c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * hci1394_q_unreserve()
4847c478bd9Sstevel@tonic-gate * Set the buffer pointer to what they were before hci1394_reserve(). This
4857c478bd9Sstevel@tonic-gate * will be called when we encounter errors during hci1394_q_at*().
4867c478bd9Sstevel@tonic-gate */
4877c478bd9Sstevel@tonic-gate static void
hci1394_q_unreserve(hci1394_q_buf_t * qbuf)4887c478bd9Sstevel@tonic-gate hci1394_q_unreserve(hci1394_q_buf_t *qbuf)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /* Go back to pointer setting before the reserve */
4937c478bd9Sstevel@tonic-gate qbuf->qb_ptrs = qbuf->qb_backup_ptrs;
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate /*
4987c478bd9Sstevel@tonic-gate * hci1394_q_next_buf()
4997c478bd9Sstevel@tonic-gate * Set our current buffer to the next cookie. If we only have one cookie, we
5007c478bd9Sstevel@tonic-gate * will go back to the top of our buffer.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate void
hci1394_q_next_buf(hci1394_q_buf_t * qbuf)5037c478bd9Sstevel@tonic-gate hci1394_q_next_buf(hci1394_q_buf_t *qbuf)
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate * go to the next cookie, if we are >= the cookie count, go back to the
5097c478bd9Sstevel@tonic-gate * first cookie.
5107c478bd9Sstevel@tonic-gate */
5117c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf++;
5127c478bd9Sstevel@tonic-gate if (qbuf->qb_ptrs.qp_current_buf >= qbuf->qb_buf.bi_cookie_count) {
5137c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current_buf = 0;
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /* adjust the begin, end, current, and offset pointers */
5177c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin = qbuf->qb_ptrs.qp_end + 1;
5187c478bd9Sstevel@tonic-gate if (qbuf->qb_ptrs.qp_begin > qbuf->qb_ptrs.qp_bottom) {
5197c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin = qbuf->qb_ptrs.qp_top;
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_end = qbuf->qb_ptrs.qp_begin +
5227c478bd9Sstevel@tonic-gate qbuf->qb_cookie[qbuf->qb_ptrs.qp_current_buf].dmac_size - 1;
5237c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current = qbuf->qb_ptrs.qp_begin;
5247c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = 0;
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate * hci1394_q_at()
5307c478bd9Sstevel@tonic-gate * Place an AT command that does NOT need the data buffer into the DMA chain.
5317c478bd9Sstevel@tonic-gate * Some examples of this are quadlet read/write, PHY packets, ATREQ Block
5327c478bd9Sstevel@tonic-gate * Read, and ATRESP block write. result is only valid on failure.
5337c478bd9Sstevel@tonic-gate */
5347c478bd9Sstevel@tonic-gate int
hci1394_q_at(hci1394_q_handle_t q_handle,hci1394_q_cmd_t * cmd,hci1394_basic_pkt_t * hdr,uint_t hdrsize,int * result)5357c478bd9Sstevel@tonic-gate hci1394_q_at(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
5367c478bd9Sstevel@tonic-gate hci1394_basic_pkt_t *hdr, uint_t hdrsize, int *result)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate int status;
5397c478bd9Sstevel@tonic-gate uint32_t ioaddr;
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
5437c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
5447c478bd9Sstevel@tonic-gate ASSERT(hdr != NULL);
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate * Check the HAL state and generation when the AT Q is locked. This
5507c478bd9Sstevel@tonic-gate * will make sure that we get all the commands when we flush the Q's
5517c478bd9Sstevel@tonic-gate * during a reset or shutdown.
5527c478bd9Sstevel@tonic-gate */
5537c478bd9Sstevel@tonic-gate if ((hci1394_state(q_handle->q_drvinfo) != HCI1394_NORMAL) ||
5547c478bd9Sstevel@tonic-gate (hci1394_ohci_current_busgen(q_handle->q_ohci) !=
5557c478bd9Sstevel@tonic-gate cmd->qc_generation)) {
5567c478bd9Sstevel@tonic-gate *result = H1394_STATUS_INVALID_BUSGEN;
5577c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
5587c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate /* save away the argument to pass up when this command completes */
5627c478bd9Sstevel@tonic-gate cmd->qc_node.tln_addr = cmd;
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate /* we have not written any 16 byte blocks to the descriptor yet */
5657c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate /* Reserve space for an OLI in the descriptor buffer */
5687c478bd9Sstevel@tonic-gate status = hci1394_q_reserve(&q_handle->q_desc,
5697c478bd9Sstevel@tonic-gate sizeof (hci1394_desc_imm_t), &ioaddr);
5707c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
5717c478bd9Sstevel@tonic-gate *result = H1394_STATUS_NOMORE_SPACE;
5727c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
5737c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate /* write the OLI to the descriptor buffer */
5777c478bd9Sstevel@tonic-gate hci1394_q_at_write_OLI(q_handle, &q_handle->q_desc, cmd, hdr, hdrsize);
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate /* Add the AT command to the queued list */
5807c478bd9Sstevel@tonic-gate hci1394_tlist_add(q_handle->q_queued_list, &cmd->qc_node);
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate /*
5897c478bd9Sstevel@tonic-gate * XXX - NOTE: POSSIBLE FUTURE OPTIMIZATION
5907c478bd9Sstevel@tonic-gate * ATREQ Block read and write's that go through software are not very
5917c478bd9Sstevel@tonic-gate * efficient (one of the reasons to use physical space). A copy is forced
5927c478bd9Sstevel@tonic-gate * on all block reads due to the design of OpenHCI. Writes do not have this
5937c478bd9Sstevel@tonic-gate * same restriction. This design forces a copy for writes too (we always
5947c478bd9Sstevel@tonic-gate * copy into a data buffer before sending). There are many reasons for this
5957c478bd9Sstevel@tonic-gate * including complexity reduction. There is a data size threshold where a
5967c478bd9Sstevel@tonic-gate * copy is more expensive than mapping the data buffer address (or worse
5977c478bd9Sstevel@tonic-gate * case a big enough difference where it pays to do it). However, we move
5987c478bd9Sstevel@tonic-gate * block data around in mblks which means that our data may be scattered
5997c478bd9Sstevel@tonic-gate * over many buffers. This adds to the complexity of mapping and setting
6007c478bd9Sstevel@tonic-gate * up the OpenHCI descriptors.
6017c478bd9Sstevel@tonic-gate *
6027c478bd9Sstevel@tonic-gate * If someone really needs a speedup on block write ATREQs, my recommendation
6037c478bd9Sstevel@tonic-gate * would be to add an additional command type at the target interface for a
6047c478bd9Sstevel@tonic-gate * fast block write. The target driver would pass a mapped io addr to use.
6057c478bd9Sstevel@tonic-gate * A function like "hci1394_q_at_with_ioaddr()" could be created which would
6067c478bd9Sstevel@tonic-gate * be almost an exact copy of hci1394_q_at_with_data() without the
6077c478bd9Sstevel@tonic-gate * hci1394_q_reserve() and hci1394_q_at_rep_put8() for the data buffer.
6087c478bd9Sstevel@tonic-gate */
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate /*
6127c478bd9Sstevel@tonic-gate * hci1394_q_at_with_data()
6137c478bd9Sstevel@tonic-gate * Place an AT command that does need the data buffer into the DMA chain.
6147c478bd9Sstevel@tonic-gate * The data is passed as a pointer to a kernel virtual address. An example of
6157c478bd9Sstevel@tonic-gate * this is the lock operations. result is only valid on failure.
6167c478bd9Sstevel@tonic-gate */
6177c478bd9Sstevel@tonic-gate int
hci1394_q_at_with_data(hci1394_q_handle_t q_handle,hci1394_q_cmd_t * cmd,hci1394_basic_pkt_t * hdr,uint_t hdrsize,uint8_t * data,uint_t datasize,int * result)6187c478bd9Sstevel@tonic-gate hci1394_q_at_with_data(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
6197c478bd9Sstevel@tonic-gate hci1394_basic_pkt_t *hdr, uint_t hdrsize, uint8_t *data, uint_t datasize,
6207c478bd9Sstevel@tonic-gate int *result)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate uint32_t desc_ioaddr;
6237c478bd9Sstevel@tonic-gate uint32_t data_ioaddr;
6247c478bd9Sstevel@tonic-gate int status;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
6287c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
6297c478bd9Sstevel@tonic-gate ASSERT(hdr != NULL);
6307c478bd9Sstevel@tonic-gate ASSERT(data != NULL);
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate * Check the HAL state and generation when the AT Q is locked. This
6367c478bd9Sstevel@tonic-gate * will make sure that we get all the commands when we flush the Q's
6377c478bd9Sstevel@tonic-gate * during a reset or shutdown.
6387c478bd9Sstevel@tonic-gate */
6397c478bd9Sstevel@tonic-gate if ((hci1394_state(q_handle->q_drvinfo) != HCI1394_NORMAL) ||
6407c478bd9Sstevel@tonic-gate (hci1394_ohci_current_busgen(q_handle->q_ohci) !=
6417c478bd9Sstevel@tonic-gate cmd->qc_generation)) {
6427c478bd9Sstevel@tonic-gate *result = H1394_STATUS_INVALID_BUSGEN;
6437c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
6447c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate /* save away the argument to pass up when this command completes */
6487c478bd9Sstevel@tonic-gate cmd->qc_node.tln_addr = cmd;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate /* we have not written any 16 byte blocks to the descriptor yet */
6517c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate /* Reserve space for an OMI and OL in the descriptor buffer */
6547c478bd9Sstevel@tonic-gate status = hci1394_q_reserve(&q_handle->q_desc,
6557c478bd9Sstevel@tonic-gate (sizeof (hci1394_desc_imm_t) + sizeof (hci1394_desc_t)),
6567c478bd9Sstevel@tonic-gate &desc_ioaddr);
6577c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
6587c478bd9Sstevel@tonic-gate *result = H1394_STATUS_NOMORE_SPACE;
6597c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
6607c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /* allocate space for data in the data buffer */
6647c478bd9Sstevel@tonic-gate status = hci1394_q_reserve(&q_handle->q_data, datasize, &data_ioaddr);
6657c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
6667c478bd9Sstevel@tonic-gate *result = H1394_STATUS_NOMORE_SPACE;
6677c478bd9Sstevel@tonic-gate hci1394_q_unreserve(&q_handle->q_desc);
6687c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
6697c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate /* Copy data into data buffer */
6737c478bd9Sstevel@tonic-gate hci1394_q_at_rep_put8(&q_handle->q_data, cmd, data, datasize);
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate /* write the OMI to the descriptor buffer */
6767c478bd9Sstevel@tonic-gate hci1394_q_at_write_OMI(q_handle, &q_handle->q_desc, cmd, hdr, hdrsize);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /* write the OL to the descriptor buffer */
6797c478bd9Sstevel@tonic-gate hci1394_q_at_write_OL(q_handle, &q_handle->q_desc, cmd, data_ioaddr,
6807c478bd9Sstevel@tonic-gate datasize);
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate /* Add the AT command to the queued list */
6837c478bd9Sstevel@tonic-gate hci1394_tlist_add(q_handle->q_queued_list, &cmd->qc_node);
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate * hci1394_q_at_with_mblk()
6937c478bd9Sstevel@tonic-gate * Place an AT command that does need the data buffer into the DMA chain.
6947c478bd9Sstevel@tonic-gate * The data is passed in mblk_t(s). Examples of this are a block write
6957c478bd9Sstevel@tonic-gate * ATREQ and a block read ATRESP. The services layer and the hal use a
6967c478bd9Sstevel@tonic-gate * private structure (h1394_mblk_t) to keep track of how much of the mblk
6977c478bd9Sstevel@tonic-gate * to send since we may have to break the transfer up into smaller blocks.
6987c478bd9Sstevel@tonic-gate * (i.e. a 1MByte block write would go out in 2KByte chunks. result is only
6997c478bd9Sstevel@tonic-gate * valid on failure.
7007c478bd9Sstevel@tonic-gate */
7017c478bd9Sstevel@tonic-gate int
hci1394_q_at_with_mblk(hci1394_q_handle_t q_handle,hci1394_q_cmd_t * cmd,hci1394_basic_pkt_t * hdr,uint_t hdrsize,h1394_mblk_t * mblk,int * result)7027c478bd9Sstevel@tonic-gate hci1394_q_at_with_mblk(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
7037c478bd9Sstevel@tonic-gate hci1394_basic_pkt_t *hdr, uint_t hdrsize, h1394_mblk_t *mblk, int *result)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate uint32_t desc_ioaddr;
7067c478bd9Sstevel@tonic-gate uint32_t data_ioaddr;
7077c478bd9Sstevel@tonic-gate int status;
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
7117c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
7127c478bd9Sstevel@tonic-gate ASSERT(hdr != NULL);
7137c478bd9Sstevel@tonic-gate ASSERT(mblk != NULL);
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate * Check the HAL state and generation when the AT Q is locked. This
7197c478bd9Sstevel@tonic-gate * will make sure that we get all the commands when we flush the Q's
7207c478bd9Sstevel@tonic-gate * during a reset or shutdown.
7217c478bd9Sstevel@tonic-gate */
7227c478bd9Sstevel@tonic-gate if ((hci1394_state(q_handle->q_drvinfo) != HCI1394_NORMAL) ||
7237c478bd9Sstevel@tonic-gate (hci1394_ohci_current_busgen(q_handle->q_ohci) !=
7247c478bd9Sstevel@tonic-gate cmd->qc_generation)) {
7257c478bd9Sstevel@tonic-gate *result = H1394_STATUS_INVALID_BUSGEN;
7267c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
7277c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate /* save away the argument to pass up when this command completes */
7317c478bd9Sstevel@tonic-gate cmd->qc_node.tln_addr = cmd;
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /* we have not written any 16 byte blocks to the descriptor yet */
7347c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate /* Reserve space for an OMI and OL in the descriptor buffer */
7377c478bd9Sstevel@tonic-gate status = hci1394_q_reserve(&q_handle->q_desc,
7387c478bd9Sstevel@tonic-gate (sizeof (hci1394_desc_imm_t) + sizeof (hci1394_desc_t)),
7397c478bd9Sstevel@tonic-gate &desc_ioaddr);
7407c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
7417c478bd9Sstevel@tonic-gate *result = H1394_STATUS_NOMORE_SPACE;
7427c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
7437c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate /* Reserve space for data in the data buffer */
7477c478bd9Sstevel@tonic-gate status = hci1394_q_reserve(&q_handle->q_data, mblk->length,
7487c478bd9Sstevel@tonic-gate &data_ioaddr);
7497c478bd9Sstevel@tonic-gate if (status != DDI_SUCCESS) {
7507c478bd9Sstevel@tonic-gate *result = H1394_STATUS_NOMORE_SPACE;
7517c478bd9Sstevel@tonic-gate hci1394_q_unreserve(&q_handle->q_desc);
7527c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
7537c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate
7567c478bd9Sstevel@tonic-gate /* Copy mblk data into data buffer */
7577c478bd9Sstevel@tonic-gate hci1394_q_at_copy_from_mblk(&q_handle->q_data, cmd, mblk);
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate /* write the OMI to the descriptor buffer */
7607c478bd9Sstevel@tonic-gate hci1394_q_at_write_OMI(q_handle, &q_handle->q_desc, cmd, hdr, hdrsize);
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate /* write the OL to the descriptor buffer */
7637c478bd9Sstevel@tonic-gate hci1394_q_at_write_OL(q_handle, &q_handle->q_desc, cmd, data_ioaddr,
7647c478bd9Sstevel@tonic-gate mblk->length);
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate /* Add the AT command to the queued list */
7677c478bd9Sstevel@tonic-gate hci1394_tlist_add(q_handle->q_queued_list, &cmd->qc_node);
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * hci1394_q_at_next()
7777c478bd9Sstevel@tonic-gate * Return the next completed AT command in cmd. If flush_q is true, we will
7787c478bd9Sstevel@tonic-gate * return the command regardless if it finished or not. We will flush
7797c478bd9Sstevel@tonic-gate * during bus reset processing, shutdown, and detach.
7807c478bd9Sstevel@tonic-gate */
7817c478bd9Sstevel@tonic-gate void
hci1394_q_at_next(hci1394_q_handle_t q_handle,boolean_t flush_q,hci1394_q_cmd_t ** cmd)7827c478bd9Sstevel@tonic-gate hci1394_q_at_next(hci1394_q_handle_t q_handle, boolean_t flush_q,
7837c478bd9Sstevel@tonic-gate hci1394_q_cmd_t **cmd)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate hci1394_q_buf_t *desc;
7867c478bd9Sstevel@tonic-gate hci1394_q_buf_t *data;
7877c478bd9Sstevel@tonic-gate hci1394_tlist_node_t *node;
7887c478bd9Sstevel@tonic-gate uint32_t cmd_status;
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
7927c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate mutex_enter(&q_handle->q_mutex);
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate desc = &q_handle->q_desc;
7977c478bd9Sstevel@tonic-gate data = &q_handle->q_data;
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /* Sync descriptor buffer */
8007c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(desc->qb_buf.bi_dma_handle, 0,
8017c478bd9Sstevel@tonic-gate desc->qb_buf.bi_length, DDI_DMA_SYNC_FORKERNEL);
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate /* Look at the top cmd on the queued list (without removing it) */
8047c478bd9Sstevel@tonic-gate hci1394_tlist_peek(q_handle->q_queued_list, &node);
8057c478bd9Sstevel@tonic-gate if (node == NULL) {
8067c478bd9Sstevel@tonic-gate /* There are no more commands left on the queued list */
8077c478bd9Sstevel@tonic-gate *cmd = NULL;
8087c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
8097c478bd9Sstevel@tonic-gate return;
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate * There is a command on the list, read its status and timestamp when
8147c478bd9Sstevel@tonic-gate * it was sent
8157c478bd9Sstevel@tonic-gate */
8167c478bd9Sstevel@tonic-gate *cmd = (hci1394_q_cmd_t *)node->tln_addr;
8177c478bd9Sstevel@tonic-gate cmd_status = ddi_get32(desc->qb_buf.bi_handle, (*cmd)->qc_status_addr);
8187c478bd9Sstevel@tonic-gate (*cmd)->qc_timestamp = cmd_status & DESC_ST_TIMESTAMP_MASK;
8197c478bd9Sstevel@tonic-gate cmd_status = HCI1394_DESC_EVT_GET(cmd_status);
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate * If we are flushing the q (e.g. due to a bus reset), we will return
8237c478bd9Sstevel@tonic-gate * the command regardless of its completion status. If we are not
8247c478bd9Sstevel@tonic-gate * flushing the Q and we do not have status on the command (e.g. status
8257c478bd9Sstevel@tonic-gate * = 0), we are done with this Q for now.
8267c478bd9Sstevel@tonic-gate */
8277c478bd9Sstevel@tonic-gate if (flush_q == B_FALSE) {
8287c478bd9Sstevel@tonic-gate if (cmd_status == 0) {
8297c478bd9Sstevel@tonic-gate *cmd = NULL;
8307c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
8317c478bd9Sstevel@tonic-gate return;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate * The command completed, remove it from the queued list. There is not
8377c478bd9Sstevel@tonic-gate * a race condition to delete the node in the list here. This is the
8387c478bd9Sstevel@tonic-gate * only place the node will be deleted so we do not need to check the
8397c478bd9Sstevel@tonic-gate * return status.
8407c478bd9Sstevel@tonic-gate */
8417c478bd9Sstevel@tonic-gate (void) hci1394_tlist_delete(q_handle->q_queued_list, node);
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate * Free the space used by the command in the descriptor and data
8457c478bd9Sstevel@tonic-gate * buffers.
8467c478bd9Sstevel@tonic-gate */
8477c478bd9Sstevel@tonic-gate desc->qb_ptrs.qp_free_buf = (*cmd)->qc_descriptor_buf;
8487c478bd9Sstevel@tonic-gate desc->qb_ptrs.qp_free = (*cmd)->qc_descriptor_end;
8497c478bd9Sstevel@tonic-gate if ((*cmd)->qc_data_used == B_TRUE) {
8507c478bd9Sstevel@tonic-gate data->qb_ptrs.qp_free_buf = (*cmd)->qc_data_buf;
8517c478bd9Sstevel@tonic-gate data->qb_ptrs.qp_free = (*cmd)->qc_data_end;
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate /* return command status */
8557c478bd9Sstevel@tonic-gate (*cmd)->qc_status = cmd_status;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate mutex_exit(&q_handle->q_mutex);
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate /*
8627c478bd9Sstevel@tonic-gate * hci1394_q_at_write_OMI()
8637c478bd9Sstevel@tonic-gate * Write an OMI descriptor into the AT descriptor buffer passed in as qbuf.
8647c478bd9Sstevel@tonic-gate * Buffer state information is stored in cmd. Use the hdr and hdr size for
8657c478bd9Sstevel@tonic-gate * the additional information attached to an immediate descriptor.
8667c478bd9Sstevel@tonic-gate */
8677c478bd9Sstevel@tonic-gate void
hci1394_q_at_write_OMI(hci1394_q_handle_t q_handle,hci1394_q_buf_t * qbuf,hci1394_q_cmd_t * cmd,hci1394_basic_pkt_t * hdr,uint_t hdrsize)8687c478bd9Sstevel@tonic-gate hci1394_q_at_write_OMI(hci1394_q_handle_t q_handle, hci1394_q_buf_t *qbuf,
8697c478bd9Sstevel@tonic-gate hci1394_q_cmd_t *cmd, hci1394_basic_pkt_t *hdr, uint_t hdrsize)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate hci1394_desc_imm_t *desc;
8727c478bd9Sstevel@tonic-gate uint32_t data;
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
8767c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
8777c478bd9Sstevel@tonic-gate ASSERT(hdr != NULL);
8787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q_handle->q_mutex));
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate /* The only valid "header" sizes for an OMI are 8 bytes or 16 bytes */
8817c478bd9Sstevel@tonic-gate ASSERT((hdrsize == 8) || (hdrsize == 16));
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate /* Make sure enough room for OMI */
8847c478bd9Sstevel@tonic-gate ASSERT(qbuf->qb_ptrs.qp_resv_size >= sizeof (hci1394_desc_imm_t));
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate /* Store the offset of the top of this descriptor block */
8877c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = (uint32_t)(qbuf->qb_ptrs.qp_current -
8887c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin);
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate /* Setup OpenHCI OMI Header */
8917c478bd9Sstevel@tonic-gate desc = (hci1394_desc_imm_t *)qbuf->qb_ptrs.qp_current;
8927c478bd9Sstevel@tonic-gate data = DESC_AT_OMI | (hdrsize & DESC_HDR_REQCOUNT_MASK);
8937c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->hdr, data);
8947c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->data_addr, 0);
8957c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->branch, 0);
8967c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->status, cmd->qc_timestamp);
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate * Copy in 1394 header. Size is in bytes, convert it to a 32-bit word
9007c478bd9Sstevel@tonic-gate * count.
9017c478bd9Sstevel@tonic-gate */
9027c478bd9Sstevel@tonic-gate ddi_rep_put32(qbuf->qb_buf.bi_handle, &hdr->q1, &desc->q1,
9037c478bd9Sstevel@tonic-gate hdrsize >> 2, DDI_DEV_AUTOINCR);
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /*
9067c478bd9Sstevel@tonic-gate * We wrote 2 16 byte blocks in the descriptor buffer, update the count
9077c478bd9Sstevel@tonic-gate * accordingly. Update the reserved size and current pointer.
9087c478bd9Sstevel@tonic-gate */
9097c478bd9Sstevel@tonic-gate q_handle->q_block_cnt += 2;
9107c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size -= sizeof (hci1394_desc_imm_t);
9117c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current += sizeof (hci1394_desc_imm_t);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /*
9167c478bd9Sstevel@tonic-gate * hci1394_q_at_write_OLI()
9177c478bd9Sstevel@tonic-gate * Write an OLI descriptor into the AT descriptor buffer passed in as qbuf.
9187c478bd9Sstevel@tonic-gate * Buffer state information is stored in cmd. Use the hdr and hdr size for
9197c478bd9Sstevel@tonic-gate * the additional information attached to an immediate descriptor.
9207c478bd9Sstevel@tonic-gate */
9217c478bd9Sstevel@tonic-gate void
hci1394_q_at_write_OLI(hci1394_q_handle_t q_handle,hci1394_q_buf_t * qbuf,hci1394_q_cmd_t * cmd,hci1394_basic_pkt_t * hdr,uint_t hdrsize)9227c478bd9Sstevel@tonic-gate hci1394_q_at_write_OLI(hci1394_q_handle_t q_handle, hci1394_q_buf_t *qbuf,
9237c478bd9Sstevel@tonic-gate hci1394_q_cmd_t *cmd, hci1394_basic_pkt_t *hdr, uint_t hdrsize)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate hci1394_desc_imm_t *desc;
9267c478bd9Sstevel@tonic-gate uint32_t data;
9277c478bd9Sstevel@tonic-gate uint32_t command_ptr;
9287c478bd9Sstevel@tonic-gate uint32_t tcode;
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
9327c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
9337c478bd9Sstevel@tonic-gate ASSERT(hdr != NULL);
9347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q_handle->q_mutex));
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /* The only valid "header" sizes for an OLI are 8, 12, 16 bytes */
9377c478bd9Sstevel@tonic-gate ASSERT((hdrsize == 8) || (hdrsize == 12) || (hdrsize == 16));
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate /* make sure enough room for 1 OLI */
9407c478bd9Sstevel@tonic-gate ASSERT(qbuf->qb_ptrs.qp_resv_size >= sizeof (hci1394_desc_imm_t));
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate /* Store the offset of the top of this descriptor block */
9437c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = (uint32_t)(qbuf->qb_ptrs.qp_current -
9447c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin);
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate /* Setup OpenHCI OLI Header */
9477c478bd9Sstevel@tonic-gate desc = (hci1394_desc_imm_t *)qbuf->qb_ptrs.qp_current;
9487c478bd9Sstevel@tonic-gate data = DESC_AT_OLI | (hdrsize & DESC_HDR_REQCOUNT_MASK);
9497c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->hdr, data);
9507c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->data_addr, 0);
9517c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->branch, 0);
9527c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->status, cmd->qc_timestamp);
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate /* Setup 1394 Header */
9557c478bd9Sstevel@tonic-gate tcode = (hdr->q1 & DESC_PKT_TCODE_MASK) >> DESC_PKT_TCODE_SHIFT;
9567c478bd9Sstevel@tonic-gate if ((tcode == IEEE1394_TCODE_WRITE_QUADLET) ||
9577c478bd9Sstevel@tonic-gate (tcode == IEEE1394_TCODE_READ_QUADLET_RESP)) {
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * if the tcode = a quadlet write, move the last quadlet as
9607c478bd9Sstevel@tonic-gate * 8-bit data. All data is treated as 8-bit data (even quadlet
9617c478bd9Sstevel@tonic-gate * reads and writes). Therefore, target drivers MUST take that
9627c478bd9Sstevel@tonic-gate * into consideration when accessing device registers.
9637c478bd9Sstevel@tonic-gate */
9647c478bd9Sstevel@tonic-gate ddi_rep_put32(qbuf->qb_buf.bi_handle, &hdr->q1, &desc->q1, 3,
9657c478bd9Sstevel@tonic-gate DDI_DEV_AUTOINCR);
9667c478bd9Sstevel@tonic-gate ddi_rep_put8(qbuf->qb_buf.bi_handle, (uint8_t *)&hdr->q4,
9677c478bd9Sstevel@tonic-gate (uint8_t *)&desc->q4, 4, DDI_DEV_AUTOINCR);
9687c478bd9Sstevel@tonic-gate } else {
9697c478bd9Sstevel@tonic-gate ddi_rep_put32(qbuf->qb_buf.bi_handle, &hdr->q1, &desc->q1,
9707c478bd9Sstevel@tonic-gate hdrsize >> 2, DDI_DEV_AUTOINCR);
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate /*
9747c478bd9Sstevel@tonic-gate * We wrote 2 16 byte blocks in the descriptor buffer, update the count
9757c478bd9Sstevel@tonic-gate * accordingly.
9767c478bd9Sstevel@tonic-gate */
9777c478bd9Sstevel@tonic-gate q_handle->q_block_cnt += 2;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /*
9807c478bd9Sstevel@tonic-gate * Sync buffer in case DMA engine currently running. This must be done
9817c478bd9Sstevel@tonic-gate * before writing the command pointer in the previous descriptor.
9827c478bd9Sstevel@tonic-gate */
9837c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
9847c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate /* save away the status address for quick access in at_next() */
9877c478bd9Sstevel@tonic-gate cmd->qc_status_addr = &desc->status;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate * Setup the command pointer. This tells the HW where to get the
9917c478bd9Sstevel@tonic-gate * descriptor we just setup. This includes the IO address along with
9927c478bd9Sstevel@tonic-gate * a 4 bit 16 byte block count
9937c478bd9Sstevel@tonic-gate */
9947c478bd9Sstevel@tonic-gate command_ptr = (uint32_t)((qbuf->qb_cookie[qbuf->qb_ptrs.qp_current_buf
9957c478bd9Sstevel@tonic-gate ].dmac_address + qbuf->qb_ptrs.qp_offset) | (q_handle->q_block_cnt &
9967c478bd9Sstevel@tonic-gate DESC_Z_MASK));
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate * if we previously setup a descriptor, add this new descriptor into
10007c478bd9Sstevel@tonic-gate * the previous descriptor's "next" pointer.
10017c478bd9Sstevel@tonic-gate */
10027c478bd9Sstevel@tonic-gate if (q_handle->q_previous != NULL) {
10037c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &q_handle->q_previous->branch,
10047c478bd9Sstevel@tonic-gate command_ptr);
10057c478bd9Sstevel@tonic-gate /* Sync buffer again, this gets the command pointer */
10067c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
10077c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate * this is now the previous descriptor. Update the current pointer,
10127c478bd9Sstevel@tonic-gate * clear the block count and reserved size since this is the end of
10137c478bd9Sstevel@tonic-gate * this command.
10147c478bd9Sstevel@tonic-gate */
10157c478bd9Sstevel@tonic-gate q_handle->q_previous = (hci1394_desc_t *)desc;
10167c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current += sizeof (hci1394_desc_imm_t);
10177c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
10187c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = 0;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate /* save away cleanup info when we are done with the command */
10217c478bd9Sstevel@tonic-gate cmd->qc_descriptor_buf = qbuf->qb_ptrs.qp_current_buf;
10227c478bd9Sstevel@tonic-gate cmd->qc_descriptor_end = qbuf->qb_ptrs.qp_current - 1;
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate /* If the DMA is not running, start it */
10257c478bd9Sstevel@tonic-gate if (q_handle->q_dma_running == B_FALSE) {
10267c478bd9Sstevel@tonic-gate q_handle->q_info.qi_start(q_handle->q_info.qi_callback_arg,
10277c478bd9Sstevel@tonic-gate command_ptr);
10287c478bd9Sstevel@tonic-gate q_handle->q_dma_running = B_TRUE;
10297c478bd9Sstevel@tonic-gate /* the DMA is running, wake it up */
10307c478bd9Sstevel@tonic-gate } else {
10317c478bd9Sstevel@tonic-gate q_handle->q_info.qi_wake(q_handle->q_info.qi_callback_arg);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate * hci1394_q_at_write_OL()
10387c478bd9Sstevel@tonic-gate * Write an OL descriptor into the AT descriptor buffer passed in as qbuf.
10397c478bd9Sstevel@tonic-gate * Buffer state information is stored in cmd. The IO address of the data
10407c478bd9Sstevel@tonic-gate * buffer is passed in io_addr. Size is the size of the data to be
10417c478bd9Sstevel@tonic-gate * transferred.
10427c478bd9Sstevel@tonic-gate */
10437c478bd9Sstevel@tonic-gate void
hci1394_q_at_write_OL(hci1394_q_handle_t q_handle,hci1394_q_buf_t * qbuf,hci1394_q_cmd_t * cmd,uint32_t io_addr,uint_t size)10447c478bd9Sstevel@tonic-gate hci1394_q_at_write_OL(hci1394_q_handle_t q_handle, hci1394_q_buf_t *qbuf,
10457c478bd9Sstevel@tonic-gate hci1394_q_cmd_t *cmd, uint32_t io_addr, uint_t size)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate hci1394_desc_t *desc;
10487c478bd9Sstevel@tonic-gate uint32_t data;
10497c478bd9Sstevel@tonic-gate uint32_t command_ptr;
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
10537c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
10547c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
10557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q_handle->q_mutex));
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate /* make sure enough room for OL */
10587c478bd9Sstevel@tonic-gate ASSERT(qbuf->qb_ptrs.qp_resv_size >= sizeof (hci1394_desc_t));
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate /* Setup OpenHCI OL Header */
10617c478bd9Sstevel@tonic-gate desc = (hci1394_desc_t *)qbuf->qb_ptrs.qp_current;
10627c478bd9Sstevel@tonic-gate data = DESC_AT_OL | (size & DESC_HDR_REQCOUNT_MASK);
10637c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->hdr, data);
10647c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->data_addr, io_addr);
10657c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->branch, 0);
10667c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->status, 0);
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate * We wrote 1 16 byte block in the descriptor buffer, update the count
10707c478bd9Sstevel@tonic-gate * accordingly.
10717c478bd9Sstevel@tonic-gate */
10727c478bd9Sstevel@tonic-gate q_handle->q_block_cnt++;
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate /*
10757c478bd9Sstevel@tonic-gate * Sync buffer in case DMA engine currently running. This must be done
10767c478bd9Sstevel@tonic-gate * before writing the command pointer in the previous descriptor.
10777c478bd9Sstevel@tonic-gate */
10787c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
10797c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate /* save away the status address for quick access in at_next() */
10827c478bd9Sstevel@tonic-gate cmd->qc_status_addr = &desc->status;
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate /*
10857c478bd9Sstevel@tonic-gate * Setup the command pointer. This tells the HW where to get the
10867c478bd9Sstevel@tonic-gate * descriptor we just setup. This includes the IO address along with
10877c478bd9Sstevel@tonic-gate * a 4 bit 16 byte block count
10887c478bd9Sstevel@tonic-gate */
10897c478bd9Sstevel@tonic-gate command_ptr = (uint32_t)((qbuf->qb_cookie[qbuf->qb_ptrs.qp_current_buf
10907c478bd9Sstevel@tonic-gate ].dmac_address + qbuf->qb_ptrs.qp_offset) | (q_handle->q_block_cnt &
10917c478bd9Sstevel@tonic-gate DESC_Z_MASK));
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate /*
10947c478bd9Sstevel@tonic-gate * if we previously setup a descriptor, add this new descriptor into
10957c478bd9Sstevel@tonic-gate * the previous descriptor's "next" pointer.
10967c478bd9Sstevel@tonic-gate */
10977c478bd9Sstevel@tonic-gate if (q_handle->q_previous != NULL) {
10987c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &q_handle->q_previous->branch,
10997c478bd9Sstevel@tonic-gate command_ptr);
11007c478bd9Sstevel@tonic-gate /* Sync buffer again, this gets the command pointer */
11017c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
11027c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate /*
11067c478bd9Sstevel@tonic-gate * this is now the previous descriptor. Update the current pointer,
11077c478bd9Sstevel@tonic-gate * clear the block count and reserved size since this is the end of
11087c478bd9Sstevel@tonic-gate * this command.
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@tonic-gate q_handle->q_previous = desc;
11117c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current += sizeof (hci1394_desc_t);
11127c478bd9Sstevel@tonic-gate q_handle->q_block_cnt = 0;
11137c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size = 0;
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate /* save away cleanup info when we are done with the command */
11167c478bd9Sstevel@tonic-gate cmd->qc_descriptor_buf = qbuf->qb_ptrs.qp_current_buf;
11177c478bd9Sstevel@tonic-gate cmd->qc_descriptor_end = qbuf->qb_ptrs.qp_current - 1;
11187c478bd9Sstevel@tonic-gate
11197c478bd9Sstevel@tonic-gate /* If the DMA is not running, start it */
11207c478bd9Sstevel@tonic-gate if (q_handle->q_dma_running == B_FALSE) {
11217c478bd9Sstevel@tonic-gate q_handle->q_info.qi_start(q_handle->q_info.qi_callback_arg,
11227c478bd9Sstevel@tonic-gate command_ptr);
11237c478bd9Sstevel@tonic-gate q_handle->q_dma_running = B_TRUE;
11247c478bd9Sstevel@tonic-gate /* the DMA is running, wake it up */
11257c478bd9Sstevel@tonic-gate } else {
11267c478bd9Sstevel@tonic-gate q_handle->q_info.qi_wake(q_handle->q_info.qi_callback_arg);
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate
11317c478bd9Sstevel@tonic-gate /*
11327c478bd9Sstevel@tonic-gate * hci1394_q_at_rep_put8()
11337c478bd9Sstevel@tonic-gate * Copy a byte stream from a kernel virtual address (data) to a IO mapped
11347c478bd9Sstevel@tonic-gate * data buffer (qbuf). Copy datasize bytes. State information for the
11357c478bd9Sstevel@tonic-gate * data buffer is kept in cmd.
11367c478bd9Sstevel@tonic-gate */
11377c478bd9Sstevel@tonic-gate void
hci1394_q_at_rep_put8(hci1394_q_buf_t * qbuf,hci1394_q_cmd_t * cmd,uint8_t * data,uint_t datasize)11387c478bd9Sstevel@tonic-gate hci1394_q_at_rep_put8(hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd,
11397c478bd9Sstevel@tonic-gate uint8_t *data, uint_t datasize)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
11427c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
11437c478bd9Sstevel@tonic-gate ASSERT(data != NULL);
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /* Make sure enough room for data */
11467c478bd9Sstevel@tonic-gate ASSERT(qbuf->qb_ptrs.qp_resv_size >= datasize);
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate /* Copy in data into the data buffer */
11497c478bd9Sstevel@tonic-gate ddi_rep_put8(qbuf->qb_buf.bi_handle, data,
11507c478bd9Sstevel@tonic-gate (uint8_t *)qbuf->qb_ptrs.qp_current, datasize, DDI_DEV_AUTOINCR);
11517c478bd9Sstevel@tonic-gate
11527c478bd9Sstevel@tonic-gate /* Update the current pointer, offset, and reserved size */
11537c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current += datasize;
11547c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = (uint32_t)(qbuf->qb_ptrs.qp_current -
11557c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin);
11567c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_resv_size -= datasize;
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate /* save away cleanup info when we are done with the command */
11597c478bd9Sstevel@tonic-gate cmd->qc_data_used = B_TRUE;
11607c478bd9Sstevel@tonic-gate cmd->qc_data_buf = qbuf->qb_ptrs.qp_current_buf;
11617c478bd9Sstevel@tonic-gate cmd->qc_data_end = qbuf->qb_ptrs.qp_current - 1;
11627c478bd9Sstevel@tonic-gate
11637c478bd9Sstevel@tonic-gate /* Sync data buffer */
11647c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
11657c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate
11697c478bd9Sstevel@tonic-gate /*
11707c478bd9Sstevel@tonic-gate * hci1394_q_at_copy_from_mblk()
11717c478bd9Sstevel@tonic-gate * Copy a byte stream from a mblk(s) to a IO mapped data buffer (qbuf).
11727c478bd9Sstevel@tonic-gate * Copy mblk->length bytes. The services layer and the hal use a private
11737c478bd9Sstevel@tonic-gate * structure (h1394_mblk_t) to keep track of how much of the mblk to send
11747c478bd9Sstevel@tonic-gate * since we may have to break the transfer up into smaller blocks. (i.e. a
11757c478bd9Sstevel@tonic-gate * 1MByte block write would go out in 2KByte chunks. State information for
11767c478bd9Sstevel@tonic-gate * the data buffer is kept in cmd.
11777c478bd9Sstevel@tonic-gate */
11787c478bd9Sstevel@tonic-gate static void
hci1394_q_at_copy_from_mblk(hci1394_q_buf_t * qbuf,hci1394_q_cmd_t * cmd,h1394_mblk_t * mblk)11797c478bd9Sstevel@tonic-gate hci1394_q_at_copy_from_mblk(hci1394_q_buf_t *qbuf, hci1394_q_cmd_t *cmd,
11807c478bd9Sstevel@tonic-gate h1394_mblk_t *mblk)
11817c478bd9Sstevel@tonic-gate {
11827c478bd9Sstevel@tonic-gate uint_t bytes_left;
11837c478bd9Sstevel@tonic-gate uint_t length;
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
11877c478bd9Sstevel@tonic-gate ASSERT(cmd != NULL);
11887c478bd9Sstevel@tonic-gate ASSERT(mblk != NULL);
11897c478bd9Sstevel@tonic-gate
11907c478bd9Sstevel@tonic-gate /* We return these variables to the Services Layer when we are done */
11917c478bd9Sstevel@tonic-gate mblk->next_offset = mblk->curr_offset;
11927c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->curr_mblk;
11937c478bd9Sstevel@tonic-gate bytes_left = mblk->length;
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate /* do while there are bytes left to copy */
11967c478bd9Sstevel@tonic-gate do {
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate * If the entire data portion of the current block transfer is
11997c478bd9Sstevel@tonic-gate * contained within a single mblk.
12007c478bd9Sstevel@tonic-gate */
12017c478bd9Sstevel@tonic-gate if ((mblk->next_offset + bytes_left) <=
12027c478bd9Sstevel@tonic-gate (mblk->next_mblk->b_wptr)) {
12037c478bd9Sstevel@tonic-gate /* Copy the data into the data Q */
12047c478bd9Sstevel@tonic-gate hci1394_q_at_rep_put8(qbuf, cmd,
12057c478bd9Sstevel@tonic-gate (uint8_t *)mblk->next_offset, bytes_left);
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate /* increment the mblk offset */
12087c478bd9Sstevel@tonic-gate mblk->next_offset += bytes_left;
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate /* we have no more bytes to put into the buffer */
12117c478bd9Sstevel@tonic-gate bytes_left = 0;
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate /*
12147c478bd9Sstevel@tonic-gate * If our offset is at the end of data in this mblk, go
12157c478bd9Sstevel@tonic-gate * to the next mblk.
12167c478bd9Sstevel@tonic-gate */
12177c478bd9Sstevel@tonic-gate if (mblk->next_offset >= mblk->next_mblk->b_wptr) {
12187c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->next_mblk->b_cont;
12197c478bd9Sstevel@tonic-gate if (mblk->next_mblk != NULL) {
12207c478bd9Sstevel@tonic-gate mblk->next_offset =
12217c478bd9Sstevel@tonic-gate mblk->next_mblk->b_rptr;
12227c478bd9Sstevel@tonic-gate }
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /*
12267c478bd9Sstevel@tonic-gate * The data portion of the current block transfer is spread
12277c478bd9Sstevel@tonic-gate * across two or more mblk's
12287c478bd9Sstevel@tonic-gate */
12297c478bd9Sstevel@tonic-gate } else {
12307c478bd9Sstevel@tonic-gate /*
12317c478bd9Sstevel@tonic-gate * Figure out how much data is in this mblk.
12327c478bd9Sstevel@tonic-gate */
12337c478bd9Sstevel@tonic-gate length = mblk->next_mblk->b_wptr - mblk->next_offset;
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate /* Copy the data into the atreq data Q */
12367c478bd9Sstevel@tonic-gate hci1394_q_at_rep_put8(qbuf, cmd,
12377c478bd9Sstevel@tonic-gate (uint8_t *)mblk->next_offset, length);
12387c478bd9Sstevel@tonic-gate
12397c478bd9Sstevel@tonic-gate /* update the bytes left count, go to the next mblk */
12407c478bd9Sstevel@tonic-gate bytes_left = bytes_left - length;
12417c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->next_mblk->b_cont;
12427c478bd9Sstevel@tonic-gate ASSERT(mblk->next_mblk != NULL);
12437c478bd9Sstevel@tonic-gate mblk->next_offset = mblk->next_mblk->b_rptr;
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate } while (bytes_left > 0);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate /*
12507c478bd9Sstevel@tonic-gate * hci1394_q_ar_next()
12517c478bd9Sstevel@tonic-gate * Return an address to the next received AR packet. If there are no more
12527c478bd9Sstevel@tonic-gate * AR packets in the buffer, q_addr will be set to NULL.
12537c478bd9Sstevel@tonic-gate */
12547c478bd9Sstevel@tonic-gate void
hci1394_q_ar_next(hci1394_q_handle_t q_handle,uint32_t ** q_addr)12557c478bd9Sstevel@tonic-gate hci1394_q_ar_next(hci1394_q_handle_t q_handle, uint32_t **q_addr)
12567c478bd9Sstevel@tonic-gate {
12577c478bd9Sstevel@tonic-gate hci1394_desc_t *desc;
12587c478bd9Sstevel@tonic-gate hci1394_q_buf_t *descb;
12597c478bd9Sstevel@tonic-gate hci1394_q_buf_t *datab;
12607c478bd9Sstevel@tonic-gate uint32_t residual_count;
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
12647c478bd9Sstevel@tonic-gate ASSERT(q_addr != NULL);
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate descb = &q_handle->q_desc;
12677c478bd9Sstevel@tonic-gate datab = &q_handle->q_data;
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate /* Sync Descriptor buffer */
12707c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(descb->qb_buf.bi_dma_handle, 0,
12717c478bd9Sstevel@tonic-gate descb->qb_buf.bi_length, DDI_DMA_SYNC_FORKERNEL);
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate * Check residual in current IM count vs q_space_left to see if we have
12757c478bd9Sstevel@tonic-gate * received any more responses
12767c478bd9Sstevel@tonic-gate */
12777c478bd9Sstevel@tonic-gate desc = (hci1394_desc_t *)q_handle->q_head;
12787c478bd9Sstevel@tonic-gate residual_count = ddi_get32(descb->qb_buf.bi_handle, &desc->status);
12797c478bd9Sstevel@tonic-gate residual_count &= DESC_ST_RESCOUNT_MASK;
12807c478bd9Sstevel@tonic-gate if (residual_count >= q_handle->q_space_left) {
12817c478bd9Sstevel@tonic-gate /* No new packets received */
12827c478bd9Sstevel@tonic-gate *q_addr = NULL;
12837c478bd9Sstevel@tonic-gate return;
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate /* Sync Data Q */
12877c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(datab->qb_buf.bi_dma_handle, 0,
12887c478bd9Sstevel@tonic-gate datab->qb_buf.bi_length, DDI_DMA_SYNC_FORKERNEL);
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate /*
12917c478bd9Sstevel@tonic-gate * We have a new packet, return the address of the start of the
12927c478bd9Sstevel@tonic-gate * packet.
12937c478bd9Sstevel@tonic-gate */
12947c478bd9Sstevel@tonic-gate *q_addr = (uint32_t *)datab->qb_ptrs.qp_current;
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate /*
12997c478bd9Sstevel@tonic-gate * hci1394_q_ar_free()
13007c478bd9Sstevel@tonic-gate * Free the space used by the AR packet at the top of the data buffer. AR
13017c478bd9Sstevel@tonic-gate * packets are processed in the order that they are received. This will
13027c478bd9Sstevel@tonic-gate * free the oldest received packet which has not yet been freed. size is
13037c478bd9Sstevel@tonic-gate * how much space the packet takes up.
13047c478bd9Sstevel@tonic-gate */
13057c478bd9Sstevel@tonic-gate void
hci1394_q_ar_free(hci1394_q_handle_t q_handle,uint_t size)13067c478bd9Sstevel@tonic-gate hci1394_q_ar_free(hci1394_q_handle_t q_handle, uint_t size)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate hci1394_q_buf_t *descb;
13097c478bd9Sstevel@tonic-gate hci1394_q_buf_t *datab;
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate descb = &q_handle->q_desc;
13157c478bd9Sstevel@tonic-gate datab = &q_handle->q_data;
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate /*
13187c478bd9Sstevel@tonic-gate * Packet is in multiple buffers. Theoretically a buffer could be broken
13197c478bd9Sstevel@tonic-gate * in more than two buffers for an ARRESP. Since the buffers should be
13207c478bd9Sstevel@tonic-gate * in at least 4K increments this will not happen since the max packet
13217c478bd9Sstevel@tonic-gate * size is 2KBytes.
13227c478bd9Sstevel@tonic-gate */
13237c478bd9Sstevel@tonic-gate if ((datab->qb_ptrs.qp_current + size) > datab->qb_ptrs.qp_end) {
13247c478bd9Sstevel@tonic-gate /* Add IM descriptor for used buffer back into Q */
13257c478bd9Sstevel@tonic-gate hci1394_q_ar_write_IM(q_handle, descb,
13267c478bd9Sstevel@tonic-gate datab->qb_cookie[datab->qb_ptrs.qp_current_buf
13277c478bd9Sstevel@tonic-gate ].dmac_address,
13287c478bd9Sstevel@tonic-gate datab->qb_cookie[datab->qb_ptrs.qp_current_buf].dmac_size);
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate /* Go to the next buffer */
13317c478bd9Sstevel@tonic-gate hci1394_q_next_buf(datab);
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate /* Update next buffers pointers for partial packet */
13347c478bd9Sstevel@tonic-gate size -= q_handle->q_space_left;
13357c478bd9Sstevel@tonic-gate datab->qb_ptrs.qp_current += size;
13367c478bd9Sstevel@tonic-gate q_handle->q_space_left =
13377c478bd9Sstevel@tonic-gate datab->qb_cookie[datab->qb_ptrs.qp_current_buf].dmac_size -
13387c478bd9Sstevel@tonic-gate size;
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate /* Change the head pointer to the next IM descriptor */
13417c478bd9Sstevel@tonic-gate q_handle->q_head += sizeof (hci1394_desc_t);
13427c478bd9Sstevel@tonic-gate if ((q_handle->q_head + sizeof (hci1394_desc_t)) >
13437c478bd9Sstevel@tonic-gate (descb->qb_ptrs.qp_bottom + 1)) {
13447c478bd9Sstevel@tonic-gate q_handle->q_head = descb->qb_ptrs.qp_top;
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate /* Packet is only in one buffer */
13487c478bd9Sstevel@tonic-gate } else {
13497c478bd9Sstevel@tonic-gate q_handle->q_space_left -= size;
13507c478bd9Sstevel@tonic-gate datab->qb_ptrs.qp_current += size;
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate /*
13567c478bd9Sstevel@tonic-gate * hci1394_q_ar_get32()
13577c478bd9Sstevel@tonic-gate * Read a quadlet of data regardless if it is in the current buffer or has
13587c478bd9Sstevel@tonic-gate * wrapped to the top buffer. If the address passed to this routine is
13597c478bd9Sstevel@tonic-gate * passed the bottom of the data buffer, this routine will automatically
13607c478bd9Sstevel@tonic-gate * wrap back to the top of the Q and look in the correct offset from the
13617c478bd9Sstevel@tonic-gate * top. Copy the data into the kernel virtual address provided.
13627c478bd9Sstevel@tonic-gate */
13637c478bd9Sstevel@tonic-gate uint32_t
hci1394_q_ar_get32(hci1394_q_handle_t q_handle,uint32_t * addr)13647c478bd9Sstevel@tonic-gate hci1394_q_ar_get32(hci1394_q_handle_t q_handle, uint32_t *addr)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate hci1394_q_buf_t *data;
13677c478bd9Sstevel@tonic-gate uintptr_t new_addr;
13687c478bd9Sstevel@tonic-gate uint32_t data32;
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate
13717c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
13727c478bd9Sstevel@tonic-gate ASSERT(addr != NULL);
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate data = &q_handle->q_data;
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate * if the data has wrapped to the top of the buffer, adjust the address.
13787c478bd9Sstevel@tonic-gate */
13797c478bd9Sstevel@tonic-gate if ((uintptr_t)addr > (uintptr_t)data->qb_ptrs.qp_bottom) {
13807c478bd9Sstevel@tonic-gate new_addr = (uintptr_t)data->qb_ptrs.qp_top + ((uintptr_t)addr -
13817c478bd9Sstevel@tonic-gate ((uintptr_t)data->qb_ptrs.qp_bottom + (uintptr_t)1));
13827c478bd9Sstevel@tonic-gate data32 = ddi_get32(data->qb_buf.bi_handle,
13837c478bd9Sstevel@tonic-gate (uint32_t *)new_addr);
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate /* data is before end of buffer */
13867c478bd9Sstevel@tonic-gate } else {
13877c478bd9Sstevel@tonic-gate data32 = ddi_get32(data->qb_buf.bi_handle, addr);
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate
13907c478bd9Sstevel@tonic-gate return (data32);
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate /*
13957c478bd9Sstevel@tonic-gate * hci1394_q_ar_rep_get8()
13967c478bd9Sstevel@tonic-gate * Read a byte stream of data regardless if it is contiguous or has partially
13977c478bd9Sstevel@tonic-gate * or fully wrapped to the top buffer. If the address passed to this routine
13987c478bd9Sstevel@tonic-gate * is passed the bottom of the data buffer, or address + size is past the
13997c478bd9Sstevel@tonic-gate * bottom of the data buffer. this routine will automatically wrap back to
14007c478bd9Sstevel@tonic-gate * the top of the Q and look in the correct offset from the top. Copy the
14017c478bd9Sstevel@tonic-gate * data into the kernel virtual address provided.
14027c478bd9Sstevel@tonic-gate */
14037c478bd9Sstevel@tonic-gate void
hci1394_q_ar_rep_get8(hci1394_q_handle_t q_handle,uint8_t * dest,uint8_t * q_addr,uint_t size)14047c478bd9Sstevel@tonic-gate hci1394_q_ar_rep_get8(hci1394_q_handle_t q_handle, uint8_t *dest,
14057c478bd9Sstevel@tonic-gate uint8_t *q_addr, uint_t size)
14067c478bd9Sstevel@tonic-gate {
14077c478bd9Sstevel@tonic-gate hci1394_q_buf_t *data;
14087c478bd9Sstevel@tonic-gate uintptr_t new_addr;
14097c478bd9Sstevel@tonic-gate uint_t new_size;
14107c478bd9Sstevel@tonic-gate uintptr_t new_dest;
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate
14137c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
14147c478bd9Sstevel@tonic-gate ASSERT(dest != NULL);
14157c478bd9Sstevel@tonic-gate ASSERT(q_addr != NULL);
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate data = &q_handle->q_data;
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate /*
14207c478bd9Sstevel@tonic-gate * There are three cases:
14217c478bd9Sstevel@tonic-gate * 1) All of the data has wrapped.
14227c478bd9Sstevel@tonic-gate * 2) Some of the data has not wrapped and some has wrapped.
14237c478bd9Sstevel@tonic-gate * 3) None of the data has wrapped.
14247c478bd9Sstevel@tonic-gate */
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate /* All of the data has wrapped, just adjust the starting address */
14277c478bd9Sstevel@tonic-gate if ((uintptr_t)q_addr > (uintptr_t)data->qb_ptrs.qp_bottom) {
14287c478bd9Sstevel@tonic-gate new_addr = (uintptr_t)data->qb_ptrs.qp_top +
14297c478bd9Sstevel@tonic-gate ((uintptr_t)q_addr - ((uintptr_t)data->qb_ptrs.qp_bottom +
14307c478bd9Sstevel@tonic-gate (uintptr_t)1));
14317c478bd9Sstevel@tonic-gate ddi_rep_get8(data->qb_buf.bi_handle, dest, (uint8_t *)new_addr,
14327c478bd9Sstevel@tonic-gate size, DDI_DEV_AUTOINCR);
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate /*
14357c478bd9Sstevel@tonic-gate * Some of the data has wrapped. Copy the data that hasn't wrapped,
14367c478bd9Sstevel@tonic-gate * adjust the address, then copy the rest.
14377c478bd9Sstevel@tonic-gate */
14387c478bd9Sstevel@tonic-gate } else if (((uintptr_t)q_addr + (uintptr_t)size) >
14397c478bd9Sstevel@tonic-gate ((uintptr_t)data->qb_ptrs.qp_bottom + (uintptr_t)1)) {
14407c478bd9Sstevel@tonic-gate /* Copy first half */
14417c478bd9Sstevel@tonic-gate new_size = (uint_t)(((uintptr_t)data->qb_ptrs.qp_bottom +
14427c478bd9Sstevel@tonic-gate (uintptr_t)1) - (uintptr_t)q_addr);
14437c478bd9Sstevel@tonic-gate ddi_rep_get8(data->qb_buf.bi_handle, dest, q_addr, new_size,
14447c478bd9Sstevel@tonic-gate DDI_DEV_AUTOINCR);
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate /* copy second half */
14477c478bd9Sstevel@tonic-gate new_dest = (uintptr_t)dest + (uintptr_t)new_size;
14487c478bd9Sstevel@tonic-gate new_size = size - new_size;
14497c478bd9Sstevel@tonic-gate new_addr = (uintptr_t)data->qb_ptrs.qp_top;
14507c478bd9Sstevel@tonic-gate ddi_rep_get8(data->qb_buf.bi_handle, (uint8_t *)new_dest,
14517c478bd9Sstevel@tonic-gate (uint8_t *)new_addr, new_size, DDI_DEV_AUTOINCR);
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate /* None of the data has wrapped */
14547c478bd9Sstevel@tonic-gate } else {
14557c478bd9Sstevel@tonic-gate ddi_rep_get8(data->qb_buf.bi_handle, dest, q_addr, size,
14567c478bd9Sstevel@tonic-gate DDI_DEV_AUTOINCR);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate
14617c478bd9Sstevel@tonic-gate /*
14627c478bd9Sstevel@tonic-gate * hci1394_q_ar_copy_to_mblk()
14637c478bd9Sstevel@tonic-gate * Read a byte stream of data regardless if it is contiguous or has partially
14647c478bd9Sstevel@tonic-gate * or fully wrapped to the top buffer. If the address passed to this routine
14657c478bd9Sstevel@tonic-gate * is passed the bottom of the data buffer, or address + size is passed the
14667c478bd9Sstevel@tonic-gate * bottom of the data buffer. this routine will automatically wrap back to
14677c478bd9Sstevel@tonic-gate * the top of the Q and look in the correct offset from the top. Copy the
14687c478bd9Sstevel@tonic-gate * data into the mblk provided. The services layer and the hal use a private
14697c478bd9Sstevel@tonic-gate * structure (h1394_mblk_t) to keep track of how much of the mblk to receive
14707c478bd9Sstevel@tonic-gate * into since we may have to break the transfer up into smaller blocks.
14717c478bd9Sstevel@tonic-gate * (i.e. a 1MByte block read would go out in 2KByte requests.
14727c478bd9Sstevel@tonic-gate */
14737c478bd9Sstevel@tonic-gate void
hci1394_q_ar_copy_to_mblk(hci1394_q_handle_t q_handle,uint8_t * addr,h1394_mblk_t * mblk)14747c478bd9Sstevel@tonic-gate hci1394_q_ar_copy_to_mblk(hci1394_q_handle_t q_handle, uint8_t *addr,
14757c478bd9Sstevel@tonic-gate h1394_mblk_t *mblk)
14767c478bd9Sstevel@tonic-gate {
14777c478bd9Sstevel@tonic-gate uint8_t *new_addr;
14787c478bd9Sstevel@tonic-gate uint_t bytes_left;
14797c478bd9Sstevel@tonic-gate uint_t length;
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
14837c478bd9Sstevel@tonic-gate ASSERT(addr != NULL);
14847c478bd9Sstevel@tonic-gate ASSERT(mblk != NULL);
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate /* We return these variables to the Services Layer when we are done */
14877c478bd9Sstevel@tonic-gate mblk->next_offset = mblk->curr_offset;
14887c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->curr_mblk;
14897c478bd9Sstevel@tonic-gate bytes_left = mblk->length;
14907c478bd9Sstevel@tonic-gate
14917c478bd9Sstevel@tonic-gate /* the address we copy from will change as we change mblks */
14927c478bd9Sstevel@tonic-gate new_addr = addr;
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate /* do while there are bytes left to copy */
14957c478bd9Sstevel@tonic-gate do {
14967c478bd9Sstevel@tonic-gate /*
14977c478bd9Sstevel@tonic-gate * If the entire data portion of the current block transfer is
14987c478bd9Sstevel@tonic-gate * contained within a single mblk.
14997c478bd9Sstevel@tonic-gate */
15007c478bd9Sstevel@tonic-gate if ((mblk->next_offset + bytes_left) <=
15017c478bd9Sstevel@tonic-gate (mblk->next_mblk->b_datap->db_lim)) {
15027c478bd9Sstevel@tonic-gate /* Copy the data into the mblk */
15037c478bd9Sstevel@tonic-gate hci1394_q_ar_rep_get8(q_handle,
15047c478bd9Sstevel@tonic-gate (uint8_t *)mblk->next_offset, new_addr, bytes_left);
15057c478bd9Sstevel@tonic-gate
15067c478bd9Sstevel@tonic-gate /* increment the offset */
15077c478bd9Sstevel@tonic-gate mblk->next_offset += bytes_left;
15087c478bd9Sstevel@tonic-gate mblk->next_mblk->b_wptr = mblk->next_offset;
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate /* we have no more bytes to put into the buffer */
15117c478bd9Sstevel@tonic-gate bytes_left = 0;
15127c478bd9Sstevel@tonic-gate
15137c478bd9Sstevel@tonic-gate /*
15147c478bd9Sstevel@tonic-gate * If our offset is at the end of data in this mblk, go
15157c478bd9Sstevel@tonic-gate * to the next mblk.
15167c478bd9Sstevel@tonic-gate */
15177c478bd9Sstevel@tonic-gate if (mblk->next_offset >=
15187c478bd9Sstevel@tonic-gate mblk->next_mblk->b_datap->db_lim) {
15197c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->next_mblk->b_cont;
15207c478bd9Sstevel@tonic-gate if (mblk->next_mblk != NULL) {
15217c478bd9Sstevel@tonic-gate mblk->next_offset =
15227c478bd9Sstevel@tonic-gate mblk->next_mblk->b_wptr;
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate }
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate /*
15277c478bd9Sstevel@tonic-gate * The data portion of the current block transfer is spread
15287c478bd9Sstevel@tonic-gate * across two or more mblk's
15297c478bd9Sstevel@tonic-gate */
15307c478bd9Sstevel@tonic-gate } else {
15317c478bd9Sstevel@tonic-gate /* Figure out how much data is in this mblk */
15327c478bd9Sstevel@tonic-gate length = mblk->next_mblk->b_datap->db_lim -
15337c478bd9Sstevel@tonic-gate mblk->next_offset;
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate /* Copy the data into the mblk */
15367c478bd9Sstevel@tonic-gate hci1394_q_ar_rep_get8(q_handle,
15377c478bd9Sstevel@tonic-gate (uint8_t *)mblk->next_offset, new_addr, length);
15387c478bd9Sstevel@tonic-gate mblk->next_mblk->b_wptr =
15397c478bd9Sstevel@tonic-gate mblk->next_mblk->b_datap->db_lim;
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate * update the bytes left and address to copy from, go
15437c478bd9Sstevel@tonic-gate * to the next mblk.
15447c478bd9Sstevel@tonic-gate */
15457c478bd9Sstevel@tonic-gate bytes_left = bytes_left - length;
15467c478bd9Sstevel@tonic-gate new_addr = (uint8_t *)((uintptr_t)new_addr +
15477c478bd9Sstevel@tonic-gate (uintptr_t)length);
15487c478bd9Sstevel@tonic-gate mblk->next_mblk = mblk->next_mblk->b_cont;
15497c478bd9Sstevel@tonic-gate ASSERT(mblk->next_mblk != NULL);
15507c478bd9Sstevel@tonic-gate mblk->next_offset = mblk->next_mblk->b_wptr;
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate } while (bytes_left > 0);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate
15567c478bd9Sstevel@tonic-gate /*
15577c478bd9Sstevel@tonic-gate * hci1394_q_ar_write_IM()
15587c478bd9Sstevel@tonic-gate * Write an IM descriptor into the AR descriptor buffer passed in as qbuf.
15597c478bd9Sstevel@tonic-gate * The IO address of the data buffer is passed in io_addr. datasize is the
15607c478bd9Sstevel@tonic-gate * size of the data data buffer to receive into.
15617c478bd9Sstevel@tonic-gate */
15627c478bd9Sstevel@tonic-gate void
hci1394_q_ar_write_IM(hci1394_q_handle_t q_handle,hci1394_q_buf_t * qbuf,uint32_t io_addr,uint_t datasize)15637c478bd9Sstevel@tonic-gate hci1394_q_ar_write_IM(hci1394_q_handle_t q_handle, hci1394_q_buf_t *qbuf,
15647c478bd9Sstevel@tonic-gate uint32_t io_addr, uint_t datasize)
15657c478bd9Sstevel@tonic-gate {
15667c478bd9Sstevel@tonic-gate hci1394_desc_t *desc;
15677c478bd9Sstevel@tonic-gate uint32_t data;
15687c478bd9Sstevel@tonic-gate uint32_t command_ptr;
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate ASSERT(q_handle != NULL);
15727c478bd9Sstevel@tonic-gate ASSERT(qbuf != NULL);
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate /* Make sure enough room for IM */
15757c478bd9Sstevel@tonic-gate if ((qbuf->qb_ptrs.qp_current + sizeof (hci1394_desc_t)) >
15767c478bd9Sstevel@tonic-gate (qbuf->qb_ptrs.qp_bottom + 1)) {
15777c478bd9Sstevel@tonic-gate hci1394_q_next_buf(qbuf);
15787c478bd9Sstevel@tonic-gate } else {
15797c478bd9Sstevel@tonic-gate /* Store the offset of the top of this descriptor block */
15807c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_offset = (uint32_t)(qbuf->qb_ptrs.qp_current -
15817c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_begin);
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate /* Setup OpenHCI IM Header */
15857c478bd9Sstevel@tonic-gate desc = (hci1394_desc_t *)qbuf->qb_ptrs.qp_current;
15867c478bd9Sstevel@tonic-gate data = DESC_AR_IM | (datasize & DESC_HDR_REQCOUNT_MASK);
15877c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->hdr, data);
15887c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->data_addr, io_addr);
15897c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->branch, 0);
15907c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle, &desc->status, datasize &
15917c478bd9Sstevel@tonic-gate DESC_ST_RESCOUNT_MASK);
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate /*
15947c478bd9Sstevel@tonic-gate * Sync buffer in case DMA engine currently running. This must be done
15957c478bd9Sstevel@tonic-gate * before writing the command pointer in the previous descriptor.
15967c478bd9Sstevel@tonic-gate */
15977c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
15987c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate /*
16017c478bd9Sstevel@tonic-gate * Setup the command pointer. This tells the HW where to get the
16027c478bd9Sstevel@tonic-gate * descriptor we just setup. This includes the IO address along with
16037c478bd9Sstevel@tonic-gate * a 4 bit 16 byte block count. We only wrote 1 16 byte block.
16047c478bd9Sstevel@tonic-gate */
16057c478bd9Sstevel@tonic-gate command_ptr = (uint32_t)((qbuf->qb_cookie[qbuf->qb_ptrs.qp_current_buf
16067c478bd9Sstevel@tonic-gate ].dmac_address + qbuf->qb_ptrs.qp_offset) | 1);
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate /*
16097c478bd9Sstevel@tonic-gate * if we previously setup a descriptor, add this new descriptor into
16107c478bd9Sstevel@tonic-gate * the previous descriptor's "next" pointer.
16117c478bd9Sstevel@tonic-gate */
16127c478bd9Sstevel@tonic-gate if (q_handle->q_previous != NULL) {
16137c478bd9Sstevel@tonic-gate ddi_put32(qbuf->qb_buf.bi_handle,
16147c478bd9Sstevel@tonic-gate &q_handle->q_previous->branch, command_ptr);
16157c478bd9Sstevel@tonic-gate /* Sync buffer again, this gets the command pointer */
16167c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(qbuf->qb_buf.bi_dma_handle, 0,
16177c478bd9Sstevel@tonic-gate qbuf->qb_buf.bi_length, DDI_DMA_SYNC_FORDEV);
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate /* this is the new previous descriptor. Update the current pointer */
16217c478bd9Sstevel@tonic-gate q_handle->q_previous = desc;
16227c478bd9Sstevel@tonic-gate qbuf->qb_ptrs.qp_current += sizeof (hci1394_desc_t);
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate /* If the DMA is not running, start it */
16257c478bd9Sstevel@tonic-gate if (q_handle->q_dma_running == B_FALSE) {
16267c478bd9Sstevel@tonic-gate q_handle->q_info.qi_start(q_handle->q_info.qi_callback_arg,
16277c478bd9Sstevel@tonic-gate command_ptr);
16287c478bd9Sstevel@tonic-gate q_handle->q_dma_running = B_TRUE;
16297c478bd9Sstevel@tonic-gate /* the DMA is running, wake it up */
16307c478bd9Sstevel@tonic-gate } else {
16317c478bd9Sstevel@tonic-gate q_handle->q_info.qi_wake(q_handle->q_info.qi_callback_arg);
16327c478bd9Sstevel@tonic-gate }
16337c478bd9Sstevel@tonic-gate }
1634