2 Copyright © 2017-2018, The AROS Development Team. All rights reserved.
7 #include <aros/debug.h>
9 #include <aros/types/timespec_s.h>
10 #include <aros/asmcall.h>
11 #include <exec/execbase.h>
12 #include <exec/lists.h>
14 #define __AROS_KERNEL__
16 #include "exec_intern.h"
18 #include "kernel_intern.h"
20 #include "intservers.h"
23 * Unlike the VBlankServer, we might not run at a fixed 60Hz.
25 int APICHeartbeatServer(struct ExceptionContext
*regs
, struct KernelBase
*KernelBase
, struct ExecBase
*SysBase
)
27 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
28 struct APICData
*apicData
= pdata
->kb_APIC
;
29 #if defined(__AROSEXEC_SMP__)
30 IPTR __LAPICBase
= apicData
->lapicBase
;
31 struct X86SchedulerPrivate
*apicScheduleData
;
36 if (apicData
->flags
& APF_TIMER
)
38 #if defined(__AROSEXEC_SMP__)
39 apicid_t cpuNum
= core_APIC_GetNumber(apicData
);
43 apicData
->cores
[cpuNum
].cpu_LAPICTick
+= APIC_REG(__LAPICBase
, APIC_TIMER_ICR
);
45 // Relaunch LAPIC timer
46 APIC_REG(__LAPICBase
, APIC_TIMER_ICR
) = (apicData
->cores
[cpuNum
].cpu_TimerFreq
+ 500) / 1000;
48 if ((now
- apicData
->cores
[cpuNum
].cpu_LastCPULoadTime
) > apicData
->cores
[cpuNum
].cpu_TSCFreq
)
51 UQUAD timeCur
= now
- apicData
->cores
[cpuNum
].cpu_LastCPULoadTime
;
53 /* Lock all lists to make sure we catch all the tasks */
54 KrnSpinLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
, NULL
, SPINLOCK_MODE_READ
);
55 ForeachNode(&SysBase
->TaskReady
, t
)
57 if (cpuNum
== IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
)
59 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuUsage
=
60 (IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
<< 32) / timeCur
;
61 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
= 0;
64 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
66 KrnSpinLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
, NULL
, SPINLOCK_MODE_READ
);
67 ForeachNode(&SysBase
->TaskWait
, t
)
69 if (cpuNum
== IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
)
71 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuUsage
=
72 (IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
<< 32) / timeCur
;
73 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
= 0;
76 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskWaitSpinLock
);
78 KrnSpinLock(&PrivExecBase(SysBase
)->TaskRunningSpinLock
, NULL
, SPINLOCK_MODE_READ
);
79 ForeachNode(&PrivExecBase(SysBase
)->TaskRunning
, t
)
81 if (cpuNum
== IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
)
84 TaskRunning list is different than others. Here the iet_private2 field is not yet updated,
85 so we have to update the CPU time in this place.
87 UQUAD time
= IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
+
88 now
- IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private1
;
91 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuUsage
= (time
<< 32) / timeCur
;
93 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuUsage
= 0xffffffff;
95 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
-= time
;
98 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskRunningSpinLock
);
100 KrnSpinLock(&PrivExecBase(SysBase
)->TaskSpinningLock
, NULL
, SPINLOCK_MODE_READ
);
101 ForeachNode(&PrivExecBase(SysBase
)->TaskSpinning
, t
)
103 if (cpuNum
== IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
)
105 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_CpuUsage
=
106 (IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
<< 32) / timeCur
;
107 IntETask(t
->tc_UnionETask
.tc_ETask
)->iet_private2
= 0;
110 KrnSpinUnLock(&PrivExecBase(SysBase
)->TaskSpinningLock
);
112 apicData
->cores
[cpuNum
].cpu_Load
=
113 ((apicData
->cores
[cpuNum
].cpu_TSCFreq
- apicData
->cores
[cpuNum
].cpu_SleepTime
) << 32) / timeCur
;
115 D(bug("[Kernel:APIC.%03u] %s() cpu load %08x\n", cpuNum
, __func__
, (ULONG
)apicData
->cores
[cpuNum
].cpu_Load
));
116 apicData
->cores
[cpuNum
].cpu_SleepTime
= 0;
117 apicData
->cores
[cpuNum
].cpu_LastCPULoadTime
= now
;
120 D(bug("[Kernel:APIC.%03u] %s(), tick=%08x:%08x\n", cpuNum
, __func__
, (ULONG
)(apicData
->cores
[cpuNum
].cpu_LAPICTick
>> 32),
121 (ULONG
)(apicData
->cores
[cpuNum
].cpu_LAPICTick
& 0xffffffff)));
123 apicTLS
= apicData
->cores
[cpuNum
].cpu_TLS
;
124 if ((apicTLS
) && ((apicScheduleData
= apicTLS
->ScheduleData
) != NULL
))
126 if ((current
= apicScheduleData
->Elapsed
))
128 if ((apicScheduleData
->Elapsed
= (current
- apicScheduleData
->Granularity
)) == 0)
130 __AROS_ATOMIC_OR_L(apicScheduleData
->ScheduleFlags
, TLSSF_Quantum
);
131 __AROS_ATOMIC_OR_L(apicScheduleData
->ScheduleFlags
, TLSSF_Switch
);
136 D(bug("[Kernel:APIC] %s()\n", __func__
));
138 current
= SCHEDELAPSED_GET
;
140 SCHEDELAPSED_SET(--current
);
144 FLAG_SCHEDQUANTUM_SET
;
145 FLAG_SCHEDSWITCH_SET
;