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(struct callout
*co
)
22 memset(co
, 0, sizeof(*co
));
25 void callout_stop(struct callout
*co
)
29 Signal(co
->co_Task
, SIGF_ABORT
);
35 static void callout_handler(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
39 ULONG us
= (ticks
* 1000000) / hz
;
41 if ((io
= ahci_OpenTimer())) {
42 signals
= ahci_WaitTO(io
, us
/ 1000000, us
% 1000000, SIGF_ABORT
);
46 if (!(signals
& SIGF_ABORT
)) {
52 int callout_reset(struct callout
*co
, unsigned ticks
, timeout_t
*func
, void *arg
)
58 t
= NewCreateTask(TASKTAG_NAME
, "AHCI Callout",
59 TASKTAG_PC
, callout_handler
,
68 return (t
== NULL
) ? ENOMEM
: 0;
71 void ahci_os_sleep(int ms
)
73 struct IORequest
*io
= ahci_OpenTimer();
75 ahci_WaitTO(io
, ms
/ 1000, (ms
% 1000) * 1000, 0);
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();
95 ahci_WaitTO(io
, 0, 100 * 1000, 0);
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.
108 static void ahci_port_thread(void *arg
)
110 struct ahci_port
*ap
= arg
;
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
121 ahci_os_lock_port(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)
137 mask
= ap
->ap_signal
;
139 ap
->ap_thread
= NULL
;
142 void ahci_os_start_port(struct ahci_port
*ap
)
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
,
156 * Stop the OS-specific port helper thread and kill the per-port lock.
158 void ahci_os_stop_port(struct ahci_port
*ap
)
161 ahci_os_signal_port_thread(ap
, AP_SIGF_STOP
);
164 kprintf("%s: Waiting for thread to terminate\n",
166 while (ap
->ap_thread
)
168 kprintf("%s: thread terminated\n",
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
)
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
)
218 driver_intr_t
*func
= fa
[0];
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
);
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];
243 handler
->is_Data
= fa
;
245 AddIntServer(INTB_KERNEL
+ r
->res_tag
, handler
);
251 int bus_teardown_intr(device_t dev
, struct resource
*r
, void *cookie
)
253 RemIntServer(INTB_KERNEL
+ r
->res_tag
, (struct Interrupt
*)cookie
);