root/usr/src/uts/common/io/1394/adapters/hci1394_buf.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * hci1394_buf.c
 *   These routines handle IO mapped memory.  They include routines to alloc and
 *   free  IO mapped memory and a routine to get the adapters default dma
 *   attributes. These routines are meant to be called from the base context.
 *   They should not be called from an interrupt handler.
 */

#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/sunddi.h>
#include <sys/kmem.h>

#include <sys/1394/h1394.h>
#include <sys/1394/adapters/hci1394.h>


/*
 * hci1394_buffer_attr_get()
 *    returns (in dma_attr) the default DMA attributes for this adapter.
 */
void
hci1394_buf_attr_get(ddi_dma_attr_t *dma_attr)
{
        dma_attr->dma_attr_version = DMA_ATTR_V0;
        dma_attr->dma_attr_addr_lo = (uint64_t)0x00000000;
        dma_attr->dma_attr_addr_hi = (uint64_t)0xFFFFFFFF;
        dma_attr->dma_attr_count_max = (uint64_t)0xFFFFFFFF;
        dma_attr->dma_attr_align = 64;
        dma_attr->dma_attr_burstsizes = 0x3FF;
        dma_attr->dma_attr_minxfer = 1;
        dma_attr->dma_attr_maxxfer = (uint64_t)0xFFFFFFFF;
        dma_attr->dma_attr_seg = (uint64_t)0xFFFFFFFF;
        dma_attr->dma_attr_sgllen = 0x7FFFFFFF;
        dma_attr->dma_attr_granular = 4;
        dma_attr->dma_attr_flags = 0;

#if defined(__x86)
        /* XXX - Not sure why x86 wants the dma_attr_seg to be 0x7FFF?? */
        dma_attr->dma_attr_seg = (uint64_t)0x7FFF;
#endif
}


/*
 * hci1394_buf_alloc()
 *    Allocate an IO mapped buffer. drvinfo is passed in and contains generic
 *    driver info, like dip, instance, buf_attr, etc.  Parms is passed in and
 *    contains the input parameters for alloc, ow much memory to alloc, how many
 *    cookies can we handle, and alignment requirements. info is returned with
 *    all the info about the mapped buffer.  handle is returned. It should be
 *    used when calling hci1394_buf_free().
 */
int
hci1394_buf_alloc(hci1394_drvinfo_t *drvinfo, hci1394_buf_parms_t *parms,
    hci1394_buf_info_t *info, hci1394_buf_handle_t *handle)
{
        ddi_dma_attr_t dma_attr;
        hci1394_buf_t *buf;
        int status;


        ASSERT(drvinfo != NULL);
        ASSERT(parms != NULL);
        ASSERT(info != NULL);
        ASSERT(handle != NULL);

        /* alloc the space to keep track of the buffer */
        buf = kmem_alloc(sizeof (hci1394_buf_t), KM_SLEEP);

        /* setup the return parameter */
        *handle = buf;

        /* save away pointer to general info */
        buf->bu_drvinfo = drvinfo;

        /* Get the default DMA attributes and override sgllen and alignment */

        _NOTE(SCHEME_PROTECTS_DATA("unique (on stack)", ddi_dma_attr_t))
        hci1394_buf_attr_get(&dma_attr);
        dma_attr.dma_attr_sgllen = parms->bp_max_cookies;
        dma_attr.dma_attr_align = parms->bp_alignment;

        status = ddi_dma_alloc_handle(drvinfo->di_dip, &dma_attr,
            DDI_DMA_SLEEP, NULL, &buf->bu_dma_handle);
        if (status != DDI_SUCCESS) {
                kmem_free(buf, sizeof (hci1394_buf_t));
                return (DDI_FAILURE);
        }

        status = ddi_dma_mem_alloc(buf->bu_dma_handle, parms->bp_length,
            &drvinfo->di_buf_attr, DDI_DMA_STREAMING, DDI_DMA_SLEEP,
            NULL, &info->bi_kaddr, &info->bi_real_length, &buf->bu_handle);
        if (status != DDI_SUCCESS) {
                ddi_dma_free_handle(&buf->bu_dma_handle);
                kmem_free(buf, sizeof (hci1394_buf_t));
                return (DDI_FAILURE);
        }

        status = ddi_dma_addr_bind_handle(buf->bu_dma_handle, NULL,
            info->bi_kaddr, info->bi_real_length, DDI_DMA_RDWR |
            DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &info->bi_cookie,
            &info->bi_cookie_count);
        if (status != DDI_SUCCESS) {
                ddi_dma_mem_free(&buf->bu_handle);
                ddi_dma_free_handle(&buf->bu_dma_handle);
                kmem_free(buf, sizeof (hci1394_buf_t));
                return (DDI_FAILURE);
        }

        /* setup rest of buffer info returned to caller */
        info->bi_handle = buf->bu_handle;
        info->bi_dma_handle = buf->bu_dma_handle;
        info->bi_length = parms->bp_length;

        return (DDI_SUCCESS);
}


/*
 * hci1394_buf_free()
 *    Free IO mapped buffer. Notice that a pointer to the handle is used for
 *    the parameter.  free() will set your handle to NULL before returning.
 */
void
hci1394_buf_free(hci1394_buf_handle_t *handle)
{
        hci1394_buf_t *buf;

        ASSERT(handle != NULL);

        buf = *handle;
        (void) ddi_dma_unbind_handle(buf->bu_dma_handle);
        ddi_dma_mem_free(&buf->bu_handle);
        ddi_dma_free_handle(&buf->bu_dma_handle);

        /* free the space to keep track of the buffer */
        kmem_free(buf, sizeof (hci1394_buf_t));

        /* set the handle to NULL to help catch bugs */
        *handle = NULL;
}