- HD_SCSICMD: assume there is no sense-data buffer if no AUTOSENSE
[AROS.git] / rom / devs / ata / timer.c
blob3b109bcbcb77bb7343aa0d29a151e54e4b5f1eff
1 /*
2 Copyright © 2009-2012, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include <exec/types.h>
10 #include <devices/timer.h>
11 #include <exec/io.h>
12 #include <proto/exec.h>
13 #include <aros/debug.h>
14 #include <proto/timer.h>
16 #include "timer.h"
17 #include "ata.h"
19 static BOOL ata_Calibrate(struct IORequest* tmr, struct ataBase *base)
21 register ULONG x;
22 register ULONG scale = 0x8000; // min iterations...
23 volatile register ULONG t = 1;
24 struct timeval t1, t2;
25 struct Device *TimerBase = base->ata_TimerBase;
27 D(bug("[ATA ] Calibration started\n"));
29 while (scale <= 0x80000000)
31 Forbid();
32 GetSysTime(&t1);
33 for (x = 1; x < scale; x++)
34 t = (((t + x) * t) - x) / x; // add, mul, sub, div, trivial benchmark.
36 GetSysTime(&t2);
37 Permit();
38 SubTime(&t2, &t1);
40 // ok, it's going to be totally insane, if secs > 1.
41 if (t2.tv_secs != 0)
43 bug("[ATA ] micro wait useless.\n");
44 return FALSE;
47 /*
48 * we expect at least 10000 times longer period, which should be 'achievable'
49 * unlikely we will cross the magic boundary here of 4 billion instructions in 10 millisecond (yielding 400'000MIPS?)
50 * on the other side, if we go as low as 1, then 4 iterations of add/sub/mul/div is perfectly fine yielding a bit more than 400ns...
53 if (t2.tv_micro >= 10000)
54 break;
55 scale <<= 1;
58 D(bug("[ATA ] Executed %ld ops in %ldus\n", scale, t2.tv_micro));
60 // always round up to the next value.. so 30.9 -> 31, 5.1 -> 6, etc
61 x = (x + t2.tv_micro - 1) / t2.tv_micro;
62 x = (x+9) / 10;
64 bug("[ATA ] Approximate number of iterations per 100 nanoseconds: %ld\n", x);
65 base->ata_ItersPer100ns = x;
66 return TRUE;
69 struct IORequest *ata_OpenTimer(struct ataBase *base)
71 struct MsgPort *p = CreateMsgPort();
72 if (NULL != p)
74 struct IORequest *io = CreateIORequest(p, sizeof(struct timerequest));
76 if (NULL != io)
79 * ok. ECLOCK does not have too great resolution, either.
80 * we will have to sacrifice our performance a little bit, meaning, the 400ns will turn into (worst case) 2us.
81 * hopefully we won't have to call that TOO often...
83 if (0 == OpenDevice("timer.device", UNIT_MICROHZ, io, 0))
85 if (NULL == base->ata_TimerBase)
87 base->ata_TimerBase = io->io_Device;
88 ata_Calibrate(io, base);
90 return io;
92 else
94 bug("[ATA ] Failed to open timer.device, unit MICROHZ\n");
96 DeleteIORequest(io);
98 else
100 bug("[ATA ] Failed to create timerequest\n");
102 DeleteMsgPort(p);
104 else
106 bug("[ATA ] Failed to create timer port\n");
109 return NULL;
112 void ata_CloseTimer(struct IORequest *tmr)
114 if (NULL != tmr)
116 struct MsgPort *p = tmr->io_Message.mn_ReplyPort;
117 CloseDevice(tmr);
118 DeleteIORequest(tmr);
119 DeleteMsgPort(p);
123 void ata_WaitNano(register ULONG ns, struct ataBase *base)
125 volatile register ULONG t = 1;
126 ns = (ns + 99) / 100;
127 ns *= base->ata_ItersPer100ns;
128 while (ns > 0)
130 t = (((t + ns) * t) - ns) / ns; // add, mul, sub, div, trivial benchmark.
131 --ns;
135 ULONG ata_WaitTO(struct IORequest* tmr, ULONG secs, ULONG micro, ULONG sigs)
137 ULONG sig = 1 << tmr->io_Message.mn_ReplyPort->mp_SigBit;
139 //D(bug("[ATA--] Timed wait %lds %ldu\n", secs, micro));
141 tmr->io_Command = TR_ADDREQUEST;
142 ((struct timerequest*)tmr)->tr_time.tv_secs = secs;
143 ((struct timerequest*)tmr)->tr_time.tv_micro = micro;
145 SendIO(tmr);
146 sigs = Wait(sigs | sig);
147 if (0 == (sigs & sig))
149 if (!CheckIO(tmr))
150 AbortIO(tmr);
152 WaitIO(tmr);
154 SetSignal(0, sig);
156 return sigs &~ sig;