ced2464851ae26ff732fd4c0f9271ab4ada3b703
[gem5.git] / src / dev / arm / gic_pl390.cc
1 /*
2 * Copyright (c) 2010, 2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 * Prakash Ramrakhyani
42 */
43
44 #include "base/trace.hh"
45 #include "debug/Checkpoint.hh"
46 #include "debug/GIC.hh"
47 #include "debug/IPI.hh"
48 #include "debug/Interrupt.hh"
49 #include "dev/arm/gic_pl390.hh"
50 #include "dev/terminal.hh"
51 #include "mem/packet.hh"
52 #include "mem/packet_access.hh"
53
54 Pl390::Pl390(const Params *p)
55 : BaseGic(p), distAddr(p->dist_addr),
56 cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
57 cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
58 enabled(false), itLines(p->it_lines), irqEnable(false)
59 {
60 itLinesLog2 = ceilLog2(itLines);
61
62 for (int x = 0; x < CPU_MAX; x++) {
63 cpuEnabled[x] = false;
64 cpuPriority[x] = 0xff;
65 cpuBpr[x] = 0;
66 // Initialize cpu highest int
67 cpuHighestInt[x] = SPURIOUS_INT;
68 postIntEvent[x] = new PostIntEvent(x, p->platform);
69 }
70 DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
71 cpuEnabled[1]);
72
73 for (int x = 0; x < INT_BITS_MAX; x++) {
74 intEnabled[x] = 0;
75 pendingInt[x] = 0;
76 activeInt[x] = 0;
77 }
78
79 for (int x = 0; x < INT_LINES_MAX; x++) {
80 intPriority[x] = 0;
81 cpuTarget[x] = 0;
82 }
83
84 for (int x = 0; x < INT_BITS_MAX*2; x++) {
85 intConfig[x] = 0;
86 }
87
88 for (int x = 0; x < SGI_MAX; x++) {
89 cpuSgiActive[x] = 0;
90 cpuSgiPending[x] = 0;
91 }
92 for (int x = 0; x < CPU_MAX; x++) {
93 cpuPpiActive[x] = 0;
94 cpuPpiPending[x] = 0;
95 }
96
97 for (int i = 0; i < CPU_MAX; i++) {
98 for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
99 bankedIntPriority[i][j] = 0;
100 }
101 }
102 }
103
104 Tick
105 Pl390::read(PacketPtr pkt)
106 {
107
108 Addr addr = pkt->getAddr();
109
110 if (addr >= distAddr && addr < distAddr + DIST_SIZE)
111 return readDistributor(pkt);
112 else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
113 return readCpu(pkt);
114 else
115 panic("Read to unknown address %#x\n", pkt->getAddr());
116 }
117
118
119 Tick
120 Pl390::write(PacketPtr pkt)
121 {
122
123 Addr addr = pkt->getAddr();
124
125 if (addr >= distAddr && addr < distAddr + DIST_SIZE)
126 return writeDistributor(pkt);
127 else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
128 return writeCpu(pkt);
129 else
130 panic("Write to unknown address %#x\n", pkt->getAddr());
131 }
132
133 Tick
134 Pl390::readDistributor(PacketPtr pkt)
135 {
136 Addr daddr = pkt->getAddr() - distAddr;
137
138 int ctx_id = pkt->req->contextId();
139
140 DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
141
142 if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
143 assert((daddr-ICDISER_ST) >> 2 < 32);
144 pkt->set<uint32_t>(intEnabled[(daddr-ICDISER_ST)>>2]);
145 goto done;
146 }
147
148 if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
149 assert((daddr-ICDICER_ST) >> 2 < 32);
150 pkt->set<uint32_t>(intEnabled[(daddr-ICDICER_ST)>>2]);
151 goto done;
152 }
153
154 if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
155 assert((daddr-ICDISPR_ST) >> 2 < 32);
156 pkt->set<uint32_t>(pendingInt[(daddr-ICDISPR_ST)>>2]);
157 goto done;
158 }
159
160 if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
161 assert((daddr-ICDICPR_ST) >> 2 < 32);
162 pkt->set<uint32_t>(pendingInt[(daddr-ICDICPR_ST)>>2]);
163 goto done;
164 }
165
166 if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) {
167 assert((daddr-ICDABR_ST) >> 2 < 32);
168 pkt->set<uint32_t>(activeInt[(daddr-ICDABR_ST)>>2]);
169 goto done;
170 }
171
172 if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
173 Addr int_num;
174 int_num = daddr - ICDIPR_ST;
175 assert(int_num < INT_LINES_MAX);
176 DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
177
178 uint8_t* int_p;
179 if (int_num < (SGI_MAX + PPI_MAX))
180 int_p = bankedIntPriority[ctx_id];
181 else
182 int_p = intPriority;
183
184 switch (pkt->getSize()) {
185 case 1:
186 pkt->set<uint8_t>(int_p[int_num]);
187 break;
188 case 2:
189 assert((int_num + 1) < INT_LINES_MAX);
190 pkt->set<uint16_t>(int_p[int_num] |
191 int_p[int_num+1] << 8);
192 break;
193 case 4:
194 assert((int_num + 3) < INT_LINES_MAX);
195 pkt->set<uint32_t>(int_p[int_num] |
196 int_p[int_num+1] << 8 |
197 int_p[int_num+2] << 16 |
198 int_p[int_num+3] << 24);
199 break;
200 default:
201 panic("Invalid size while reading priority regs in GIC: %d\n",
202 pkt->getSize());
203 }
204 goto done;
205 }
206
207 if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
208 Addr int_num;
209 int_num = (daddr-ICDIPTR_ST) ;
210 DPRINTF(GIC, "Reading processor target register for int# %#x \n",
211 int_num);
212 assert(int_num < INT_LINES_MAX);
213
214 // First 31 interrupts only target single processor (SGI)
215 if (int_num > 31) {
216 if (pkt->getSize() == 1) {
217 pkt->set<uint8_t>(cpuTarget[int_num]);
218 } else {
219 assert(pkt->getSize() == 4);
220 int_num = mbits(int_num, 31, 2);
221 pkt->set<uint32_t>(cpuTarget[int_num] |
222 cpuTarget[int_num+1] << 8 |
223 cpuTarget[int_num+2] << 16 |
224 cpuTarget[int_num+3] << 24) ;
225 }
226 } else {
227 assert(ctx_id < sys->numRunningContexts());
228 // convert the CPU id number into a bit mask
229 uint32_t ctx_mask = power(2, ctx_id);
230 // replicate the 8-bit mask 4 times in a 32-bit word
231 ctx_mask |= ctx_mask << 8;
232 ctx_mask |= ctx_mask << 16;
233 pkt->set<uint32_t>(ctx_mask);
234 }
235 goto done;
236 }
237
238 if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
239 assert((daddr-ICDICFR_ST) >> 2 < 64);
240 /** @todo software generated interrutps and PPIs
241 * can't be configured in some ways
242 */
243 pkt->set<uint32_t>(intConfig[(daddr-ICDICFR_ST)>>2]);
244 goto done;
245 }
246
247 switch(daddr) {
248 case ICDDCR:
249 pkt->set<uint32_t>(enabled);
250 break;
251 case ICDICTR:
252 uint32_t tmp;
253 tmp = ((sys->numRunningContexts() - 1) << 5) |
254 (itLines/INT_BITS_MAX -1);
255 pkt->set<uint32_t>(tmp);
256 break;
257 default:
258 panic("Tried to read Gic distributor at offset %#x\n", daddr);
259 break;
260 }
261 done:
262 pkt->makeAtomicResponse();
263 return distPioDelay;
264 }
265
266 Tick
267 Pl390::readCpu(PacketPtr pkt)
268 {
269 Addr daddr = pkt->getAddr() - cpuAddr;
270
271 assert(pkt->req->hasContextId());
272 int ctx_id = pkt->req->contextId();
273 assert(ctx_id < sys->numRunningContexts());
274
275 DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
276 ctx_id);
277
278 switch(daddr) {
279 case ICCICR:
280 pkt->set<uint32_t>(cpuEnabled[ctx_id]);
281 break;
282 case ICCPMR:
283 pkt->set<uint32_t>(cpuPriority[ctx_id]);
284 break;
285 case ICCBPR:
286 pkt->set<uint32_t>(cpuBpr[ctx_id]);
287 break;
288 case ICCIAR:
289 if (enabled && cpuEnabled[ctx_id]) {
290 int active_int = cpuHighestInt[ctx_id];
291 IAR iar = 0;
292 iar.ack_id = active_int;
293 iar.cpu_id = 0;
294 if (active_int < SGI_MAX) {
295 // this is a software interrupt from another CPU
296 if (!cpuSgiPending[active_int])
297 panic("Interrupt %d active but no CPU generated it?\n",
298 active_int);
299 for (int x = 0; x < CPU_MAX; x++) {
300 // See which CPU generated the interrupt
301 uint8_t cpugen =
302 bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
303 if (cpugen & (1 << ctx_id)) {
304 iar.cpu_id = x;
305 break;
306 }
307 }
308 uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id);
309 cpuSgiActive[iar.ack_id] |= sgi_num;
310 cpuSgiPending[iar.ack_id] &= ~sgi_num;
311 } else if (active_int < (SGI_MAX + PPI_MAX) ) {
312 uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX);
313 cpuPpiActive[ctx_id] |= int_num;
314 updateRunPri();
315 cpuPpiPending[ctx_id] &= ~int_num;
316
317 } else {
318 uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
319 activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
320 updateRunPri();
321 pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
322 }
323
324 DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
325 ctx_id, iar.ack_id, iar.cpu_id, iar);
326 cpuHighestInt[ctx_id] = SPURIOUS_INT;
327 updateIntState(-1);
328 pkt->set<uint32_t>(iar);
329 platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
330 } else {
331 pkt->set<uint32_t>(SPURIOUS_INT);
332 }
333
334 break;
335 case ICCRPR:
336 pkt->set<uint32_t>(iccrpr[0]);
337 break;
338 case ICCHPIR:
339 pkt->set<uint32_t>(0);
340 panic("Need to implement HPIR");
341 break;
342 default:
343 panic("Tried to read Gic cpu at offset %#x\n", daddr);
344 break;
345 }
346 pkt->makeAtomicResponse();
347 return cpuPioDelay;
348 }
349
350 Tick
351 Pl390::writeDistributor(PacketPtr pkt)
352 {
353 Addr daddr = pkt->getAddr() - distAddr;
354
355 assert(pkt->req->hasContextId());
356 int ctx_id = pkt->req->contextId();
357
358 uint32_t pkt_data M5_VAR_USED;
359 switch (pkt->getSize())
360 {
361 case 1:
362 pkt_data = pkt->get<uint8_t>();
363 break;
364 case 2:
365 pkt_data = pkt->get<uint16_t>();
366 break;
367 case 4:
368 pkt_data = pkt->get<uint32_t>();
369 break;
370 default:
371 panic("Invalid size when writing to priority regs in Gic: %d\n",
372 pkt->getSize());
373 }
374
375 DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
376 daddr, pkt->getSize(), pkt_data);
377
378 if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
379 assert((daddr-ICDISER_ST) >> 2 < 32);
380 intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>();
381 goto done;
382 }
383
384 if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
385 assert((daddr-ICDICER_ST) >> 2 < 32);
386 intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>();
387 goto done;
388 }
389
390 if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
391 assert((daddr-ICDISPR_ST) >> 2 < 32);
392 pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>();
393 pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
394 updateIntState((daddr-ICDISPR_ST) >> 2);
395 goto done;
396 }
397
398 if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
399 assert((daddr-ICDICPR_ST) >> 2 < 32);
400 pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>();
401 pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
402 updateIntState((daddr-ICDICPR_ST) >> 2);
403 goto done;
404 }
405
406 if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
407 Addr int_num = daddr - ICDIPR_ST;
408 assert(int_num < INT_LINES_MAX);
409 uint8_t* int_p;
410 if (int_num < (SGI_MAX + PPI_MAX))
411 int_p = bankedIntPriority[ctx_id];
412 else
413 int_p = intPriority;
414 uint32_t tmp;
415 switch(pkt->getSize()) {
416 case 1:
417 tmp = pkt->get<uint8_t>();
418 int_p[int_num] = bits(tmp, 7, 0);
419 break;
420 case 2:
421 tmp = pkt->get<uint16_t>();
422 int_p[int_num] = bits(tmp, 7, 0);
423 int_p[int_num + 1] = bits(tmp, 15, 8);
424 break;
425 case 4:
426 tmp = pkt->get<uint32_t>();
427 int_p[int_num] = bits(tmp, 7, 0);
428 int_p[int_num + 1] = bits(tmp, 15, 8);
429 int_p[int_num + 2] = bits(tmp, 23, 16);
430 int_p[int_num + 3] = bits(tmp, 31, 24);
431 break;
432 default:
433 panic("Invalid size when writing to priority regs in Gic: %d\n",
434 pkt->getSize());
435 }
436
437 updateIntState(-1);
438 updateRunPri();
439 goto done;
440 }
441
442 if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
443 Addr int_num = (daddr-ICDIPTR_ST) ;
444 assert(int_num < INT_LINES_MAX);
445 // First 31 interrupts only target single processor
446 if (int_num >= SGI_MAX) {
447 if (pkt->getSize() == 1) {
448 uint8_t tmp = pkt->get<uint8_t>();
449 cpuTarget[int_num] = tmp & 0xff;
450 } else {
451 assert (pkt->getSize() == 4);
452 int_num = mbits(int_num, 31, 2);
453 uint32_t tmp = pkt->get<uint32_t>();
454 cpuTarget[int_num] = bits(tmp, 7, 0);
455 cpuTarget[int_num+1] = bits(tmp, 15, 8);
456 cpuTarget[int_num+2] = bits(tmp, 23, 16);
457 cpuTarget[int_num+3] = bits(tmp, 31, 24);
458 }
459 updateIntState((daddr-ICDIPTR_ST)>>2);
460 }
461 goto done;
462 }
463
464 if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
465 assert((daddr-ICDICFR_ST) >> 2 < 64);
466 intConfig[(daddr-ICDICFR_ST)>>2] = pkt->get<uint32_t>();
467 if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
468 warn("GIC N:N mode selected and not supported at this time\n");
469 goto done;
470 }
471
472 switch(daddr) {
473 case ICDDCR:
474 enabled = pkt->get<uint32_t>();
475 DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
476 break;
477 case ICDSGIR:
478 softInt(ctx_id, pkt->get<uint32_t>());
479 break;
480 default:
481 panic("Tried to write Gic distributor at offset %#x\n", daddr);
482 break;
483 }
484
485 done:
486 pkt->makeAtomicResponse();
487 return distPioDelay;
488 }
489
490 Tick
491 Pl390::writeCpu(PacketPtr pkt)
492 {
493 Addr daddr = pkt->getAddr() - cpuAddr;
494
495 assert(pkt->req->hasContextId());
496 int ctx_id = pkt->req->contextId();
497 IAR iar;
498
499 DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
500 ctx_id, daddr, pkt->get<uint32_t>());
501
502 switch(daddr) {
503 case ICCICR:
504 cpuEnabled[ctx_id] = pkt->get<uint32_t>();
505 break;
506 case ICCPMR:
507 cpuPriority[ctx_id] = pkt->get<uint32_t>();
508 break;
509 case ICCBPR:
510 cpuBpr[ctx_id] = pkt->get<uint32_t>();
511 break;
512 case ICCEOIR:
513 iar = pkt->get<uint32_t>();
514 if (iar.ack_id < SGI_MAX) {
515 // Clear out the bit that corrseponds to the cleared int
516 uint64_t clr_int = ULL(1) << (ctx_id + 8 * iar.cpu_id);
517 if (!(cpuSgiActive[iar.ack_id] & clr_int))
518 panic("Done handling a SGI that isn't active?\n");
519 cpuSgiActive[iar.ack_id] &= ~clr_int;
520 } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
521 uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
522 if (!(cpuPpiActive[ctx_id] & int_num))
523 panic("CPU %d Done handling a PPI interrupt that isn't active?\n", ctx_id);
524 cpuPpiActive[ctx_id] &= ~int_num;
525 } else {
526 uint32_t int_num = 1 << intNumToBit(iar.ack_id);
527 if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
528 panic("Done handling interrupt that isn't active?\n");
529 activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
530 }
531 updateRunPri();
532 DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
533 ctx_id, iar.ack_id, iar.cpu_id);
534 break;
535 default:
536 panic("Tried to write Gic cpu at offset %#x\n", daddr);
537 break;
538 }
539 if (cpuEnabled[ctx_id]) updateIntState(-1);
540 pkt->makeAtomicResponse();
541 return cpuPioDelay;
542 }
543
544 void
545 Pl390::softInt(int ctx_id, SWI swi)
546 {
547 switch (swi.list_type) {
548 case 1:
549 // interrupt all
550 uint8_t cpu_list;
551 cpu_list = 0;
552 for (int x = 0; x < CPU_MAX; x++)
553 cpu_list |= cpuEnabled[x] ? 1 << x : 0;
554 swi.cpu_list = cpu_list;
555 break;
556 case 2:
557 // interrupt requesting cpu only
558 swi.cpu_list = 1 << ctx_id;
559 break;
560 // else interrupt cpus specified
561 }
562
563 DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id,
564 swi.cpu_list);
565 for (int i = 0; i < CPU_MAX; i++) {
566 DPRINTF(IPI, "Processing CPU %d\n", i);
567 if (!cpuEnabled[i])
568 continue;
569 if (swi.cpu_list & (1 << i))
570 cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx_id);
571 DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, cpuSgiPending[swi.sgi_id]);
572 }
573 updateIntState(-1);
574 }
575
576 uint64_t
577 Pl390::genSwiMask(int cpu)
578 {
579 if (cpu > 7)
580 panic("Invalid CPU ID\n");
581 return ULL(0x0101010101010101) << cpu;
582 }
583
584 void
585 Pl390::updateIntState(int hint)
586 {
587 for (int cpu = 0; cpu < CPU_MAX; cpu++) {
588 if (!cpuEnabled[cpu])
589 continue;
590 if (cpu >= sys->numContexts())
591 break;
592
593 /*@todo use hint to do less work. */
594 int highest_int = SPURIOUS_INT;
595 // Priorities below that set in ICCPMR can be ignored
596 uint8_t highest_pri = cpuPriority[cpu];
597
598 // Check SGIs
599 for (int swi = 0; swi < SGI_MAX; swi++) {
600 if (!cpuSgiPending[swi])
601 continue;
602 if (cpuSgiPending[swi] & genSwiMask(cpu))
603 if (highest_pri > bankedIntPriority[cpu][swi]) {
604 highest_pri = bankedIntPriority[cpu][swi];
605 highest_int = swi;
606 }
607 }
608
609 // Check PPIs
610 if (cpuPpiPending[cpu]) {
611 for (int ppi = 0; ppi < PPI_MAX; ppi++) {
612 if (cpuPpiPending[cpu] & (1 << ppi))
613 if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
614 highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
615 highest_int = SGI_MAX + ppi;
616 }
617 }
618 }
619
620 bool mp_sys = sys->numRunningContexts() > 1;
621 // Check other ints
622 for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
623 if (intEnabled[x] & pendingInt[x]) {
624 for (int y = 0; y < INT_BITS_MAX; y++) {
625 uint32_t int_nm = x * INT_BITS_MAX + y;
626 DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
627 /* Set current pending int as highest int for current cpu
628 if the interrupt's priority higher than current prioirty
629 and if currrent cpu is the target (for mp configs only)
630 */
631 if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
632 (intPriority[int_nm] < highest_pri))
633 if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) {
634 highest_pri = intPriority[int_nm];
635 highest_int = int_nm;
636 }
637 }
638 }
639 }
640
641 cpuHighestInt[cpu] = highest_int;
642
643 if (highest_int == SPURIOUS_INT)
644 continue;
645
646 /* @todo make this work for more than one cpu, need to handle 1:N, N:N
647 * models */
648 if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
649 !(activeInt[intNumToWord(highest_int)]
650 & (1 << intNumToBit(highest_int)))) {
651
652 DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
653 cpu);
654 postInt(cpu, curTick() + intLatency);
655 }
656 }
657 }
658
659 void
660 Pl390::updateRunPri()
661 {
662 for (int cpu = 0; cpu < CPU_MAX; cpu++) {
663 if (!cpuEnabled[cpu])
664 continue;
665 uint8_t maxPriority = 0xff;
666 for (int i = 0; i < itLines; i++){
667 if (i < SGI_MAX) {
668 if ((cpuSgiActive[i] & genSwiMask(cpu)) &&
669 (bankedIntPriority[cpu][i] < maxPriority))
670 maxPriority = bankedIntPriority[cpu][i];
671 } else if (i < (SGI_MAX + PPI_MAX)) {
672 if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
673 (bankedIntPriority[cpu][i] < maxPriority))
674 maxPriority = bankedIntPriority[cpu][i];
675
676 } else {
677 if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
678 if (intPriority[i] < maxPriority)
679 maxPriority = intPriority[i];
680 }
681 }
682 iccrpr[cpu] = maxPriority;
683 }
684 }
685
686 void
687 Pl390::sendInt(uint32_t num)
688 {
689 DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n",
690 num, cpuTarget[num]);
691 if (cpuTarget[num] & (cpuTarget[num] - 1))
692 panic("Multiple targets for peripheral interrupts is not supported\n");
693 pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
694 updateIntState(intNumToWord(num));
695
696 }
697
698 void
699 Pl390::sendPPInt(uint32_t num, uint32_t cpu)
700 {
701 DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n",
702 num, cpu);
703 cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
704 updateIntState(intNumToWord(num));
705 }
706
707 void
708 Pl390::clearInt(uint32_t number)
709 {
710 /* @todo assume edge triggered only at the moment. Nothing to do. */
711 }
712
713 void
714 Pl390::clearPPInt(uint32_t num, uint32_t cpu)
715 {
716 DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n",
717 num, cpu);
718 cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX));
719 updateIntState(intNumToWord(num));
720 }
721
722 void
723 Pl390::postInt(uint32_t cpu, Tick when)
724 {
725 if (!(postIntEvent[cpu]->scheduled()))
726 eventq->schedule(postIntEvent[cpu], when);
727 }
728
729 AddrRangeList
730 Pl390::getAddrRanges() const
731 {
732 AddrRangeList ranges;
733 ranges.push_back(RangeSize(distAddr, DIST_SIZE));
734 ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
735 return ranges;
736 }
737
738
739 void
740 Pl390::serialize(std::ostream &os)
741 {
742 DPRINTF(Checkpoint, "Serializing Arm GIC\n");
743
744 SERIALIZE_SCALAR(distAddr);
745 SERIALIZE_SCALAR(cpuAddr);
746 SERIALIZE_SCALAR(distPioDelay);
747 SERIALIZE_SCALAR(cpuPioDelay);
748 SERIALIZE_SCALAR(enabled);
749 SERIALIZE_SCALAR(itLines);
750 SERIALIZE_SCALAR(itLinesLog2);
751 SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
752 SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
753 SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
754 SERIALIZE_ARRAY(iccrpr, CPU_MAX);
755 SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
756 SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
757 SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
758 SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
759 SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
760 SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
761 SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
762 SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
763 SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
764 SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
765 SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
766 SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
767 SERIALIZE_SCALAR(irqEnable);
768 Tick interrupt_time[CPU_MAX];
769 for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
770 interrupt_time[cpu] = 0;
771 if (postIntEvent[cpu]->scheduled()) {
772 interrupt_time[cpu] = postIntEvent[cpu]->when();
773 }
774 }
775 SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
776
777 }
778
779 void
780 Pl390::unserialize(Checkpoint *cp, const std::string &section)
781 {
782 DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
783
784 UNSERIALIZE_SCALAR(distAddr);
785 UNSERIALIZE_SCALAR(cpuAddr);
786 UNSERIALIZE_SCALAR(distPioDelay);
787 UNSERIALIZE_SCALAR(cpuPioDelay);
788 UNSERIALIZE_SCALAR(enabled);
789 UNSERIALIZE_SCALAR(itLines);
790 UNSERIALIZE_SCALAR(itLinesLog2);
791 UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
792 UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
793 UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
794 UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
795 UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
796 UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
797 UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
798 UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
799 UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
800 UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
801 UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
802 UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
803 UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
804 UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
805 UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
806 UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
807 UNSERIALIZE_SCALAR(irqEnable);
808
809 Tick interrupt_time[CPU_MAX];
810 UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
811
812 for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
813 if (interrupt_time[cpu])
814 schedule(postIntEvent[cpu], interrupt_time[cpu]);
815 }
816
817 }
818
819 Pl390 *
820 Pl390Params::create()
821 {
822 return new Pl390(this);
823 }
824
825 /* Functions for debugging and testing */
826 void
827 Pl390::driveSPI(unsigned int spiVect)
828 {
829 DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
830 pendingInt[1] |= spiVect;
831 if (irqEnable && enabled) {
832 updateIntState(-1);
833 }
834 }
835
836 void
837 Pl390::driveIrqEn( bool state)
838 {
839 irqEnable = state;
840 DPRINTF(GIC, " Enabling Irq\n");
841 updateIntState(-1);
842 }
843
844 void
845 Pl390::driveLegIRQ(bool state)
846 {
847 if (irqEnable && !(!enabled && cpuEnabled[0])) {
848 if (state) {
849 DPRINTF(GIC, "Driving Legacy Irq\n");
850 platform->intrctrl->post(0, ArmISA::INT_IRQ, 0);
851 }
852 else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
853 }
854 }
855
856 void
857 Pl390::driveLegFIQ(bool state)
858 {
859 if (state)
860 platform->intrctrl->post(0, ArmISA::INT_FIQ, 0);
861 else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0);
862 }