2 * Copyright (C) 2012-2018, 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 <proto/exec.h>
10 /* We want all other bases obtained from our base */
13 #include <aros/atomic.h>
15 #include <proto/oop.h>
19 #include <devices/timer.h>
24 void callout_init_mp(struct callout
*co
)
26 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
27 memset(co
, 0, sizeof(*co
));
30 void callout_init(struct callout
*co
)
32 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
36 void callout_stop(struct callout
*co
)
38 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
41 Signal(co
->co_Task
, SIGF_ABORT
);
47 void callout_stop_sync(struct callout
*co
)
49 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
53 static void callout_handler(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
59 if ((io
= ahci_OpenTimer())) {
60 signals
= ahci_WaitTO(io
, ms
/ 1000, 1000 * (ms
% 1000), SIGF_ABORT
);
64 if (!(signals
& SIGF_ABORT
)) {
70 int callout_reset(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
73 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
77 t
= NewCreateTask(TASKTAG_NAME
, "AHCI Callout",
78 TASKTAG_PC
, callout_handler
,
87 return (t
== NULL
) ? ENOMEM
: 0;
90 void ahci_os_sleep(int ms
)
92 struct IORequest
*io
= ahci_OpenTimer();
94 ahci_WaitTO(io
, ms
/ 1000, (ms
% 1000) * 1000, 0);
99 void ahci_os_hardsleep(int us
)
101 ahci_WaitNano((ULONG
)us
* 1000);
105 * Sleep for a minimum interval and return the number of milliseconds
106 * that was. The minimum value returned is 1
108 * UNIT_MICROHZ is only guaranteed to work down to 2 microseconds.
110 int ahci_os_softsleep(void)
112 struct IORequest
*io
= ahci_OpenTimer();
114 ahci_WaitTO(io
, 0, 100 * 1000, 0);
121 * Per-port thread helper. This helper thread is responsible for
122 * atomically retrieving and clearing the signal mask and calling
123 * the machine-independant driver core.
127 static void ahci_port_thread(void *arg
)
129 struct ahci_port
*ap
= arg
;
132 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
135 * The helper thread is responsible for the initial port init,
136 * so all the ports can be inited in parallel.
138 * We also run the state machine which should do all probes.
139 * Since CAM is not attached yet we will not get out-of-order
142 ahci_os_lock_port(ap
);
144 atomic_clear_int(&ap
->ap_signal
, AP_SIGF_THREAD_SYNC
);
145 ahci_port_state_machine(ap
, 1);
146 ahci_os_unlock_port(ap
);
147 atomic_clear_int(&ap
->ap_signal
, AP_SIGF_INIT
);
150 * Then loop on the helper core.
152 mask
= ap
->ap_signal
;
153 while ((mask
& AP_SIGF_STOP
) == 0) {
154 ahci_port_thread_core(ap
, mask
);
155 // lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
156 if (ap
->ap_signal
== 0)
158 mask
= ap
->ap_signal
;
159 atomic_clear_int(&ap
->ap_signal
, mask
);
160 // lockmgr(&ap->ap_sig_lock, LK_RELEASE);
162 ap
->ap_thread
= NULL
;
165 void ahci_os_start_port(struct ahci_port
*ap
)
169 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
171 atomic_set_int(&ap
->ap_signal
, AP_SIGF_INIT
| AP_SIGF_THREAD_SYNC
);
172 lockinit(&ap
->ap_lock
, "ahcipo", 0, LK_CANRECURSE
);
173 lockinit(&ap
->ap_sim_lock
, "ahcicam", 0, LK_CANRECURSE
);
174 ksnprintf(name
, sizeof(name
), "%d", ap
->ap_num
);
176 kthread_create(ahci_port_thread
, ap
, &ap
->ap_thread
,
181 * Stop the OS-specific port helper thread and kill the per-port lock.
183 void ahci_os_stop_port(struct ahci_port
*ap
)
185 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
187 ahci_os_signal_port_thread(ap
, AP_SIGF_STOP
);
190 kprintf("%s: Waiting for thread to terminate\n",
192 while (ap
->ap_thread
)
194 kprintf("%s: thread terminated\n",
198 lockuninit(&ap
->ap_lock
);
202 * Add (mask) to the set of bits being sent to the per-port thread helper
203 * and wake the helper up if necessary.
205 * We use SIGF_DOS, since these are Threads, not Processes, and
206 * won't already be using SIGF_DOS for messages.
208 void ahci_os_signal_port_thread(struct ahci_port
*ap
, int mask
)
210 D(bug("[AHCI] %s()\n", __PRETTY_FUNCTION__
));
211 atomic_set_int(&ap
->ap_signal
, mask
);
212 Signal(ap
->ap_thread
, SIGF_DOS
);
216 * Unconditionally lock the port structure for access.
218 void ahci_os_lock_port(struct ahci_port
*ap
)
220 lockmgr(&ap
->ap_lock
, LK_EXCLUSIVE
);
224 * Conditionally lock the port structure for access.
226 * Returns 0 on success, non-zero on failure.
228 int ahci_os_lock_port_nb(struct ahci_port
*ap
)
234 * Unlock a previously locked port.
236 void ahci_os_unlock_port(struct ahci_port
*ap
)
238 lockmgr(&ap
->ap_lock
, LK_RELEASE
);