1/*
2 * Copyright (c) 2008-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/ddi.h>
32
33#include "sfxge.h"
34#include "efx.h"
35
36static int
37sfxge_dma_buffer_unbind_handle(efsys_mem_t *esmp)
38{
39	int rc;
40
41	esmp->esm_addr = 0;
42	rc = ddi_dma_unbind_handle(esmp->esm_dma_handle);
43	if (rc != DDI_SUCCESS)
44		goto fail1;
45
46	return (0);
47
48fail1:
49	DTRACE_PROBE1(fail1, int, rc);
50
51	return (rc);
52}
53
54static void
55sfxge_dma_buffer_mem_free(efsys_mem_t *esmp)
56{
57	esmp->esm_base = NULL;
58	ddi_dma_mem_free(&(esmp->esm_acc_handle));
59	esmp->esm_acc_handle = NULL;
60}
61
62static void
63sfxge_dma_buffer_handle_free(ddi_dma_handle_t *dhandlep)
64{
65	ddi_dma_free_handle(dhandlep);
66	*dhandlep = NULL;
67}
68
69int
70sfxge_dma_buffer_create(efsys_mem_t *esmp, const sfxge_dma_buffer_attr_t *sdbap)
71{
72	int err;
73	int rc;
74	size_t unit;
75	ddi_dma_cookie_t dmac;
76	unsigned int ncookies;
77
78	/* Allocate a DMA handle */
79	err = ddi_dma_alloc_handle(sdbap->sdba_dip, sdbap->sdba_dattrp,
80	    sdbap->sdba_callback, NULL, &(esmp->esm_dma_handle));
81	switch (err) {
82	case DDI_SUCCESS:
83		break;
84
85	case DDI_DMA_BADATTR:
86		rc = EINVAL;
87		goto fail1;
88
89	case DDI_DMA_NORESOURCES:
90		rc = ENOMEM;
91		goto fail1;
92
93	default:
94		rc = EFAULT;
95		goto fail1;
96	}
97
98	/* Allocate some DMA memory */
99	err = ddi_dma_mem_alloc(esmp->esm_dma_handle, sdbap->sdba_length,
100	    sdbap->sdba_devaccp, sdbap->sdba_memflags,
101	    sdbap->sdba_callback, NULL,
102	    &(esmp->esm_base), &unit, &(esmp->esm_acc_handle));
103	switch (err) {
104	case DDI_SUCCESS:
105		break;
106
107	case DDI_FAILURE:
108		/*FALLTHRU*/
109	default:
110		rc = EFAULT;
111		goto fail2;
112	}
113
114	if (sdbap->sdba_zeroinit)
115		bzero(esmp->esm_base, sdbap->sdba_length);
116
117	/* Bind the DMA memory to the DMA handle */
118	/* We aren't handling partial mappings */
119	ASSERT3U(sdbap->sdba_bindflags & DDI_DMA_PARTIAL, !=, DDI_DMA_PARTIAL);
120	err = ddi_dma_addr_bind_handle(esmp->esm_dma_handle, NULL,
121	    esmp->esm_base, sdbap->sdba_length, sdbap->sdba_bindflags,
122	    sdbap->sdba_callback, NULL, &dmac, &ncookies);
123	switch (err) {
124	case DDI_DMA_MAPPED:
125		break;
126
127	case DDI_DMA_INUSE:
128		rc = EEXIST;
129		goto fail3;
130
131	case DDI_DMA_NORESOURCES:
132		rc = ENOMEM;
133		goto fail3;
134
135	case DDI_DMA_NOMAPPING:
136		rc = ENOTSUP;
137		goto fail3;
138
139	case DDI_DMA_TOOBIG:
140		rc = EFBIG;
141		goto fail3;
142
143	default:
144		rc = EFAULT;
145		goto fail3;
146	}
147	ASSERT3U(ncookies, >=, 1);
148	ASSERT3U(ncookies, <=, sdbap->sdba_maxcookies);
149
150	esmp->esm_addr = dmac.dmac_laddress;
151	esmp->esm_size = dmac.dmac_size;
152	DTRACE_PROBE1(addr, efsys_dma_addr_t, esmp->esm_addr);
153
154	return (0);
155
156fail3:
157	DTRACE_PROBE(fail3);
158
159	sfxge_dma_buffer_mem_free(esmp);
160
161fail2:
162	DTRACE_PROBE(fail2);
163
164	sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
165	esmp->esm_dma_handle = NULL;
166
167fail1:
168	DTRACE_PROBE1(fail1, int, rc);
169
170	return (-1);
171}
172
173void
174sfxge_dma_buffer_destroy(efsys_mem_t *esmp)
175{
176	int rc;
177
178	rc = sfxge_dma_buffer_unbind_handle(esmp);
179	if (rc != 0) {
180		cmn_err(CE_WARN, SFXGE_CMN_ERR "DMA Unbind failed rc=%d", rc);
181	}
182	sfxge_dma_buffer_mem_free(esmp);
183	sfxge_dma_buffer_handle_free(&(esmp->esm_dma_handle));
184}
185