revert 213 commits (to 56092) from the last month. 10 still need work to resolve...
[AROS.git] / rom / devs / ahci / ahci_aros_bus.c
blob36623ede60da0e5596048c2ce9320ac463bd320a
1 /*
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
6 */
8 #include "ahci_aros.h"
10 #define DDMA(x)
12 struct bus_dma_tag_slab {
13 TAILQ_ENTRY(bus_dma_tag_slab) sl_node;
14 APTR sl_memory;
15 APTR sl_segment;
16 int sl_segfree;
17 uint64_t sl_segmap;
20 struct bus_dma_tag {
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;
26 int dt_nsegments;
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)
32 bus_dma_tag_t tag;
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));
38 return -EINVAL;
41 tag = AllocVec(sizeof(*tag), MEMF_ANY | MEMF_CLEAR);
42 if (tag == NULL)
43 return -ENOMEM;
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));
56 (*dmat) = tag;
57 return 0;
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);
68 FreeVec(slab);
70 FreeVec(tag);
71 return 0;
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__));
81 if (boundary < 4)
82 boundary = 4;
84 slab = AllocVec(sizeof(*slab), MEMF_ANY | MEMF_CLEAR);
85 if (slab == NULL) {
86 bug("%s: Can't allocate %d byte slab header\n", __func__, sizeof(*slab));
87 return NULL;
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);
93 FreeVec(slab);
94 return NULL;
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);
104 return slab;
107 int bus_dmamem_alloc(bus_dma_tag_t tag, void **vaddr, unsigned flags, bus_dmamap_t *map)
109 void *addr;
110 struct bus_dma_tag_slab *slab;
111 int i;
112 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__));
114 TAILQ_FOREACH(slab, &tag->dt_slabs, sl_node) {
115 if (slab->sl_segfree != 0)
116 break;
119 if (slab == NULL) {
120 slab = bus_dmamem_alloc_slab(tag);
121 if (slab == NULL) {
122 bug("%s: %p: Failed to allocate segment\n", __func__, tag);
123 return -ENOMEM;
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);
131 slab->sl_segfree--;
132 break;
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));
141 if (vaddr)
142 *vaddr = addr;
144 *map = addr;
145 return 0;
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);
165 slab->sl_segfree++;
166 break;
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);
177 return 0;
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);
190 return 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);
201 else
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;
212 IPTR INTLine;
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));
219 if (!resource)
220 return NULL;
222 switch (type) {
223 case SYS_RES_IRQ:
224 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_INTLine, &INTLine);
225 resource->res_tag = INTLine;
226 break;
227 case SYS_RES_MEMORY:
228 resource->res_tag = pci_read_config(dev, *rid, 4);
229 break;
232 if (type == SYS_RES_MEMORY && (*rid) >= PCIR_BAR(0) && (*rid) < PCIR_BAR(6)) {
233 struct pHidd_PCIDriver_MapPCI map;
234 IPTR hba_size;
235 OOP_Object *Driver;
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);
245 } else {
246 /* FIXME: Map IRQ? */
247 resource->res_handle = resource->res_tag;
248 resource->res_size = 1;
251 return resource;
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;
263 OOP_Object *Driver;
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));
272 return 0;
275 /* Bus IRQ */
276 AROS_INTH1(bus_intr_wrap, void **, fa)
278 AROS_INTFUNC_INIT
280 driver_intr_t *func = fa[0];
281 void *arg = fa[1];
283 func(arg);
285 return FALSE;
287 AROS_INTFUNC_EXIT
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);
295 void **fa;
297 DDMA(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__));
299 if (handler == NULL)
300 return ENOMEM;
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];
306 fa[0] = func;
307 fa[1] = arg;
308 handler->is_Data = fa;
310 if (!HIDD_PCIDevice_AddInterrupt(dev->dev_Object, handler))
312 FreeVec(handler);
313 return ENOMEM;
316 *cookiep = handler;
318 return 0;
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);
329 FreeVec(cookie);
331 return 0;