File : s-bcprmu-8641d.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . C P U _ P R I M I T I V E S . --
6 -- M U L T I P R O C E S S O R S --
7 -- --
8 -- B o d y --
9 -- --
10 -- Copyright (C) 2014-2015, AdaCore --
11 -- --
12 -- GNARL is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 3, or (at your option) any later ver- --
15 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- --
19 -- --
20 -- --
21 -- --
22 -- --
23 -- You should have received a copy of the GNU General Public License and --
24 -- a copy of the GCC Runtime Library Exception along with this program; --
25 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
26 -- <http://www.gnu.org/licenses/>. --
27 -- --
28 ------------------------------------------------------------------------------
29
30 pragma Restrictions (No_Elaboration_Code);
31
32 with Interfaces; use Interfaces;
33 with System.Multiprocessors; use System.Multiprocessors;
34 with System.BB.Interrupts; use System.BB.Interrupts;
35 with System.BB.Protection;
36 with System.BB.Board_Parameters; use System.BB.Board_Parameters;
37
38 package body System.BB.CPU_Primitives.Multiprocessors is
39
40 procedure Poke_Handler (Interrupt : Interrupts.Interrupt_ID);
41
42 -----------------------------------------------------
43 -- The PCR register in the Memory Coherency Module --
44 -----------------------------------------------------
45
46 MCM_PCR : Unsigned_32;
47 for MCM_PCR'Address use System'To_Address (CCSRBAR + 16#1010#);
48 pragma Import (Ada, MCM_PCR);
49 -- Port configuration register
50
51 -----------------
52 -- Current_CPU --
53 -----------------
54
55 function Current_CPU return System.Multiprocessors.CPU is
56 Cpu_Id : Unsigned_32;
57 for Cpu_Id'Address use System'To_Address (CCSRBAR + 16#4_0090#);
58 pragma Import (Ada, Cpu_Id);
59 -- Per-CPU WHOAMI register
60 begin
61 return CPU_Range (Cpu_Id) + CPU'First;
62 end Current_CPU;
63
64 --------------
65 -- Poke_CPU --
66 --------------
67
68 procedure Poke_CPU (CPU_Id : System.Multiprocessors.CPU) is
69 Val : Unsigned_32;
70
71 IPI : Unsigned_32;
72 for IPI'Address use System'To_Address (CCSRBAR + 16#4_0040#);
73 pragma Import (Ada, IPI);
74 -- Per-CPU interproces interrupt dispatch register (IPIDR0)
75 begin
76 -- Send IPI0 to processor CPU_Id
77 Val := Shift_Left (1, CPU_Range'Pos (CPU_Id - CPU'First));
78 IPI := IPI or Val;
79 end Poke_CPU;
80
81 ---------------
82 -- Start_CPU --
83 ---------------
84
85 procedure Start_CPU (CPU_Id : System.Multiprocessors.CPU) is
86 Val : Unsigned_32;
87 begin
88 -- Enable processor CPU_Id
89 Val := Shift_Left (1, 24 + CPU_Range'Pos (CPU_Id - CPU'First));
90 MCM_PCR := MCM_PCR or Val;
91 end Start_CPU;
92
93 ------------------
94 -- Poke_Handler --
95 ------------------
96
97 procedure Poke_Handler (Interrupt : Interrupts.Interrupt_ID) is
98 Bogus : Unsigned_32;
99 pragma Unreferenced (Bogus);
100 IACK : Unsigned_32;
101 for IACK'Address use System'To_Address (CCSRBAR + 16#4_00a0#);
102 pragma Import (Ada, IACK);
103 EOI : Unsigned_32;
104 for EOI'Address use System'To_Address (CCSRBAR + 16#4_00b0#);
105 pragma Import (Ada, EOI);
106 begin
107 -- Make sure we are handling the right interrupt
108 pragma Assert (Interrupt = 1);
109
110 -- Acknowledge the interrupt by reading the OpenPIC IACK register
111 Bogus := IACK;
112
113 -- Just so that we can call a Leave_Kernel
114 Protection.Enter_Kernel;
115
116 -- Leave_Kernel will handle served entries and wake up their calling
117 -- threads
118 Protection.Leave_Kernel;
119
120 -- Disable interrupts in order to write to EOI register
121 CPU_Primitives.Disable_Interrupts;
122 EOI := 0;
123
124 end Poke_Handler;
125
126 --------------------
127 -- Start_All_CPUs --
128 --------------------
129
130 procedure Start_All_CPUs is
131 Val : Unsigned_32;
132
133 IPIVPR : Unsigned_32;
134 for IPIVPR'Address use System'To_Address (CCSRBAR + 16#4_10a0#);
135 pragma Import (Ada, IPIVPR);
136 -- IPI0 vector/priority register
137
138 PCTP : Unsigned_32;
139 for PCTP'Address use System'To_Address (CCSRBAR + 16#6_1080#);
140 pragma Import (Ada, PCTP);
141 -- Processor 1 current task priority register
142
143 begin
144 -- Nothing to do when there's only one CPU
145
146 if System.Multiprocessors.Number_Of_CPUs = 1 then
147 return;
148 end if;
149
150 Attach_Handler (Poke_Handler'Access, 1, Interrupt_Priority'First);
151 PCTP := 0;
152
153 -- Unask IPI, priority 15, vector #0
154 IPIVPR := (IPIVPR or 16#000f_0000#) and (not 16#8000_0000#);
155
156 -- Enable all CPUs
157 Val := Shift_Left
158 (Shift_Left (1, CPU_Range'Pos (Number_Of_CPUs)) - 1, 24);
159 MCM_PCR := MCM_PCR or Val;
160 end Start_All_CPUs;
161
162 end System.BB.CPU_Primitives.Multiprocessors;