2 * Copyright (C) 2012-2018, 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
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 DDMA(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 DDMA(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 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
64 for (slab
= TAILQ_FIRST(&tag
->dt_slabs
); slab
;
65 slab
= TAILQ_FIRST(&tag
->dt_slabs
)) {
66 TAILQ_REMOVE(&tag
->dt_slabs
, slab
, sl_node
);
67 FreeVec(slab
->sl_memory
);
74 static struct bus_dma_tag_slab
*bus_dmamem_alloc_slab(bus_dma_tag_t tag
)
76 int boundary
= tag
->dt_boundary
;
77 struct bus_dma_tag_slab
*slab
;
79 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
84 slab
= AllocVec(sizeof(*slab
), MEMF_ANY
| MEMF_CLEAR
);
86 bug("%s: Can't allocate %d byte slab header\n", __func__
, sizeof(*slab
));
90 slab
->sl_memory
= AllocVec(tag
->dt_segsize
* tag
->dt_nsegments
+ boundary
- 4, MEMF_ANY
);
91 if (slab
->sl_memory
== NULL
) {
92 bug("%s: %p: Can't allocate %d bytes for DMA\n", __func__
, tag
, tag
->dt_segsize
* tag
->dt_nsegments
+ boundary
- 4);
97 slab
->sl_segment
= (APTR
)(((IPTR
)slab
->sl_memory
+ boundary
- 4) & ~(boundary
-1));
98 DDMA(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
));
100 slab
->sl_segfree
= tag
->dt_nsegments
;
102 TAILQ_INSERT_TAIL(&tag
->dt_slabs
, slab
, sl_node
);
107 int bus_dmamem_alloc(bus_dma_tag_t tag
, void **vaddr
, unsigned flags
, bus_dmamap_t
*map
)
110 struct bus_dma_tag_slab
*slab
;
112 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
114 TAILQ_FOREACH(slab
, &tag
->dt_slabs
, sl_node
) {
115 if (slab
->sl_segfree
!= 0)
120 slab
= bus_dmamem_alloc_slab(tag
);
122 bug("%s: %p: Failed to allocate segment\n", __func__
, tag
);
127 DDMA(bug("%s: %p: Slab %p 0x%08llx\n", __func__
, tag
, slab
, slab
->sl_segmap
));
128 for (i
= 0; i
< tag
->dt_nsegments
; i
++ ) {
129 if ((slab
->sl_segmap
& (1 << i
)) == 0) {
130 slab
->sl_segmap
|= (1 << i
);
136 addr
= slab
->sl_segment
+ i
* tag
->dt_segsize
;
137 if (flags
& MEMF_CLEAR
)
138 memset(addr
, 0, tag
->dt_segsize
);
140 DDMA(bug("%s: %p: Allocated slot %d, %p: size %d\n", __func__
, tag
, i
, addr
, tag
->dt_maxsegsz
));
148 bus_size_t
bus_dma_tag_getmaxsize(bus_dma_tag_t tag
)
150 return tag
->dt_maxsize
;
153 void bus_dmamem_free(bus_dma_tag_t tag
, void *vaddr
, bus_dmamap_t map
)
155 uintptr_t end_offset
;
156 struct bus_dma_tag_slab
*slab
;
158 end_offset
= tag
->dt_segsize
* (tag
->dt_nsegments
-1);
160 TAILQ_FOREACH(slab
, &tag
->dt_slabs
, sl_node
) {
161 if (vaddr
>= slab
->sl_segment
&& vaddr
<= (slab
->sl_segment
+ end_offset
)) {
162 int slot
= (vaddr
- slab
->sl_segment
) / tag
->dt_segsize
;
163 ASSERT(slab
->sl_segmap
& (1 << slot
));
164 slab
->sl_segmap
&= ~(1 << slot
);
170 ASSERT(slab
!= NULL
);
173 int bus_dmamap_create(bus_dma_tag_t tag
, unsigned flags
, bus_dmamap_t
*map
)
175 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
176 bus_dmamem_alloc(tag
, NULL
, 0, map
);
180 void bus_dmamap_destroy(bus_dma_tag_t tag
, bus_dmamap_t map
)
182 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
183 bus_dmamem_free(tag
, NULL
, map
);
186 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
)
188 bus_dma_segment_t seg
= { .ds_addr
= (bus_addr_t
)data
, .ds_len
= (bus_size_t
)len
};
189 callback(info
, &seg
, 1, 0);
193 void bus_dmamap_sync(bus_dma_tag_t tag
, bus_dmamap_t map
, unsigned flags
)
195 ULONG len
= tag
->dt_maxsegsz
;
197 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
199 if (!(flags
& (1 << 31)))
200 CachePreDMA(map
, &len
, flags
);
202 CachePostDMA(map
, &len
, flags
);
205 void bus_dmamap_unload(bus_dma_tag_t tag
, bus_dmamap_t map
)
209 struct resource
*bus_alloc_resource_any(device_t dev
, enum bus_resource_t type
, int *rid
, u_int flags
)
211 struct resource
*resource
;
213 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
214 OOP_AttrBase HiddPCIDeviceAttrBase
= AHCIBase
->ahci_HiddPCIDeviceAttrBase
;
216 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
218 resource
= AllocPooled(AHCIBase
->ahci_MemPool
, sizeof(*resource
));
224 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_INTLine
, &INTLine
);
225 resource
->res_tag
= INTLine
;
228 resource
->res_tag
= pci_read_config(dev
, *rid
, 4);
232 if (type
== SYS_RES_MEMORY
&& (*rid
) >= PCIR_BAR(0) && (*rid
) < PCIR_BAR(6)) {
233 struct pHidd_PCIDriver_MapPCI map
;
237 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
238 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Size0
+ (((*rid
) - PCIR_BAR(0))/4)*3, &hba_size
);
239 resource
->res_size
= hba_size
;
241 map
.mID
= AHCIBase
->ahci_HiddPCIDriverMethodBase
+ moHidd_PCIDriver_MapPCI
;
242 map
.PCIAddress
= (APTR
)resource
->res_tag
;
243 map
.Length
= resource
->res_size
;
244 resource
->res_handle
= OOP_DoMethod(Driver
, (OOP_Msg
)&map
);
246 /* FIXME: Map IRQ? */
247 resource
->res_handle
= resource
->res_tag
;
248 resource
->res_size
= 1;
254 int bus_release_resource(device_t dev
, enum bus_resource_t type
, int rid
, struct resource
*res
)
256 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
257 OOP_AttrBase HiddPCIDeviceAttrBase
= AHCIBase
->ahci_HiddPCIDeviceAttrBase
;
259 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
261 if (type
== SYS_RES_MEMORY
&& rid
> PCIR_BAR(0) && rid
< PCIR_BAR(6)) {
262 struct pHidd_PCIDriver_UnmapPCI unmap
;
265 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
266 unmap
.mID
= AHCIBase
->ahci_HiddPCIDriverMethodBase
+ moHidd_PCIDriver_UnmapPCI
;
267 unmap
.CPUAddress
= (APTR
)res
->res_handle
;
268 unmap
.Length
= res
->res_size
;
269 OOP_DoMethod(Driver
, (OOP_Msg
)&unmap
);
271 FreePooled(AHCIBase
->ahci_MemPool
, res
, sizeof(*res
));
276 AROS_INTH1(bus_intr_wrap
, void **, fa
)
280 driver_intr_t
*func
= fa
[0];
290 int bus_setup_intr(device_t dev
, struct resource
*r
, int flags
, driver_intr_t func
, void *arg
, void **cookiep
, void *serializer
)
292 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
293 OOP_MethodID HiddPCIDeviceBase
= AHCIBase
->ahci_HiddPCIDeviceMethodBase
;
294 struct Interrupt
*handler
= AllocVec(sizeof(struct Interrupt
)+sizeof(void *)*2, MEMF_PUBLIC
| MEMF_CLEAR
);
297 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
302 handler
->is_Node
.ln_Pri
= 10;
303 handler
->is_Node
.ln_Name
= device_get_name(dev
);
304 handler
->is_Code
= (VOID_FUNC
)bus_intr_wrap
;
305 fa
= (void **)&handler
[1];
308 handler
->is_Data
= fa
;
310 if (!HIDD_PCIDevice_AddInterrupt(dev
->dev_Object
, handler
))
321 int bus_teardown_intr(device_t dev
, struct resource
*r
, void *cookie
)
323 struct AHCIBase
*AHCIBase
= dev
->dev_AHCIBase
;
324 OOP_MethodID HiddPCIDeviceBase
= AHCIBase
->ahci_HiddPCIDeviceMethodBase
;
326 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
328 HIDD_PCIDevice_RemoveInterrupt(dev
->dev_Object
, cookie
);