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
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>
26 #include "ahci_intern.h"
30 #define kprintf(fmt, args...) device_printf(NULL, fmt ,##args)
33 #define __packed __attribute__((__packed__))
35 #error Define __packed appropriately for your compiler!
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
52 struct MinNode dev_Node
;
53 OOP_Object
*dev_Object
;
54 struct AHCIBase
*dev_AHCIBase
;
55 struct ahci_softc
*dev_softc
;
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
)
73 static inline int device_printf(device_t dev
, const char *fmt
, ...)
78 err
= kvcprintf(fmt
, bug_c
, NULL
, 10, args
);
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
)
96 static inline void crit_enter(void)
101 static inline void crit_exit(void)
106 typedef struct Task
*thread_t
;
108 static inline int kthread_create(void (*func
)(void *), void *arg
, thread_t
*tdp
, const char *fmt
, ...)
114 kvsnprintf(name
, sizeof(name
), fmt
, args
);
117 name
[sizeof(name
)-1] = 0;
119 *tdp
= NewCreateTask(TASKTAG_NAME
, name
,
125 return (*tdp
== NULL
) ? ENOMEM
: 0;
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
)
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
;
145 cb
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_ReadConfigByte
;
147 val
= (u_int32_t
)OOP_DoMethod(Device
, (OOP_Msg
)&cb
);
151 cw
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_ReadConfigWord
;
153 val
= (u_int32_t
)OOP_DoMethod(Device
, (OOP_Msg
)&cw
);
157 cl
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_ReadConfigLong
;
159 val
= (u_int32_t
)OOP_DoMethod(Device
, (OOP_Msg
)&cl
);
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
;
177 cb
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_WriteConfigByte
;
180 OOP_DoMethod(Device
, (OOP_Msg
)&cb
);
184 cw
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_WriteConfigWord
;
186 cw
.val
= val
& 0xffff;
187 OOP_DoMethod(Device
, (OOP_Msg
)&cw
);
191 cl
.mID
= HiddPCIDeviceMethodBase
+ moHidd_PCIDevice_WriteConfigLong
;
194 OOP_DoMethod(Device
, (OOP_Msg
)&cl
);
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);
221 typedef IPTR bus_size_t
;
222 typedef IPTR bus_addr_t
;
229 bus_size_t dt_alignment
;
230 bus_size_t dt_maxsize
;
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
);
249 (*dmat
)->dt_alignment
= alignment
;
250 (*dmat
)->dt_maxsize
= maxsize
;
251 (*dmat
)->dt_size
= maxsegsz
;
255 static inline int bus_dma_tag_destroy(bus_dma_tag_t tag
)
261 #define BUS_DMA_ALLOCNOW (1 << 0)
262 #define BUS_DMA_ZERO (1 << 1)
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
);
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
));
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
);
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);
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
{
340 #define AHCI_IRQ_RID 0
343 bus_space_tag_t res_tag
;
344 bus_space_handle_t res_handle
;
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
;
355 OOP_AttrBase HiddPCIDeviceAttrBase
= dev
->dev_AHCIBase
->ahci_HiddPCIDeviceAttrBase
;
357 resource
= AllocPooled(dev
->dev_AHCIBase
->ahci_MemPool
, sizeof(*resource
));
363 OOP_GetAttr(dev
->dev_Object
, aHidd_PCIDevice_INTLine
, &INTLine
);
364 resource
->res_tag
= INTLine
;
367 resource
->res_tag
= pci_read_config(dev
, *rid
, 4);
371 if (type
== SYS_RES_MEMORY
&& (*rid
) >= PCIR_BAR(0) && (*rid
) < PCIR_BAR(6)) {
372 struct pHidd_PCIDriver_MapPCI map
;
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
);
385 /* FIXME: Map IRQ? */
386 resource
->res_handle
= resource
->res_tag
;
387 resource
->res_size
= 1;
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
;
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
));
412 static inline bus_space_tag_t
rman_get_bustag(struct resource
*r
)
417 static inline bus_space_handle_t
rman_get_bushandle(struct resource
*r
)
419 return r
->res_handle
;
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
);
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
;
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 */
467 struct SignalSemaphore sem
;
471 static inline void lockinit(struct lock
*lock
, const char *name
, unsigned flags
, unsigned count
)
474 InitSemaphore(&lock
->sem
);
477 static inline void lockuninit(struct lock
*lock
)
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
)
491 flags
&= (LK_EXCLUSIVE
| LK_NOWAIT
| LK_RELEASE
);
494 ObtainSemaphoreShared(&lock
->sem
);
496 case LK_EXCLUSIVE
| LK_NOWAIT
:
497 err
= (AttemptSemaphore(&lock
->sem
) == FALSE
) ? 1 : 0;
500 ObtainSemaphore(&lock
->sem
);
503 ReleaseSemaphore(&lock
->sem
);
511 #define atomic_clear_int(ptr, val) AROS_ATOMIC_AND(*(ptr), ~(val))
512 #define atomic_set_int(ptr, val) AROS_ATOMIC_OR(*(ptr), (val))
516 static const int hz
= (1000000 / 2); /* UNIT_MICROHZ frequency */
518 typedef void timeout_t (void *);
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)
551 #define M_ZERO MEMF_CLEAR
553 static const int bootverbose
= 0;
556 static inline int ffs(unsigned int bits
)
560 for (i
= 0; i
< 32; i
++, bits
>>= 1)
568 void ahci_ata_io_complete(struct ata_xfer
*xa
);
570 #endif /* AHCI_AROS_H */