2 * Copyright (c) 1998 - 2006 Søren Schmidt <sos@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/sys/dev/ata/ata-dma.c,v 1.141 2006/01/05 21:27:19 sos Exp $
27 * $DragonFly: src/sys/dev/disk/nata/ata-dma.c,v 1.2 2007/06/01 00:31:15 dillon Exp $
32 #include <sys/param.h>
34 #include <sys/bus_dma.h>
35 #include <sys/endian.h>
36 #include <sys/malloc.h>
39 #include <machine/bus_dma.h>
46 static void ata_dmaalloc(device_t
);
47 static void ata_dmafree(device_t
);
48 static void ata_dmasetprd(void *, bus_dma_segment_t
*, int, int);
49 static int ata_dmaload(device_t
, caddr_t
, int32_t, int, void *, int *);
50 static int ata_dmaunload(device_t
);
53 static MALLOC_DEFINE(M_ATADMA
, "ata_dma", "ATA driver DMA");
56 #define MAXTABSZ PAGE_SIZE
57 #define MAXWSPCSZ PAGE_SIZE*2
59 struct ata_dc_cb_args
{
65 ata_dmainit(device_t dev
)
67 struct ata_channel
*ch
= device_get_softc(dev
);
69 if ((ch
->dma
= kmalloc(sizeof(struct ata_dma
), M_ATADMA
, M_NOWAIT
|M_ZERO
))) {
70 ch
->dma
->alloc
= ata_dmaalloc
;
71 ch
->dma
->free
= ata_dmafree
;
72 ch
->dma
->setprd
= ata_dmasetprd
;
73 ch
->dma
->load
= ata_dmaload
;
74 ch
->dma
->unload
= ata_dmaunload
;
75 ch
->dma
->alignment
= 2;
76 ch
->dma
->boundary
= 128 * DEV_BSIZE
;
77 ch
->dma
->segsize
= 128 * DEV_BSIZE
;
78 ch
->dma
->max_iosize
= 128 * DEV_BSIZE
;
79 ch
->dma
->max_address
= BUS_SPACE_MAXADDR_32BIT
;
84 ata_dmasetupc_cb(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
86 struct ata_dc_cb_args
*cba
= (struct ata_dc_cb_args
*)xsc
;
88 if (!(cba
->error
= error
))
89 cba
->maddr
= segs
[0].ds_addr
;
93 ata_dmaalloc(device_t dev
)
95 struct ata_channel
*ch
= device_get_softc(dev
);
96 struct ata_dc_cb_args ccba
;
98 if (bus_dma_tag_create(NULL
, ch
->dma
->alignment
, 0,
99 ch
->dma
->max_address
, BUS_SPACE_MAXADDR
,
100 NULL
, NULL
, ch
->dma
->max_iosize
,
101 ATA_DMA_ENTRIES
, ch
->dma
->segsize
,
102 0, &ch
->dma
->dmatag
))
105 if (bus_dma_tag_create(ch
->dma
->dmatag
, PAGE_SIZE
, PAGE_SIZE
,
106 ch
->dma
->max_address
, BUS_SPACE_MAXADDR
,
107 NULL
, NULL
, MAXTABSZ
, 1, MAXTABSZ
,
108 0, &ch
->dma
->sg_tag
))
111 if (bus_dma_tag_create(ch
->dma
->dmatag
,ch
->dma
->alignment
,ch
->dma
->boundary
,
112 ch
->dma
->max_address
, BUS_SPACE_MAXADDR
,
113 NULL
, NULL
, ch
->dma
->max_iosize
,
114 ATA_DMA_ENTRIES
, ch
->dma
->segsize
,
115 0, &ch
->dma
->data_tag
))
118 if (bus_dmamem_alloc(ch
->dma
->sg_tag
, (void **)&ch
->dma
->sg
, 0,
122 if (bus_dmamap_load(ch
->dma
->sg_tag
, ch
->dma
->sg_map
, ch
->dma
->sg
,
123 MAXTABSZ
, ata_dmasetupc_cb
, &ccba
, 0) || ccba
.error
) {
124 bus_dmamem_free(ch
->dma
->sg_tag
, ch
->dma
->sg
, ch
->dma
->sg_map
);
127 ch
->dma
->sg_bus
= ccba
.maddr
;
129 if (bus_dmamap_create(ch
->dma
->data_tag
, 0, &ch
->dma
->data_map
))
132 if (bus_dma_tag_create(ch
->dma
->dmatag
, PAGE_SIZE
, 64 * 1024,
133 ch
->dma
->max_address
, BUS_SPACE_MAXADDR
,
134 NULL
, NULL
, MAXWSPCSZ
, 1, MAXWSPCSZ
,
135 0, &ch
->dma
->work_tag
))
138 if (bus_dmamem_alloc(ch
->dma
->work_tag
, (void **)&ch
->dma
->work
, 0,
142 if (bus_dmamap_load(ch
->dma
->work_tag
, ch
->dma
->work_map
,ch
->dma
->work
,
143 MAXWSPCSZ
, ata_dmasetupc_cb
, &ccba
, 0) || ccba
.error
) {
144 bus_dmamem_free(ch
->dma
->work_tag
,ch
->dma
->work
, ch
->dma
->work_map
);
147 ch
->dma
->work_bus
= ccba
.maddr
;
152 device_printf(dev
, "WARNING - DMA allocation failed, disabling DMA\n");
154 kfree(ch
->dma
, M_ATADMA
);
159 ata_dmafree(device_t dev
)
161 struct ata_channel
*ch
= device_get_softc(dev
);
163 if (ch
->dma
->work_bus
) {
164 bus_dmamap_unload(ch
->dma
->work_tag
, ch
->dma
->work_map
);
165 bus_dmamem_free(ch
->dma
->work_tag
, ch
->dma
->work
, ch
->dma
->work_map
);
166 ch
->dma
->work_bus
= 0;
167 ch
->dma
->work_map
= NULL
;
168 ch
->dma
->work
= NULL
;
170 if (ch
->dma
->work_tag
) {
171 bus_dma_tag_destroy(ch
->dma
->work_tag
);
172 ch
->dma
->work_tag
= NULL
;
174 if (ch
->dma
->sg_bus
) {
175 bus_dmamap_unload(ch
->dma
->sg_tag
, ch
->dma
->sg_map
);
176 bus_dmamem_free(ch
->dma
->sg_tag
, ch
->dma
->sg
, ch
->dma
->sg_map
);
178 ch
->dma
->sg_map
= NULL
;
181 if (ch
->dma
->data_map
) {
182 bus_dmamap_destroy(ch
->dma
->data_tag
, ch
->dma
->data_map
);
183 ch
->dma
->data_map
= NULL
;
185 if (ch
->dma
->sg_tag
) {
186 bus_dma_tag_destroy(ch
->dma
->sg_tag
);
187 ch
->dma
->sg_tag
= NULL
;
189 if (ch
->dma
->data_tag
) {
190 bus_dma_tag_destroy(ch
->dma
->data_tag
);
191 ch
->dma
->data_tag
= NULL
;
193 if (ch
->dma
->dmatag
) {
194 bus_dma_tag_destroy(ch
->dma
->dmatag
);
195 ch
->dma
->dmatag
= NULL
;
200 ata_dmasetprd(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
202 struct ata_dmasetprd_args
*args
= xsc
;
203 struct ata_dma_prdentry
*prd
= args
->dmatab
;
206 if ((args
->error
= error
))
209 for (i
= 0; i
< nsegs
; i
++) {
210 prd
[i
].addr
= htole32(segs
[i
].ds_addr
);
211 prd
[i
].count
= htole32(segs
[i
].ds_len
);
213 prd
[i
- 1].count
|= htole32(ATA_DMA_EOT
);
218 ata_dmaload(device_t dev
, caddr_t data
, int32_t count
, int dir
,
219 void *addr
, int *entries
)
221 struct ata_channel
*ch
= device_get_softc(dev
);
222 struct ata_dmasetprd_args cba
;
225 if (ch
->dma
->flags
& ATA_DMA_LOADED
) {
226 device_printf(dev
, "FAILURE - already active DMA on this device\n");
230 device_printf(dev
, "FAILURE - zero length DMA transfer attempted\n");
233 if (((uintptr_t)data
& (ch
->dma
->alignment
- 1)) ||
234 (count
& (ch
->dma
->alignment
- 1))) {
235 device_printf(dev
, "FAILURE - non aligned DMA transfer attempted\n");
238 if (count
> ch
->dma
->max_iosize
) {
239 device_printf(dev
, "FAILURE - oversized DMA transfer attempt %d > %d\n",
240 count
, ch
->dma
->max_iosize
);
246 if ((error
= bus_dmamap_load(ch
->dma
->data_tag
, ch
->dma
->data_map
,
247 data
, count
, ch
->dma
->setprd
, &cba
,
248 BUS_DMA_NOWAIT
)) || (error
= cba
.error
))
251 *entries
= cba
.nsegs
;
253 bus_dmamap_sync(ch
->dma
->sg_tag
, ch
->dma
->sg_map
, BUS_DMASYNC_PREWRITE
);
255 bus_dmamap_sync(ch
->dma
->data_tag
, ch
->dma
->data_map
,
256 dir
? BUS_DMASYNC_PREREAD
: BUS_DMASYNC_PREWRITE
);
258 ch
->dma
->cur_iosize
= count
;
259 ch
->dma
->flags
= dir
? (ATA_DMA_LOADED
| ATA_DMA_READ
) : ATA_DMA_LOADED
;
264 ata_dmaunload(device_t dev
)
266 struct ata_channel
*ch
= device_get_softc(dev
);
268 if (ch
->dma
->flags
& ATA_DMA_LOADED
) {
269 bus_dmamap_sync(ch
->dma
->sg_tag
, ch
->dma
->sg_map
,
270 BUS_DMASYNC_POSTWRITE
);
272 bus_dmamap_sync(ch
->dma
->data_tag
, ch
->dma
->data_map
,
273 (ch
->dma
->flags
& ATA_DMA_READ
) ?
274 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
275 bus_dmamap_unload(ch
->dma
->data_tag
, ch
->dma
->data_map
);
277 ch
->dma
->cur_iosize
= 0;
278 ch
->dma
->flags
&= ~ATA_DMA_LOADED
;