2 * Copyright (c) 1998 - 2008 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.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/endian.h>
35 #include <sys/malloc.h>
38 #include <sys/taskqueue.h>
41 #include <machine/bus.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/ata/ata-all.h>
45 #include <dev/ata/ata-pci.h>
48 static void ata_dmafini(device_t dev
);
49 static void ata_dmasetupc_cb(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
);
50 static void ata_dmaalloc(device_t dev
);
51 static void ata_dmafree(device_t dev
);
52 static void ata_dmasetprd(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
);
53 static int ata_dmaload(struct ata_request
*request
, void *addr
, int *nsegs
);
54 static int ata_dmaunload(struct ata_request
*request
);
57 static MALLOC_DEFINE(M_ATADMA
, "ata_dma", "ATA driver DMA");
60 #define MAXTABSZ PAGE_SIZE
61 #define MAXWSPCSZ PAGE_SIZE*2
63 struct ata_dc_cb_args
{
69 ata_dmainit(device_t dev
)
71 struct ata_channel
*ch
= device_get_softc(dev
);
72 struct ata_dc_cb_args dcba
;
74 ch
->dma
.alloc
= ata_dmaalloc
;
75 ch
->dma
.free
= ata_dmafree
;
76 ch
->dma
.setprd
= ata_dmasetprd
;
77 ch
->dma
.load
= ata_dmaload
;
78 ch
->dma
.unload
= ata_dmaunload
;
79 ch
->dma
.alignment
= 2;
80 ch
->dma
.boundary
= 65536;
81 ch
->dma
.segsize
= 63536;
82 ch
->dma
.max_iosize
= 128 * DEV_BSIZE
;
83 ch
->dma
.max_address
= BUS_SPACE_MAXADDR_32BIT
;
84 ch
->dma
.dma_slots
= 2;
86 if (bus_dma_tag_create(bus_get_dma_tag(dev
), ch
->dma
.alignment
, 0,
87 ch
->dma
.max_address
, BUS_SPACE_MAXADDR
,
88 NULL
, NULL
, ch
->dma
.max_iosize
,
89 ATA_DMA_ENTRIES
, ch
->dma
.segsize
,
90 0, NULL
, NULL
, &ch
->dma
.dmatag
))
93 if (bus_dma_tag_create(ch
->dma
.dmatag
, PAGE_SIZE
, 64 * 1024,
94 ch
->dma
.max_address
, BUS_SPACE_MAXADDR
,
95 NULL
, NULL
, MAXWSPCSZ
, 1, MAXWSPCSZ
,
96 0, NULL
, NULL
, &ch
->dma
.work_tag
))
99 if (bus_dmamem_alloc(ch
->dma
.work_tag
, (void **)&ch
->dma
.work
, 0,
103 if (bus_dmamap_load(ch
->dma
.work_tag
, ch
->dma
.work_map
, ch
->dma
.work
,
104 MAXWSPCSZ
, ata_dmasetupc_cb
, &dcba
, 0) ||
106 bus_dmamem_free(ch
->dma
.work_tag
, ch
->dma
.work
, ch
->dma
.work_map
);
109 ch
->dma
.work_bus
= dcba
.maddr
;
113 device_printf(dev
, "WARNING - DMA initialization failed, disabling DMA\n");
118 ata_dmafini(device_t dev
)
120 struct ata_channel
*ch
= device_get_softc(dev
);
122 if (ch
->dma
.work_bus
) {
123 bus_dmamap_unload(ch
->dma
.work_tag
, ch
->dma
.work_map
);
124 bus_dmamem_free(ch
->dma
.work_tag
, ch
->dma
.work
, ch
->dma
.work_map
);
125 ch
->dma
.work_bus
= 0;
126 ch
->dma
.work_map
= NULL
;
129 if (ch
->dma
.work_tag
) {
130 bus_dma_tag_destroy(ch
->dma
.work_tag
);
131 ch
->dma
.work_tag
= NULL
;
133 if (ch
->dma
.dmatag
) {
134 bus_dma_tag_destroy(ch
->dma
.dmatag
);
135 ch
->dma
.dmatag
= NULL
;
140 ata_dmasetupc_cb(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
142 struct ata_dc_cb_args
*dcba
= (struct ata_dc_cb_args
*)xsc
;
144 if (!(dcba
->error
= error
))
145 dcba
->maddr
= segs
[0].ds_addr
;
149 ata_dmaalloc(device_t dev
)
151 struct ata_channel
*ch
= device_get_softc(dev
);
152 struct ata_dc_cb_args dcba
;
155 /* alloc and setup needed dma slots */
156 bzero(ch
->dma
.slot
, sizeof(struct ata_dmaslot
) * ATA_DMA_SLOTS
);
157 for (i
= 0; i
< ch
->dma
.dma_slots
; i
++) {
158 struct ata_dmaslot
*slot
= &ch
->dma
.slot
[i
];
160 if (bus_dma_tag_create(ch
->dma
.dmatag
, PAGE_SIZE
, PAGE_SIZE
,
161 ch
->dma
.max_address
, BUS_SPACE_MAXADDR
,
162 NULL
, NULL
, PAGE_SIZE
, 1, PAGE_SIZE
,
163 0, NULL
, NULL
, &slot
->sg_tag
)) {
164 device_printf(ch
->dev
, "FAILURE - create sg_tag\n");
168 if (bus_dmamem_alloc(slot
->sg_tag
, (void **)&slot
->sg
,
170 device_printf(ch
->dev
, "FAILURE - alloc sg_map\n");
174 if (bus_dmamap_load(slot
->sg_tag
, slot
->sg_map
, slot
->sg
, MAXTABSZ
,
175 ata_dmasetupc_cb
, &dcba
, 0) || dcba
.error
) {
176 device_printf(ch
->dev
, "FAILURE - load sg\n");
179 slot
->sg_bus
= dcba
.maddr
;
181 if (bus_dma_tag_create(ch
->dma
.dmatag
,
182 ch
->dma
.alignment
, ch
->dma
.boundary
,
183 ch
->dma
.max_address
, BUS_SPACE_MAXADDR
,
184 NULL
, NULL
, ch
->dma
.max_iosize
,
185 ATA_DMA_ENTRIES
, ch
->dma
.segsize
,
186 BUS_DMA_ALLOCNOW
, NULL
, NULL
, &slot
->data_tag
)) {
187 device_printf(ch
->dev
, "FAILURE - create data_tag\n");
191 if (bus_dmamap_create(slot
->data_tag
, 0, &slot
->data_map
)) {
192 device_printf(ch
->dev
, "FAILURE - create data_map\n");
200 device_printf(dev
, "WARNING - DMA allocation failed, disabling DMA\n");
205 ata_dmafree(device_t dev
)
207 struct ata_channel
*ch
= device_get_softc(dev
);
210 /* free all dma slots */
211 for (i
= 0; i
< ATA_DMA_SLOTS
; i
++) {
212 struct ata_dmaslot
*slot
= &ch
->dma
.slot
[i
];
215 bus_dmamap_unload(slot
->sg_tag
, slot
->sg_map
);
219 bus_dmamem_free(slot
->sg_tag
, slot
->sg
, slot
->sg_map
);
220 bus_dmamap_destroy(slot
->sg_tag
, slot
->sg_map
);
224 if (slot
->data_map
) {
225 bus_dmamap_destroy(slot
->data_tag
, slot
->data_map
);
226 slot
->data_map
= NULL
;
229 bus_dma_tag_destroy(slot
->sg_tag
);
232 if (slot
->data_tag
) {
233 bus_dma_tag_destroy(slot
->data_tag
);
234 slot
->data_tag
= NULL
;
240 ata_dmasetprd(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
242 struct ata_dmasetprd_args
*args
= xsc
;
243 struct ata_dma_prdentry
*prd
= args
->dmatab
;
246 if ((args
->error
= error
))
249 for (i
= 0; i
< nsegs
; i
++) {
250 prd
[i
].addr
= htole32(segs
[i
].ds_addr
);
251 prd
[i
].count
= htole32(segs
[i
].ds_len
);
253 prd
[i
- 1].count
|= htole32(ATA_DMA_EOT
);
254 KASSERT(nsegs
<= ATA_DMA_ENTRIES
, ("too many DMA segment entries\n"));
259 ata_dmaload(struct ata_request
*request
, void *addr
, int *entries
)
261 struct ata_channel
*ch
= device_get_softc(request
->parent
);
262 struct ata_device
*atadev
= device_get_softc(request
->dev
);
263 struct ata_dmasetprd_args dspa
;
266 ATA_DEBUG_RQ(request
, "dmaload");
269 device_printf(request
->dev
,
270 "FAILURE - already active DMA on this device\n");
273 if (!request
->bytecount
) {
274 device_printf(request
->dev
,
275 "FAILURE - zero length DMA transfer attempted\n");
278 if (((uintptr_t)(request
->data
) & (ch
->dma
.alignment
- 1)) ||
279 (request
->bytecount
& (ch
->dma
.alignment
- 1))) {
280 device_printf(request
->dev
,
281 "FAILURE - non aligned DMA transfer attempted\n");
284 if (request
->bytecount
> ch
->dma
.max_iosize
) {
285 device_printf(request
->dev
,
286 "FAILURE - oversized DMA transfer attempt %d > %d\n",
287 request
->bytecount
, ch
->dma
.max_iosize
);
291 /* set our slot, unit for simplicity XXX SOS NCQ will change that */
292 request
->dma
= &ch
->dma
.slot
[atadev
->unit
];
297 dspa
.dmatab
= request
->dma
->sg
;
299 if ((error
= bus_dmamap_load(request
->dma
->data_tag
, request
->dma
->data_map
,
300 request
->data
, request
->bytecount
,
301 ch
->dma
.setprd
, &dspa
, BUS_DMA_NOWAIT
)) ||
302 (error
= dspa
.error
)) {
303 device_printf(request
->dev
, "FAILURE - load data\n");
308 *entries
= dspa
.nsegs
;
310 bus_dmamap_sync(request
->dma
->sg_tag
, request
->dma
->sg_map
,
311 BUS_DMASYNC_PREWRITE
);
312 bus_dmamap_sync(request
->dma
->data_tag
, request
->dma
->data_map
,
313 (request
->flags
& ATA_R_READ
) ?
314 BUS_DMASYNC_PREREAD
: BUS_DMASYNC_PREWRITE
);
318 ata_dmaunload(request
);
323 ata_dmaunload(struct ata_request
*request
)
325 ATA_DEBUG_RQ(request
, "dmaunload");
328 bus_dmamap_sync(request
->dma
->sg_tag
, request
->dma
->sg_map
,
329 BUS_DMASYNC_POSTWRITE
);
330 bus_dmamap_sync(request
->dma
->data_tag
, request
->dma
->data_map
,
331 (request
->flags
& ATA_R_READ
) ?
332 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
334 bus_dmamap_unload(request
->dma
->data_tag
, request
->dma
->data_map
);