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
8 #include <aros/atomic.h>
10 #include <proto/exec.h>
11 #include <proto/oop.h>
15 #include <devices/timer.h>
20 void callout_init_mp(struct callout
*co
)
22 memset(co
, 0, sizeof(*co
));
25 void callout_init(struct callout
*co
)
30 void callout_stop(struct callout
*co
)
34 Signal(co
->co_Task
, SIGF_ABORT
);
40 void callout_stop_sync(struct callout
*co
)
45 static void callout_handler(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
51 if ((io
= ahci_OpenTimer())) {
52 signals
= ahci_WaitTO(io
, ms
/ 1000, 1000 * (ms
% 1000), SIGF_ABORT
);
56 if (!(signals
& SIGF_ABORT
)) {
62 int callout_reset(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
68 t
= NewCreateTask(TASKTAG_NAME
, "AHCI Callout",
69 TASKTAG_PC
, callout_handler
,
78 return (t
== NULL
) ? ENOMEM
: 0;
81 void ahci_os_sleep(int ms
)
83 struct IORequest
*io
= ahci_OpenTimer();
85 ahci_WaitTO(io
, ms
/ 1000, (ms
% 1000) * 1000, 0);
90 void ahci_os_hardsleep(int us
)
92 ahci_WaitNano((ULONG
)us
* 1000);
96 * Sleep for a minimum interval and return the number of milliseconds
97 * that was. The minimum value returned is 1
99 * UNIT_MICROHZ is only guaranteed to work down to 2 microseconds.
101 int ahci_os_softsleep(void)
103 struct IORequest
*io
= ahci_OpenTimer();
105 ahci_WaitTO(io
, 0, 100 * 1000, 0);
112 * Per-port thread helper. This helper thread is responsible for
113 * atomically retrieving and clearing the signal mask and calling
114 * the machine-independant driver core.
118 static void ahci_port_thread(void *arg
)
120 struct ahci_port
*ap
= arg
;
124 * The helper thread is responsible for the initial port init,
125 * so all the ports can be inited in parallel.
127 * We also run the state machine which should do all probes.
128 * Since CAM is not attached yet we will not get out-of-order
131 ahci_os_lock_port(ap
);
133 atomic_clear_int(&ap
->ap_signal
, AP_SIGF_THREAD_SYNC
);
134 ahci_port_state_machine(ap
, 1);
135 ahci_os_unlock_port(ap
);
136 atomic_clear_int(&ap
->ap_signal
, AP_SIGF_INIT
);
139 * Then loop on the helper core.
141 mask
= ap
->ap_signal
;
142 while ((mask
& AP_SIGF_STOP
) == 0) {
143 ahci_port_thread_core(ap
, mask
);
144 // lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
145 if (ap
->ap_signal
== 0)
147 mask
= ap
->ap_signal
;
148 atomic_clear_int(&ap
->ap_signal
, mask
);
149 // lockmgr(&ap->ap_sig_lock, LK_RELEASE);
151 ap
->ap_thread
= NULL
;
154 void ahci_os_start_port(struct ahci_port
*ap
)
158 atomic_set_int(&ap
->ap_signal
, AP_SIGF_INIT
| AP_SIGF_THREAD_SYNC
);
159 lockinit(&ap
->ap_lock
, "ahcipo", 0, LK_CANRECURSE
);
160 lockinit(&ap
->ap_sim_lock
, "ahcicam", 0, LK_CANRECURSE
);
161 ksnprintf(name
, sizeof(name
), "%d", ap
->ap_num
);
163 kthread_create(ahci_port_thread
, ap
, &ap
->ap_thread
,
168 * Stop the OS-specific port helper thread and kill the per-port lock.
170 void ahci_os_stop_port(struct ahci_port
*ap
)
173 ahci_os_signal_port_thread(ap
, AP_SIGF_STOP
);
176 kprintf("%s: Waiting for thread to terminate\n",
178 while (ap
->ap_thread
)
180 kprintf("%s: thread terminated\n",
184 lockuninit(&ap
->ap_lock
);
188 * Add (mask) to the set of bits being sent to the per-port thread helper
189 * and wake the helper up if necessary.
191 * We use SIGF_DOS, since these are Threads, not Processes, and
192 * won't already be using SIGF_DOS for messages.
194 void ahci_os_signal_port_thread(struct ahci_port
*ap
, int mask
)
196 atomic_set_int(&ap
->ap_signal
, mask
);
197 Signal(ap
->ap_thread
, SIGF_DOS
);
201 * Unconditionally lock the port structure for access.
203 void ahci_os_lock_port(struct ahci_port
*ap
)
205 lockmgr(&ap
->ap_lock
, LK_EXCLUSIVE
);
209 * Conditionally lock the port structure for access.
211 * Returns 0 on success, non-zero on failure.
213 int ahci_os_lock_port_nb(struct ahci_port
*ap
)
219 * Unlock a previously locked port.
221 void ahci_os_unlock_port(struct ahci_port
*ap
)
223 lockmgr(&ap
->ap_lock
, LK_RELEASE
);