includes: AROS_UFIxx -> AROS_INTxx change
[AROS.git] / rom / devs / ahci / ahci_aros.c
blobac5f029078a9e48967c58be1c768490e26872380
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 #include <aros/atomic.h>
10 #include <proto/exec.h>
11 #include <proto/oop.h>
13 #include <hidd/pci.h>
15 #include <devices/timer.h>
17 #include "ahci.h"
18 #include "timer.h"
20 void callout_init(struct callout *co)
22 memset(co, 0, sizeof(*co));
25 void callout_stop(struct callout *co)
27 Forbid();
28 if (co->co_Task) {
29 Signal(co->co_Task, SIGF_ABORT);
30 co->co_Task = NULL;
32 Permit();
35 static void callout_handler(struct callout *co, unsigned ticks, timeout_t *func, void *arg)
37 struct IORequest *io;
38 ULONG signals = 0;
39 ULONG us = (ticks * 1000000) / hz;
41 if ((io = ahci_OpenTimer())) {
42 signals = ahci_WaitTO(io, us / 1000000, us % 1000000, SIGF_ABORT);
43 ahci_CloseTimer(io);
46 if (!(signals & SIGF_ABORT)) {
47 co->co_Task = NULL;
48 func(arg);
52 int callout_reset(struct callout *co, unsigned ticks, timeout_t *func, void *arg)
54 struct Task *t;
56 callout_stop(co);
58 t = NewCreateTask(TASKTAG_NAME, "AHCI Callout",
59 TASKTAG_PC, callout_handler,
60 TASKTAG_PRI, 21,
61 TASKTAG_ARG1, co,
62 TASKTAG_ARG2, ticks,
63 TASKTAG_ARG3, func,
64 TASKTAG_ARG4, arg,
65 TAG_END);
66 co->co_Task = t;
68 return (t == NULL) ? ENOMEM : 0;
71 void ahci_os_sleep(int ms)
73 struct IORequest *io = ahci_OpenTimer();
74 if (io != NULL) {
75 ahci_WaitTO(io, ms / 1000, (ms % 1000) * 1000, 0);
76 ahci_CloseTimer(io);
80 void ahci_os_hardsleep(int us)
82 ahci_WaitNano((ULONG)us * 1000);
86 * Sleep for a minimum interval and return the number of milliseconds
87 * that was. The minimum value returned is 1
89 * UNIT_MICROHZ is only guaranteed to work down to 2 microseconds.
91 int ahci_os_softsleep(void)
93 struct IORequest *io = ahci_OpenTimer();
94 if (io != NULL) {
95 ahci_WaitTO(io, 0, 100 * 1000, 0);
96 ahci_CloseTimer(io);
98 return 100;
102 * Per-port thread helper. This helper thread is responsible for
103 * atomically retrieving and clearing the signal mask and calling
104 * the machine-independant driver core.
106 * MPSAFE
108 static void ahci_port_thread(void *arg)
110 struct ahci_port *ap = arg;
111 int mask;
114 * The helper thread is responsible for the initial port init,
115 * so all the ports can be inited in parallel.
117 * We also run the state machine which should do all probes.
118 * Since CAM is not attached yet we will not get out-of-order
119 * SCSI attachments.
121 ahci_os_lock_port(ap);
122 ahci_port_init(ap);
123 atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC);
124 ahci_port_state_machine(ap, 1);
125 ahci_os_unlock_port(ap);
126 atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT);
129 * Then loop on the helper core.
131 mask = ap->ap_signal;
132 while ((mask & AP_SIGF_STOP) == 0) {
133 atomic_clear_int(&ap->ap_signal, mask);
134 ahci_port_thread_core(ap, mask);
135 if (ap->ap_signal == 0)
136 Wait(SIGF_DOS);
137 mask = ap->ap_signal;
139 ap->ap_thread = NULL;
142 void ahci_os_start_port(struct ahci_port *ap)
144 char name[16];
146 atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC);
147 lockinit(&ap->ap_lock, "ahcipo", 0, 0);
148 lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE);
149 ksnprintf(name, sizeof(name), "%d", ap->ap_num);
151 kthread_create(ahci_port_thread, ap, &ap->ap_thread,
152 "%s", PORTNAME(ap));
156 * Stop the OS-specific port helper thread and kill the per-port lock.
158 void ahci_os_stop_port(struct ahci_port *ap)
160 if (ap->ap_thread) {
161 ahci_os_signal_port_thread(ap, AP_SIGF_STOP);
162 ahci_os_sleep(10);
163 if (ap->ap_thread) {
164 kprintf("%s: Waiting for thread to terminate\n",
165 PORTNAME(ap));
166 while (ap->ap_thread)
167 ahci_os_sleep(100);
168 kprintf("%s: thread terminated\n",
169 PORTNAME(ap));
172 lockuninit(&ap->ap_lock);
176 * Add (mask) to the set of bits being sent to the per-port thread helper
177 * and wake the helper up if necessary.
179 * We use SIGF_DOS, since these are Threads, not Processes, and
180 * won't already be using SIGF_DOS for messages.
182 void ahci_os_signal_port_thread(struct ahci_port *ap, int mask)
184 atomic_set_int(&ap->ap_signal, mask);
185 Signal(ap->ap_thread, SIGF_DOS);
189 * Unconditionally lock the port structure for access.
191 void ahci_os_lock_port(struct ahci_port *ap)
193 lockmgr(&ap->ap_lock, LK_EXCLUSIVE);
197 * Conditionally lock the port structure for access.
199 * Returns 0 on success, non-zero on failure.
201 int ahci_os_lock_port_nb(struct ahci_port *ap)
203 return 1;
207 * Unlock a previously locked port.
209 void ahci_os_unlock_port(struct ahci_port *ap)
211 lockmgr(&ap->ap_lock, LK_RELEASE);
214 AROS_INTH1(ahci_Interrupt, void **, fa)
216 AROS_INTFUNC_INIT
218 driver_intr_t *func = fa[0];
219 void *arg = fa[1];
221 func(arg);
223 return FALSE;
225 AROS_INTFUNC_EXIT
228 /* IRQ management */
229 int bus_setup_intr(device_t dev, struct resource *r, int flags, driver_intr_t func, void *arg, void **cookiep, void *serializer)
231 struct Interrupt *handler = AllocVec(sizeof(struct Interrupt)+sizeof(void *)*2, MEMF_PUBLIC);
232 void **fa;
234 if (handler == NULL)
235 return ENOMEM;
237 handler->is_Node.ln_Pri = 10;
238 handler->is_Node.ln_Name = device_get_name(dev);
239 handler->is_Code = (VOID_FUNC)ahci_Interrupt;
240 fa = (void **)&handler[1];
241 fa[0] = func;
242 fa[1] = arg;
243 handler->is_Data = fa;
245 AddIntServer(INTB_KERNEL + r->res_tag, handler);
246 *cookiep = handler;
248 return 0;
251 int bus_teardown_intr(device_t dev, struct resource *r, void *cookie)
253 RemIntServer(INTB_KERNEL + r->res_tag, (struct Interrupt *)cookie);
254 FreeVec(cookie);
256 return 0;