ahci.device: Clean up some memory allocations
[AROS.git] / rom / devs / ahci / ahci_aros.h
blob5838819ded7ad371290510540564e1e3137a9c3f
1 /*
2 * Copyright (C) 2012, 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 #ifndef AHCI_AROS_H
9 #define AHCI_AROS_H
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <errno.h>
14 #include <assert.h>
16 #include <sys/types.h>
17 #include <sys/select.h>
19 #include <aros/debug.h>
21 #include <proto/exec.h>
22 #include <proto/oop.h>
24 #include <hidd/pci.h>
26 #include "ahci_intern.h"
27 #include "pci_ids.h"
29 #undef kprintf
30 #define kprintf(fmt, args...) device_printf(NULL, fmt ,##args)
32 #ifdef __GNUC__
33 #define __packed __attribute__((__packed__))
34 #else
35 #error Define __packed appropriately for your compiler!
36 #endif
38 typedef uint8_t u_int8_t;
39 typedef uint16_t u_int16_t;
40 typedef uint32_t u_int32_t;
41 typedef uint64_t u_int64_t;
42 typedef unsigned int u_int;
44 #define le16toh(x) AROS_LE2WORD(x)
45 #define le32toh(x) AROS_LE2LONG(x)
46 #define htole32(x) AROS_LONG2LE(x)
47 #define htole16(x) AROS_WORD2LE(x)
49 #define PAGE_SIZE 4096
51 typedef struct {
52 struct MinNode dev_Node;
53 OOP_Object *dev_Object;
54 struct AHCIBase *dev_AHCIBase;
55 struct ahci_softc *dev_softc;
56 ULONG dev_HostID;
57 } *device_t;
59 /* Kernel stuff */
61 #define KKASSERT(expr) assert(expr)
63 int kvsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap);
64 int kvsnprintf(char *str, size_t size, const char *format, va_list ap);
65 int ksnprintf(char *buff, size_t len, const char *fmt, ...);
66 int kvcprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap);
68 static inline void bug_c(int c, void *info)
70 RawPutChar(c);
73 static inline int device_printf(device_t dev, const char *fmt, ...)
75 va_list args;
76 int err;
77 va_start(args, fmt);
78 err = kvcprintf(fmt, bug_c, NULL, 10, args);
79 va_end(args);
80 return err;
84 #define panic(fmt, args...) do { Forbid(); device_printf(NULL, fmt ,##args); Disable(); for (;;); } while (0);
86 static inline void *kmalloc(size_t size, unsigned where, unsigned flags)
88 return AllocVec(size, flags);
91 static inline void kfree(void *ptr, unsigned where)
93 FreeVec(ptr);
96 static inline void crit_enter(void)
98 Disable();
101 static inline void crit_exit(void)
103 Enable();
106 typedef struct Task *thread_t;
108 static inline int kthread_create(void (*func)(void *), void *arg, thread_t *tdp, const char *fmt, ...)
110 va_list args;
111 char name[64];
113 va_start(args, fmt);
114 kvsnprintf(name, sizeof(name), fmt, args);
115 va_end(args);
117 name[sizeof(name)-1] = 0;
119 *tdp = NewCreateTask(TASKTAG_NAME, name,
120 TASKTAG_PC, func,
121 TASKTAG_PRI, 20,
122 TASKTAG_ARG1, arg,
123 TAG_END);
125 return (*tdp == NULL) ? ENOMEM : 0;
128 /* PCI devices */
129 typedef u_int16_t pci_vendor_id_t;
130 typedef u_int16_t pci_product_id_t;
131 typedef u_int32_t pcireg_t;
133 static inline u_int32_t pci_read_config(device_t dev, int reg, int width)
135 u_int32_t val = ~0;
136 struct AHCIBase *AHCIBase = dev->dev_AHCIBase;
137 OOP_MethodID HiddPCIDeviceMethodBase = AHCIBase->ahci_HiddPCIDeviceMethodBase;
138 struct pHidd_PCIDevice_ReadConfigByte cb;
139 struct pHidd_PCIDevice_ReadConfigWord cw;
140 struct pHidd_PCIDevice_ReadConfigLong cl;
141 OOP_Object *Device = dev->dev_Object;
143 switch (width) {
144 case 1:
145 cb.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_ReadConfigByte;
146 cb.reg = reg;
147 val = (u_int32_t)OOP_DoMethod(Device, (OOP_Msg)&cb);
148 break;
150 case 2:
151 cw.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_ReadConfigWord;
152 cw.reg = reg;
153 val = (u_int32_t)OOP_DoMethod(Device, (OOP_Msg)&cw);
154 break;
156 case 4:
157 cl.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_ReadConfigLong;
158 cl.reg = reg;
159 val = (u_int32_t)OOP_DoMethod(Device, (OOP_Msg)&cl);
160 break;
163 return val;
166 static inline void pci_write_config(device_t dev, int reg, u_int32_t val, int width)
168 struct AHCIBase *AHCIBase = dev->dev_AHCIBase;
169 OOP_MethodID HiddPCIDeviceMethodBase = AHCIBase->ahci_HiddPCIDeviceMethodBase;
170 struct pHidd_PCIDevice_WriteConfigByte cb;
171 struct pHidd_PCIDevice_WriteConfigWord cw;
172 struct pHidd_PCIDevice_WriteConfigLong cl;
173 OOP_Object *Device = dev->dev_Object;
175 switch (width) {
176 case 1:
177 cb.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_WriteConfigByte;
178 cb.reg = reg;
179 cw.val = val & 0xff;
180 OOP_DoMethod(Device, (OOP_Msg)&cb);
181 break;
183 case 2:
184 cw.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_WriteConfigWord;
185 cw.reg = reg;
186 cw.val = val & 0xffff;
187 OOP_DoMethod(Device, (OOP_Msg)&cw);
188 break;
190 case 4:
191 cl.mID = HiddPCIDeviceMethodBase + moHidd_PCIDevice_WriteConfigLong;
192 cl.reg = reg;
193 cl.val = val;
194 OOP_DoMethod(Device, (OOP_Msg)&cl);
195 break;
200 static inline u_int16_t pci_get_vendor(device_t dev)
202 return (u_int16_t)pci_read_config(dev, PCIR_VENDOR, 2);
205 static inline u_int16_t pci_get_device(device_t dev)
207 return (u_int16_t)pci_read_config(dev, PCIR_DEVICE, 2);
210 static inline u_int8_t pci_get_class(device_t dev)
212 return (u_int8_t)pci_read_config(dev, PCIR_CLASS, 1);
215 static inline u_int8_t pci_get_subclass(device_t dev)
217 return (u_int8_t)pci_read_config(dev, PCIR_SUBCLASS, 1);
220 /* DMA Types */
221 typedef IPTR bus_size_t;
222 typedef IPTR bus_addr_t;
223 typedef struct {
224 bus_addr_t ds_addr;
225 bus_size_t ds_len;
226 } bus_dma_segment_t;
228 typedef struct {
229 bus_size_t dt_alignment;
230 bus_size_t dt_maxsize;
231 bus_size_t dt_size;
232 } *bus_dma_tag_t;
234 typedef IPTR bus_space_tag_t;
235 typedef APTR bus_dmamap_t;
236 typedef IPTR bus_space_handle_t;
237 typedef int bus_dma_filter_t(void *arg, bus_addr_t paddr);
239 #define BUS_SPACE_MAXADDR ~0
240 #define BUS_SPACE_MAXADDR_32BIT ((ULONG)~0)
242 static inline 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)
244 D(bug("%s: Allocating tag, %d objects of size %d, aligned by %d\n", __func__, nsegments, maxsegsz, alignment));
245 *dmat = AllocVec(sizeof(**dmat), MEMF_ANY);
246 if (*dmat == NULL)
247 return -ENOMEM;
249 (*dmat)->dt_alignment = alignment;
250 (*dmat)->dt_maxsize = maxsize;
251 (*dmat)->dt_size = maxsegsz;
252 return 0;
255 static inline int bus_dma_tag_destroy(bus_dma_tag_t tag)
257 FreeVec(tag);
258 return 0;
261 #define BUS_DMA_ALLOCNOW (1 << 0)
262 #define BUS_DMA_ZERO (1 << 1)
264 struct bus_chunk {
265 ULONG negoffset;
268 static inline int bus_dmamem_alloc(bus_dma_tag_t tag, void **vaddr, unsigned flags, bus_dmamap_t *map)
270 struct bus_chunk *addr;
271 void *mem = AllocVec(sizeof(struct bus_chunk) + tag->dt_size + tag->dt_alignment, MEMF_ANY);
272 if (mem == NULL)
273 return -ENOMEM;
275 addr = (struct bus_chunk *)(((IPTR)mem + sizeof(struct bus_chunk) + tag->dt_alignment - 1) & ~(tag->dt_alignment-1));
276 addr[-1].negoffset = ((IPTR)addr - (IPTR)mem);
278 D(bug("%s: Allocated %p: size %d, real start %p\n", __func__, addr, tag->dt_size, mem));
279 if (vaddr)
280 *vaddr = addr;
282 *map = addr;
283 return 0;
286 static inline bus_size_t bus_dma_tag_getmaxsize(bus_dma_tag_t tag)
288 return tag->dt_maxsize;
291 static inline void bus_dmamem_free(bus_dma_tag_t tag, void *vaddr, bus_dmamap_t map)
293 struct bus_chunk *mem = (void *)map;
294 D(bug("%s: Free %p: size %d, real start %p\n", __func__, map, tag->dt_size, (APTR)((IPTR)mem - mem[-1].negoffset)));
295 FreeVec((APTR)((IPTR)mem - mem[-1].negoffset));
298 static inline int bus_dmamap_create(bus_dma_tag_t tag, unsigned flags, bus_dmamap_t *map)
300 bus_dmamem_alloc(tag, NULL, 0, map);
301 return 0;
304 static inline void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t map)
306 bus_dmamem_free(tag, NULL, map);
309 typedef void bus_dmamap_callback_t(void *info, bus_dma_segment_t *segs, int nsegs, int error);
311 #define BUS_DMA_NOWAIT 0
312 #define BUS_DMA_WAITOK 0
313 #define BUS_DMASYNC_POSTREAD 0
314 #define BUS_DMASYNC_POSTWRITE 0
316 static inline 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)
318 bus_dma_segment_t seg = { .ds_addr = (bus_addr_t)data, .ds_len = (bus_size_t)len };
319 callback(info, &seg, 1, 0);
320 return 0;
323 #define BUS_DMASYNC_PREREAD 0
324 #define BUS_DMASYNC_PREWRITE 0
326 static inline void bus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t map, unsigned flags)
330 static inline void bus_dmamap_unload(bus_dma_tag_t tag, bus_dmamap_t map)
334 /* Generic bus operations */
335 enum bus_resource_t {
336 SYS_RES_IRQ = 0,
337 SYS_RES_MEMORY = 1,
340 #define AHCI_IRQ_RID 0
342 struct resource {
343 bus_space_tag_t res_tag;
344 bus_space_handle_t res_handle;
345 ULONG res_size;
348 #define RF_SHAREABLE (1 << 0)
349 #define RF_ACTIVE (1 << 1)
351 static inline struct resource *bus_alloc_resource_any(device_t dev, enum bus_resource_t type, int *rid, u_int flags)
353 struct resource *resource;
354 IPTR INTLine;
355 OOP_AttrBase HiddPCIDeviceAttrBase = dev->dev_AHCIBase->ahci_HiddPCIDeviceAttrBase;
357 resource = AllocPooled(dev->dev_AHCIBase->ahci_MemPool, sizeof(*resource));
358 if (!resource)
359 return NULL;
361 switch (type) {
362 case SYS_RES_IRQ:
363 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_INTLine, &INTLine);
364 resource->res_tag = INTLine;
365 break;
366 case SYS_RES_MEMORY:
367 resource->res_tag = pci_read_config(dev, *rid, 4);
368 break;
371 if (type == SYS_RES_MEMORY && (*rid) >= PCIR_BAR(0) && (*rid) < PCIR_BAR(6)) {
372 struct pHidd_PCIDriver_MapPCI map;
373 IPTR hba_size;
374 OOP_Object *Driver;
376 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_Driver, (IPTR *)&Driver);
377 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_Size0 + (((*rid) - PCIR_BAR(0))/4)*3, &hba_size);
378 resource->res_size = hba_size;
380 map.mID = dev->dev_AHCIBase->ahci_HiddPCIDriverMethodBase + moHidd_PCIDriver_MapPCI;
381 map.PCIAddress = (APTR)resource->res_tag;
382 map.Length = resource->res_size;
383 resource->res_handle = OOP_DoMethod(Driver, (OOP_Msg)&map);
384 } else {
385 /* FIXME: Map IRQ? */
386 resource->res_handle = resource->res_tag;
387 resource->res_size = 1;
390 return resource;
393 static inline int bus_release_resource(device_t dev, enum bus_resource_t type, int rid, struct resource *res)
395 OOP_AttrBase HiddPCIDeviceAttrBase = dev->dev_AHCIBase->ahci_HiddPCIDeviceAttrBase;
397 if (type == SYS_RES_MEMORY && rid > PCIR_BAR(0) && rid < PCIR_BAR(6)) {
398 struct pHidd_PCIDriver_UnmapPCI unmap;
399 OOP_Object *Driver;
401 OOP_GetAttr(dev->dev_Object, aHidd_PCIDevice_Driver, (IPTR *)&Driver);
402 unmap.mID = dev->dev_AHCIBase->ahci_HiddPCIDriverMethodBase + moHidd_PCIDriver_UnmapPCI;
403 unmap.CPUAddress = (APTR)res->res_handle;
404 unmap.Length = res->res_size;
405 OOP_DoMethod(Driver, (OOP_Msg)&unmap);
407 FreePooled(dev->dev_AHCIBase->ahci_MemPool, res, sizeof(*res));
408 return 0;
412 static inline bus_space_tag_t rman_get_bustag(struct resource *r)
414 return r->res_tag;
417 static inline bus_space_handle_t rman_get_bushandle(struct resource *r)
419 return r->res_handle;
422 /* Bus IRQ */
423 typedef void driver_intr_t(void *arg);
425 #define INTR_MPSAFE 0
427 int bus_setup_intr(device_t dev, struct resource *r, int flags, driver_intr_t handler, void *arg, void **cookiep, void *serializer);
429 int bus_teardown_intr(device_t dev, struct resource *r, void *cookie);
431 /* Bus IO */
433 static inline int bus_space_subregion(bus_space_tag_t iot, bus_space_handle_t ioh, unsigned offset, size_t size, bus_space_handle_t *result)
435 *result = ioh + offset;
436 return 0;
439 #define BUS_SPACE_BARRIER_READ 0
440 #define BUS_SPACE_BARRIER_WRITE 0
442 static inline void bus_space_barrier(bus_space_tag_t iot, bus_space_handle_t ioh, unsigned offset, size_t size, unsigned flags)
444 /* FIXME: Sync bus area */
447 static inline u_int32_t bus_space_read_4(bus_space_tag_t iot, bus_space_handle_t ioh, unsigned offset)
449 return *(u_int32_t *)(ioh + offset);
452 static inline void bus_space_write_4(bus_space_tag_t iot, bus_space_handle_t ioh, unsigned offset, u_int32_t val)
454 *(u_int32_t *)(ioh + offset) = val;
458 /* Generic device info */
459 static inline void *device_get_softc(device_t dev)
461 return dev->dev_softc;
464 /* Lock management */
466 struct lock {
467 struct SignalSemaphore sem;
468 const char *name;
471 static inline void lockinit(struct lock *lock, const char *name, unsigned flags, unsigned count)
473 lock->name = name;
474 InitSemaphore(&lock->sem);
477 static inline void lockuninit(struct lock *lock)
479 /* Nothing needed */
482 #define LK_RELEASE (1 << 0)
483 #define LK_EXCLUSIVE (1 << 1)
484 #define LK_CANRECURSE (1 << 2)
485 #define LK_NOWAIT (1 << 3)
487 static inline int lockmgr(struct lock *lock, int flags)
489 int err = 0;
491 flags &= (LK_EXCLUSIVE | LK_NOWAIT | LK_RELEASE);
492 switch (flags) {
493 case 0:
494 ObtainSemaphoreShared(&lock->sem);
495 break;
496 case LK_EXCLUSIVE | LK_NOWAIT:
497 err = (AttemptSemaphore(&lock->sem) == FALSE) ? 1 : 0;
498 break;
499 case LK_EXCLUSIVE:
500 ObtainSemaphore(&lock->sem);
501 break;
502 case LK_RELEASE:
503 ReleaseSemaphore(&lock->sem);
504 break;
507 return err;
510 /* Events */
511 #define atomic_clear_int(ptr, val) AROS_ATOMIC_AND(*(ptr), ~(val))
512 #define atomic_set_int(ptr, val) AROS_ATOMIC_OR(*(ptr), (val))
514 /* Callouts */
516 static const int hz = (1000000 / 2); /* UNIT_MICROHZ frequency */
518 typedef void timeout_t (void *);
520 struct callout {
521 struct Task *co_Task;
524 void callout_init_mp(struct callout *c);
526 void callout_init(struct callout *c);
528 void callout_stop(struct callout *c);
530 void callout_stop_sync(struct callout *c);
532 int callout_reset(struct callout *c, unsigned int ticks, void (*func)(void *), void *arg);
534 struct sysctl_ctx_list {};
536 /* BSD style TailQs */
537 #define TAILQ_HEAD(sname,type) struct sname { struct type *next, *last; }
538 #define TAILQ_ENTRY(type) TAILQ_HEAD(,type)
539 #define TAILQ_INIT(head) do { (head)->next = (head)->last = NULL; } while (0)
540 #define TAILQ_FIRST(head) ((head)->next)
541 #define TAILQ_REMOVE(head,n,link) ({ (n) = (head)->next; if ((n) != NULL) (head)->next = (n)->link.next; (n)->link.next = (n)->link.last = NULL; })
542 #define TAILQ_INSERT_TAIL(head,n,link) do { if ((head)->last != NULL) (head)->last->link.next = (n); (head)->last = (n); if ((head)->next == NULL) (head)->next = (n); } while (0)
544 #define device_get_name(dev) "ahci.device "
545 #define device_get_unit(dev) ((dev)->dev_HostID)
547 #define M_DEVBUF 0
548 #define M_TEMP 0
549 #define M_WAITOK 0
550 #define M_INTWAIT 0
551 #define M_ZERO MEMF_CLEAR
553 static const int bootverbose = 0;
555 /* Bit operations */
556 static inline int ffs(unsigned int bits)
558 int i;
560 for (i = 0; i < 32; i++, bits >>= 1)
561 if (bits & 1)
562 return (i+1);
564 return 0;
567 struct ata_xfer;
568 void ahci_ata_io_complete(struct ata_xfer *xa);
570 #endif /* AHCI_AROS_H */