summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/1394/adapters/hci1394_buf.c
blob: b9cdc2fc0378561ff2d5960a880b6a71a63aa418 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * 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;
}