Defined more SCSI sense data keys
[AROS.git] / rom / devs / ahci / ahci_aros_bus.c
blobf6a34770700fe71716e0ff431bb3260b49efad54
1 /*
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
6 */
8 #define __OOP_NOMETHODBASES__
10 #include "ahci_aros.h"
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 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));
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 D2(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 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);
67 FreeVec(slab);
69 FreeVec(tag);
70 return 0;
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;
78 if (boundary < 4)
79 boundary = 4;
81 slab = AllocVec(sizeof(*slab), MEMF_ANY | MEMF_CLEAR);
82 if (slab == NULL) {
83 D(bug("%s: Can't allocate %d byte slab header\n", __func__, sizeof(*slab)));
84 return NULL;
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));
90 FreeVec(slab);
91 return NULL;
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);
101 return slab;
104 int bus_dmamem_alloc(bus_dma_tag_t tag, void **vaddr, unsigned flags, bus_dmamap_t *map)
106 void *addr;
107 struct bus_dma_tag_slab *slab;
108 int i;
110 TAILQ_FOREACH(slab, &tag->dt_slabs, sl_node) {
111 if (slab->sl_segfree != 0)
112 break;
115 if (slab == NULL) {
116 slab = bus_dmamem_alloc_slab(tag);
117 if (slab == NULL) {
118 D(bug("%s: %p: Failed to allocate segment\n", __func__, tag));
119 return -ENOMEM;
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);
127 slab->sl_segfree--;
128 break;
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));
137 if (vaddr)
138 *vaddr = addr;
140 *map = addr;
141 return 0;
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);
161 slab->sl_segfree++;
162 break;
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);
172 return 0;
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);
184 return 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);
193 else
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;
204 IPTR INTLine;
205 OOP_AttrBase HiddPCIDeviceAttrBase = dev->dev_AHCIBase->ahci_HiddPCIDeviceAttrBase;
207 resource = AllocPooled(dev->dev_AHCIBase->ahci_MemPool, sizeof(*resource));
208 if (!resource)
209 return NULL;
211 switch (type) {
212 case SYS_RES_IRQ:
213 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_INTLine, &INTLine);
214 resource->res_tag = INTLine;
215 break;
216 case SYS_RES_MEMORY:
217 resource->res_tag = pci_read_config(dev, *rid, 4);
218 break;
221 if (type == SYS_RES_MEMORY && (*rid) >= PCIR_BAR(0) && (*rid) < PCIR_BAR(6)) {
222 struct pHidd_PCIDriver_MapPCI map;
223 IPTR hba_size;
224 OOP_Object *Driver;
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);
234 } else {
235 /* FIXME: Map IRQ? */
236 resource->res_handle = resource->res_tag;
237 resource->res_size = 1;
240 return resource;
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;
249 OOP_Object *Driver;
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));
258 return 0;
261 /* Bus IRQ */
262 AROS_INTH1(bus_intr_wrap, void **, fa)
264 AROS_INTFUNC_INIT
266 driver_intr_t *func = fa[0];
267 void *arg = fa[1];
269 func(arg);
271 return FALSE;
273 AROS_INTFUNC_EXIT
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);
281 void **fa;
283 if (handler == NULL)
284 return ENOMEM;
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];
290 fa[0] = func;
291 fa[1] = arg;
292 handler->is_Data = fa;
294 if (!HIDD_PCIDevice_AddInterrupt(dev->dev_Object, handler))
296 FreeVec(handler);
297 return ENOMEM;
300 *cookiep = handler;
302 return 0;
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);
311 FreeVec(cookie);
313 return 0;