2 * Copyright (C) 2012-2013, The AROS Development Team. All rights reserved.
3 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
8 #define __OOP_NOMETHODBASES__
10 #include "ahci_aros.h"
12 struct bus_dma_tag_slab
{
13 TAILQ_ENTRY(bus_dma_tag_slab
) sl_node
;
21 bus_size_t dt_boundary
;
22 bus_size_t dt_alignment
;
23 bus_size_t dt_maxsize
;
24 bus_size_t dt_maxsegsz
;
25 bus_size_t dt_segsize
;
27 TAILQ_HEAD(, bus_dma_tag_slab
) dt_slabs
;
30 int bus_dma_tag_create(bus_dma_tag_t parent
, bus_size_t alignment
, bus_size_t boundary
, bus_addr_t lowaddr
, bus_addr_t highaddr
, bus_dma_filter_t
*filter
, void *filterarg
, bus_size_t maxsize
, int nsegments
, bus_size_t maxsegsz
, int flags
, bus_dma_tag_t
*dmat
)
34 D2(bug("%s: Allocating tag, %d objects of size %d, aligned by %d\n", __func__
, nsegments
, maxsegsz
, alignment
));
36 if (nsegments
> BUS_DMA_MAX_SEGMENTS
) {
37 D(bug("%s: Too many segments, max is %d\n", __func__
, BUS_DMA_MAX_SEGMENTS
));
41 tag
= AllocVec(sizeof(*tag
), MEMF_ANY
| MEMF_CLEAR
);
45 tag
->dt_boundary
= boundary
;
46 tag
->dt_segsize
= (maxsegsz
+ alignment
-1) & ~(alignment
- 1);
47 tag
->dt_nsegments
= nsegments
;
48 tag
->dt_alignment
= alignment
;
49 tag
->dt_maxsize
= maxsize
;
50 tag
->dt_maxsegsz
= maxsegsz
;
52 TAILQ_INIT(&tag
->dt_slabs
);
54 D2(bug("%s: %p: Tag created\n", __func__
, tag
));
60 int bus_dma_tag_destroy(bus_dma_tag_t tag
)
62 struct bus_dma_tag_slab
*slab
;
63 for (slab
= TAILQ_FIRST(&tag
->dt_slabs
); slab
;
64 slab
= TAILQ_FIRST(&tag
->dt_slabs
)) {
65 TAILQ_REMOVE(&tag
->dt_slabs
, slab
, sl_node
);
66 FreeVec(slab
->sl_memory
);
73 static struct bus_dma_tag_slab
*bus_dmamem_alloc_slab(bus_dma_tag_t tag
)
75 int boundary
= tag
->dt_boundary
;
76 struct bus_dma_tag_slab
*slab
;
81 slab
= AllocVec(sizeof(*slab
), MEMF_ANY
| MEMF_CLEAR
);
83 D(bug("%s: Can't allocate %d byte slab header\n", __func__
, sizeof(*slab
)));
87 slab
->sl_memory
= AllocVec(tag
->dt_segsize
* tag
->dt_nsegments
+ boundary
- 4, MEMF_ANY
);
88 if (slab
->sl_memory
== NULL
) {
89 D(bug("%s: %p: Can't allocate %d bytes for DMA\n", __func__
, tag
, tag
->dt_segsize
* tag
->dt_nsegments
+ boundary
- 4));
94 slab
->sl_segment
= (APTR
)(((IPTR
)slab
->sl_memory
+ boundary
- 4) & ~(boundary
-1));
95 D2(bug("%s: %p: Memory %p, %dx%d segments at %p\n", __func__
, tag
, slab
->sl_memory
, tag
->dt_nsegments
, tag
->dt_maxsegsz
, slab
->sl_segment
));
97 slab
->sl_segfree
= tag
->dt_nsegments
;
99 TAILQ_INSERT_TAIL(&tag
->dt_slabs
, slab
, sl_node
);
104 int bus_dmamem_alloc(bus_dma_tag_t tag
, void **vaddr
, unsigned flags
, bus_dmamap_t
*map
)
107 struct bus_dma_tag_slab
*slab
;
110 TAILQ_FOREACH(slab
, &tag
->dt_slabs
, sl_node
) {
111 if (slab
->sl_segfree
!= 0)
116 slab
= bus_dmamem_alloc_slab(tag
);
118 D(bug("%s: %p: Failed to allocate segment\n", __func__
, tag
));
123 D2(bug("%s: %p: Slab %p 0x%08llx\n", __func__
, tag
, slab
, slab
->sl_segmap
));
124 for (i
= 0; i
< tag
->dt_nsegments
; i
++ ) {
125 if ((slab
->sl_segmap
& (1 << i
)) == 0) {
126 slab
->sl_segmap
|= (1 << i
);
132 addr
= slab
->sl_segment
+ i
* tag
->dt_segsize
;
133 if (flags
& MEMF_CLEAR
)
134 memset(addr
, 0, tag
->dt_segsize
);
136 D2(bug("%s: %p: Allocated slot %d, %p: size %d\n", __func__
, tag
, i
, addr
, tag
->dt_maxsegsz
));
144 bus_size_t
bus_dma_tag_getmaxsize(bus_dma_tag_t tag
)
146 return tag
->dt_maxsize
;
149 void bus_dmamem_free(bus_dma_tag_t tag
, void *vaddr
, bus_dmamap_t map
)
151 uintptr_t end_offset
;
152 struct bus_dma_tag_slab
*slab
;
154 end_offset
= tag
->dt_segsize
* (tag
->dt_nsegments
-1);
156 TAILQ_FOREACH(slab
, &tag
->dt_slabs
, sl_node
) {
157 if (vaddr
>= slab
->sl_segment
&& vaddr
<= (slab
->sl_segment
+ end_offset
)) {
158 int slot
= (vaddr
- slab
->sl_segment
) / tag
->dt_segsize
;
159 ASSERT(slab
->sl_segmap
& (1 << slot
));
160 slab
->sl_segmap
&= ~(1 << slot
);
166 ASSERT(slab
!= NULL
);
169 int bus_dmamap_create(bus_dma_tag_t tag
, unsigned flags
, bus_dmamap_t
*map
)
171 bus_dmamem_alloc(tag
, NULL
, 0, map
);
175 void bus_dmamap_destroy(bus_dma_tag_t tag
, bus_dmamap_t map
)
177 bus_dmamem_free(tag
, NULL
, map
);
180 int bus_dmamap_load(bus_dma_tag_t tag
, bus_dmamap_t map
, void *data
, size_t len
, bus_dmamap_callback_t
*callback
, void *info
, unsigned flags
)
182 bus_dma_segment_t seg
= { .ds_addr
= (bus_addr_t
)data
, .ds_len
= (bus_size_t
)len
};
183 callback(info
, &seg
, 1, 0);
187 void bus_dmamap_sync(bus_dma_tag_t tag
, bus_dmamap_t map
, unsigned flags
)
189 ULONG len
= tag
->dt_maxsegsz
;
191 if (!(flags
& (1 << 31)))
192 CachePreDMA(map
, &len
, flags
);
194 CachePostDMA(map
, &len
, flags
);
197 void bus_dmamap_unload(bus_dma_tag_t tag
, bus_dmamap_t map
)
201 struct resource
*bus_alloc_resource_any(device_t dev
, enum bus_resource_t type
, int *rid
, u_int flags
)
203 struct resource
*resource
;
205 OOP_AttrBase HiddPCIDeviceAttrBase
= dev
->dev_AHCIBase
->ahci_HiddPCIDeviceAttrBase
;
207 resource
= AllocPooled(dev
->dev_AHCIBase
->ahci_MemPool
, sizeof(*resource
));
213 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_INTLine
, &INTLine
);
214 resource
->res_tag
= INTLine
;
217 resource
->res_tag
= pci_read_config(dev
, *rid
, 4);
221 if (type
== SYS_RES_MEMORY
&& (*rid
) >= PCIR_BAR(0) && (*rid
) < PCIR_BAR(6)) {
222 struct pHidd_PCIDriver_MapPCI map
;
226 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
227 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Size0
+ (((*rid
) - PCIR_BAR(0))/4)*3, &hba_size
);
228 resource
->res_size
= hba_size
;
230 map
.mID
= dev
->dev_AHCIBase
->ahci_HiddPCIDriverMethodBase
+ moHidd_PCIDriver_MapPCI
;
231 map
.PCIAddress
= (APTR
)resource
->res_tag
;
232 map
.Length
= resource
->res_size
;
233 resource
->res_handle
= OOP_DoMethod(Driver
, (OOP_Msg
)&map
);
235 /* FIXME: Map IRQ? */
236 resource
->res_handle
= resource
->res_tag
;
237 resource
->res_size
= 1;
243 int bus_release_resource(device_t dev
, enum bus_resource_t type
, int rid
, struct resource
*res
)
245 OOP_AttrBase HiddPCIDeviceAttrBase
= dev
->dev_AHCIBase
->ahci_HiddPCIDeviceAttrBase
;
247 if (type
== SYS_RES_MEMORY
&& rid
> PCIR_BAR(0) && rid
< PCIR_BAR(6)) {
248 struct pHidd_PCIDriver_UnmapPCI unmap
;
251 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
252 unmap
.mID
= dev
->dev_AHCIBase
->ahci_HiddPCIDriverMethodBase
+ moHidd_PCIDriver_UnmapPCI
;
253 unmap
.CPUAddress
= (APTR
)res
->res_handle
;
254 unmap
.Length
= res
->res_size
;
255 OOP_DoMethod(Driver
, (OOP_Msg
)&unmap
);
257 FreePooled(dev
->dev_AHCIBase
->ahci_MemPool
, res
, sizeof(*res
));
262 AROS_INTH1(bus_intr_wrap
, void **, fa
)
266 driver_intr_t
*func
= fa
[0];
276 int bus_setup_intr(device_t dev
, struct resource
*r
, int flags
, driver_intr_t func
, void *arg
, void **cookiep
, void *serializer
)
278 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
279 OOP_MethodID HiddPCIDeviceBase
= AHCIBase
->ahci_HiddPCIDeviceMethodBase
;
280 struct Interrupt
*handler
= AllocVec(sizeof(struct Interrupt
)+sizeof(void *)*2, MEMF_PUBLIC
| MEMF_CLEAR
);
286 handler
->is_Node
.ln_Pri
= 10;
287 handler
->is_Node
.ln_Name
= device_get_name(dev
);
288 handler
->is_Code
= (VOID_FUNC
)bus_intr_wrap
;
289 fa
= (void **)&handler
[1];
292 handler
->is_Data
= fa
;
294 if (!HIDD_PCIDevice_AddInterrupt(dev
->dev_Object
, handler
))
305 int bus_teardown_intr(device_t dev
, struct resource
*r
, void *cookie
)
307 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
308 OOP_MethodID HiddPCIDeviceBase
= AHCIBase
->ahci_HiddPCIDeviceMethodBase
;
310 HIDD_PCIDevice_RemoveInterrupt(dev
->dev_Object
, cookie
);