2 * Copyright (c) 2010, 2013, 2015 ARM Limited
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.
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
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"
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)
60 itLinesLog2
= ceilLog2(itLines
);
62 for (int x
= 0; x
< CPU_MAX
; x
++) {
64 cpuEnabled
[x
] = false;
65 cpuPriority
[x
] = 0xff;
67 // Initialize cpu highest int
68 cpuHighestInt
[x
] = SPURIOUS_INT
;
69 postIntEvent
[x
] = new PostIntEvent(x
, p
->platform
);
71 DPRINTF(Interrupt
, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled
[0],
74 for (int x
= 0; x
< INT_BITS_MAX
; x
++) {
80 for (int x
= 0; x
< INT_LINES_MAX
; x
++) {
85 for (int x
= 0; x
< INT_BITS_MAX
*2; x
++) {
89 for (int x
= 0; x
< SGI_MAX
; x
++) {
93 for (int x
= 0; x
< CPU_MAX
; x
++) {
96 cpuSgiActiveExt
[x
] = 0;
97 cpuSgiPendingExt
[x
] = 0;
100 for (int i
= 0; i
< CPU_MAX
; i
++) {
101 for (int j
= 0; j
< (SGI_MAX
+ PPI_MAX
); j
++) {
102 bankedIntPriority
[i
][j
] = 0;
106 gem5ExtensionsEnabled
= false;
110 Pl390::read(PacketPtr pkt
)
113 Addr addr
= pkt
->getAddr();
115 if (addr
>= distAddr
&& addr
< distAddr
+ DIST_SIZE
)
116 return readDistributor(pkt
);
117 else if (addr
>= cpuAddr
&& addr
< cpuAddr
+ CPU_SIZE
)
120 panic("Read to unknown address %#x\n", pkt
->getAddr());
125 Pl390::write(PacketPtr pkt
)
128 Addr addr
= pkt
->getAddr();
130 if (addr
>= distAddr
&& addr
< distAddr
+ DIST_SIZE
)
131 return writeDistributor(pkt
);
132 else if (addr
>= cpuAddr
&& addr
< cpuAddr
+ CPU_SIZE
)
133 return writeCpu(pkt
);
135 panic("Write to unknown address %#x\n", pkt
->getAddr());
139 Pl390::readDistributor(PacketPtr pkt
)
141 Addr daddr
= pkt
->getAddr() - distAddr
;
143 ContextID ctx_id
= pkt
->req
->contextId();
145 DPRINTF(GIC
, "gic distributor read register %#x\n", daddr
);
147 if (daddr
>= ICDISER_ST
&& daddr
< ICDISER_ED
+ 4) {
148 assert((daddr
-ICDISER_ST
) >> 2 < 32);
149 pkt
->set
<uint32_t>(intEnabled
[(daddr
-ICDISER_ST
)>>2]);
153 if (daddr
>= ICDICER_ST
&& daddr
< ICDICER_ED
+ 4) {
154 assert((daddr
-ICDICER_ST
) >> 2 < 32);
155 pkt
->set
<uint32_t>(intEnabled
[(daddr
-ICDICER_ST
)>>2]);
159 if (daddr
>= ICDISPR_ST
&& daddr
< ICDISPR_ED
+ 4) {
160 assert((daddr
-ICDISPR_ST
) >> 2 < 32);
161 pkt
->set
<uint32_t>(pendingInt
[(daddr
-ICDISPR_ST
)>>2]);
165 if (daddr
>= ICDICPR_ST
&& daddr
< ICDICPR_ED
+ 4) {
166 assert((daddr
-ICDICPR_ST
) >> 2 < 32);
167 pkt
->set
<uint32_t>(pendingInt
[(daddr
-ICDICPR_ST
)>>2]);
171 if (daddr
>= ICDABR_ST
&& daddr
< ICDABR_ED
+ 4) {
172 assert((daddr
-ICDABR_ST
) >> 2 < 32);
173 pkt
->set
<uint32_t>(activeInt
[(daddr
-ICDABR_ST
)>>2]);
177 if (daddr
>= ICDIPR_ST
&& daddr
< ICDIPR_ED
+ 4) {
179 int_num
= daddr
- ICDIPR_ST
;
180 assert(int_num
< INT_LINES_MAX
);
181 DPRINTF(Interrupt
, "Reading interrupt priority at int# %#x \n",int_num
);
184 if (int_num
< (SGI_MAX
+ PPI_MAX
))
185 int_p
= bankedIntPriority
[ctx_id
];
189 switch (pkt
->getSize()) {
191 pkt
->set
<uint8_t>(int_p
[int_num
]);
194 assert((int_num
+ 1) < INT_LINES_MAX
);
195 pkt
->set
<uint16_t>(int_p
[int_num
] |
196 int_p
[int_num
+1] << 8);
199 assert((int_num
+ 3) < INT_LINES_MAX
);
200 pkt
->set
<uint32_t>(int_p
[int_num
] |
201 int_p
[int_num
+1] << 8 |
202 int_p
[int_num
+2] << 16 |
203 int_p
[int_num
+3] << 24);
206 panic("Invalid size while reading priority regs in GIC: %d\n",
212 if (daddr
>= ICDIPTR_ST
&& daddr
< ICDIPTR_ED
+ 4) {
214 int_num
= (daddr
-ICDIPTR_ST
) ;
215 DPRINTF(GIC
, "Reading processor target register for int# %#x \n",
217 assert(int_num
< INT_LINES_MAX
);
219 // First 31 interrupts only target single processor (SGI)
221 if (pkt
->getSize() == 1) {
222 pkt
->set
<uint8_t>(cpuTarget
[int_num
]);
224 assert(pkt
->getSize() == 4);
225 int_num
= mbits(int_num
, 31, 2);
226 pkt
->set
<uint32_t>(cpuTarget
[int_num
] |
227 cpuTarget
[int_num
+1] << 8 |
228 cpuTarget
[int_num
+2] << 16 |
229 cpuTarget
[int_num
+3] << 24) ;
232 assert(ctx_id
< sys
->numRunningContexts());
234 if (gem5ExtensionsEnabled
) {
237 // convert the CPU id number into a bit mask
238 ctx_mask
= power(2, ctx_id
);
240 // replicate the 8-bit mask 4 times in a 32-bit word
241 ctx_mask
|= ctx_mask
<< 8;
242 ctx_mask
|= ctx_mask
<< 16;
243 pkt
->set
<uint32_t>(ctx_mask
);
248 if (daddr
>= ICDICFR_ST
&& daddr
< ICDICFR_ED
+ 4) {
249 assert((daddr
-ICDICFR_ST
) >> 2 < 64);
250 /** @todo software generated interrutps and PPIs
251 * can't be configured in some ways
253 pkt
->set
<uint32_t>(intConfig
[(daddr
-ICDICFR_ST
)>>2]);
259 pkt
->set
<uint32_t>(enabled
);
263 tmp
= ((sys
->numRunningContexts() - 1) << 5) |
264 (itLines
/INT_BITS_MAX
-1) |
266 /* The 0x100 is a made-up flag to show that gem5 extensions
268 * write 0x200 to this register to enable it.
270 pkt
->set
<uint32_t>(tmp
);
273 panic("Tried to read Gic distributor at offset %#x\n", daddr
);
277 pkt
->makeAtomicResponse();
282 Pl390::readCpu(PacketPtr pkt
)
284 Addr daddr
= pkt
->getAddr() - cpuAddr
;
286 assert(pkt
->req
->hasContextId());
287 ContextID ctx_id
= pkt
->req
->contextId();
288 assert(ctx_id
< sys
->numRunningContexts());
290 DPRINTF(GIC
, "gic cpu read register %#x cpu context: %d\n", daddr
,
295 pkt
->set
<uint32_t>(0);
298 pkt
->set
<uint32_t>(cpuEnabled
[ctx_id
]);
301 pkt
->set
<uint32_t>(cpuPriority
[ctx_id
]);
304 pkt
->set
<uint32_t>(cpuBpr
[ctx_id
]);
307 if (enabled
&& cpuEnabled
[ctx_id
]) {
308 int active_int
= cpuHighestInt
[ctx_id
];
310 iar
.ack_id
= active_int
;
312 if (active_int
< SGI_MAX
) {
313 // this is a software interrupt from another CPU
314 if (!gem5ExtensionsEnabled
) {
315 panic_if(!cpuSgiPending
[active_int
],
316 "Interrupt %d active but no CPU generated it?\n",
318 for (int x
= 0; x
< sys
->numRunningContexts(); x
++) {
319 // See which CPU generated the interrupt
321 bits(cpuSgiPending
[active_int
], 7 + 8 * x
, 8 * x
);
322 if (cpugen
& (1 << ctx_id
)) {
327 uint64_t sgi_num
= ULL(1) << (ctx_id
+ 8 * iar
.cpu_id
);
328 cpuSgiActive
[iar
.ack_id
] |= sgi_num
;
329 cpuSgiPending
[iar
.ack_id
] &= ~sgi_num
;
331 uint64_t sgi_num
= ULL(1) << iar
.ack_id
;
332 cpuSgiActiveExt
[ctx_id
] |= sgi_num
;
333 cpuSgiPendingExt
[ctx_id
] &= ~sgi_num
;
335 } else if (active_int
< (SGI_MAX
+ PPI_MAX
) ) {
336 uint32_t int_num
= 1 << (cpuHighestInt
[ctx_id
] - SGI_MAX
);
337 cpuPpiActive
[ctx_id
] |= int_num
;
339 cpuPpiPending
[ctx_id
] &= ~int_num
;
342 uint32_t int_num
= 1 << intNumToBit(cpuHighestInt
[ctx_id
]);
343 activeInt
[intNumToWord(cpuHighestInt
[ctx_id
])] |= int_num
;
345 pendingInt
[intNumToWord(cpuHighestInt
[ctx_id
])] &= ~int_num
;
348 DPRINTF(Interrupt
,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
349 ctx_id
, iar
.ack_id
, iar
.cpu_id
, iar
);
350 cpuHighestInt
[ctx_id
] = SPURIOUS_INT
;
352 pkt
->set
<uint32_t>(iar
);
353 platform
->intrctrl
->clear(ctx_id
, ArmISA::INT_IRQ
, 0);
355 pkt
->set
<uint32_t>(SPURIOUS_INT
);
360 pkt
->set
<uint32_t>(iccrpr
[0]);
363 pkt
->set
<uint32_t>(0);
364 panic("Need to implement HPIR");
367 panic("Tried to read Gic cpu at offset %#x\n", daddr
);
370 pkt
->makeAtomicResponse();
375 Pl390::writeDistributor(PacketPtr pkt
)
377 Addr daddr
= pkt
->getAddr() - distAddr
;
379 assert(pkt
->req
->hasContextId());
380 ContextID ctx_id
= pkt
->req
->contextId();
382 uint32_t pkt_data M5_VAR_USED
;
383 switch (pkt
->getSize())
386 pkt_data
= pkt
->get
<uint8_t>();
389 pkt_data
= pkt
->get
<uint16_t>();
392 pkt_data
= pkt
->get
<uint32_t>();
395 panic("Invalid size when writing to priority regs in Gic: %d\n",
399 DPRINTF(GIC
, "gic distributor write register %#x size %#x value %#x \n",
400 daddr
, pkt
->getSize(), pkt_data
);
402 if (daddr
>= ICDISER_ST
&& daddr
< ICDISER_ED
+ 4) {
403 assert((daddr
-ICDISER_ST
) >> 2 < 32);
404 intEnabled
[(daddr
-ICDISER_ST
) >> 2] |= pkt
->get
<uint32_t>();
408 if (daddr
>= ICDICER_ST
&& daddr
< ICDICER_ED
+ 4) {
409 assert((daddr
-ICDICER_ST
) >> 2 < 32);
410 intEnabled
[(daddr
-ICDICER_ST
) >> 2] &= ~pkt
->get
<uint32_t>();
414 if (daddr
>= ICDISPR_ST
&& daddr
< ICDISPR_ED
+ 4) {
415 assert((daddr
-ICDISPR_ST
) >> 2 < 32);
416 pendingInt
[(daddr
-ICDISPR_ST
) >> 2] |= pkt
->get
<uint32_t>();
417 pendingInt
[0] &= SGI_MASK
; // Don't allow SGIs to be changed
418 updateIntState((daddr
-ICDISPR_ST
) >> 2);
422 if (daddr
>= ICDICPR_ST
&& daddr
< ICDICPR_ED
+ 4) {
423 assert((daddr
-ICDICPR_ST
) >> 2 < 32);
424 pendingInt
[(daddr
-ICDICPR_ST
) >> 2] &= ~pkt
->get
<uint32_t>();
425 pendingInt
[0] &= SGI_MASK
; // Don't allow SGIs to be changed
426 updateIntState((daddr
-ICDICPR_ST
) >> 2);
430 if (daddr
>= ICDIPR_ST
&& daddr
< ICDIPR_ED
+ 4) {
431 Addr int_num
= daddr
- ICDIPR_ST
;
432 assert(int_num
< INT_LINES_MAX
);
434 if (int_num
< (SGI_MAX
+ PPI_MAX
))
435 int_p
= bankedIntPriority
[ctx_id
];
439 switch(pkt
->getSize()) {
441 tmp
= pkt
->get
<uint8_t>();
442 int_p
[int_num
] = bits(tmp
, 7, 0);
445 tmp
= pkt
->get
<uint16_t>();
446 int_p
[int_num
] = bits(tmp
, 7, 0);
447 int_p
[int_num
+ 1] = bits(tmp
, 15, 8);
450 tmp
= pkt
->get
<uint32_t>();
451 int_p
[int_num
] = bits(tmp
, 7, 0);
452 int_p
[int_num
+ 1] = bits(tmp
, 15, 8);
453 int_p
[int_num
+ 2] = bits(tmp
, 23, 16);
454 int_p
[int_num
+ 3] = bits(tmp
, 31, 24);
457 panic("Invalid size when writing to priority regs in Gic: %d\n",
466 if (daddr
>= ICDIPTR_ST
&& daddr
< ICDIPTR_ED
+ 4) {
467 Addr int_num
= (daddr
-ICDIPTR_ST
) ;
468 assert(int_num
< INT_LINES_MAX
);
469 // First 31 interrupts only target single processor
470 if (int_num
>= SGI_MAX
) {
471 if (pkt
->getSize() == 1) {
472 uint8_t tmp
= pkt
->get
<uint8_t>();
473 cpuTarget
[int_num
] = tmp
& 0xff;
475 assert (pkt
->getSize() == 4);
476 int_num
= mbits(int_num
, 31, 2);
477 uint32_t tmp
= pkt
->get
<uint32_t>();
478 cpuTarget
[int_num
] = bits(tmp
, 7, 0);
479 cpuTarget
[int_num
+1] = bits(tmp
, 15, 8);
480 cpuTarget
[int_num
+2] = bits(tmp
, 23, 16);
481 cpuTarget
[int_num
+3] = bits(tmp
, 31, 24);
483 updateIntState((daddr
-ICDIPTR_ST
)>>2);
488 if (daddr
>= ICDICFR_ST
&& daddr
< ICDICFR_ED
+ 4) {
489 assert((daddr
-ICDICFR_ST
) >> 2 < 64);
490 intConfig
[(daddr
-ICDICFR_ST
)>>2] = pkt
->get
<uint32_t>();
491 if (pkt
->get
<uint32_t>() & NN_CONFIG_MASK
)
492 warn("GIC N:N mode selected and not supported at this time\n");
498 enabled
= pkt
->get
<uint32_t>();
499 DPRINTF(Interrupt
, "Distributor enable flag set to = %d\n", enabled
);
502 /* 0x200 is a made-up flag to enable gem5 extension functionality.
503 * This reg is not normally written.
505 gem5ExtensionsEnabled
= !!(pkt
->get
<uint32_t>() & 0x200);
506 DPRINTF(GIC
, "gem5 extensions %s\n", gem5ExtensionsEnabled
? "enabled" : "disabled");
509 softInt(ctx_id
, pkt
->get
<uint32_t>());
512 panic("Tried to write Gic distributor at offset %#x\n", daddr
);
517 pkt
->makeAtomicResponse();
522 Pl390::writeCpu(PacketPtr pkt
)
524 Addr daddr
= pkt
->getAddr() - cpuAddr
;
526 assert(pkt
->req
->hasContextId());
527 ContextID ctx_id
= pkt
->req
->contextId();
530 DPRINTF(GIC
, "gic cpu write register cpu:%d %#x val: %#x\n",
531 ctx_id
, daddr
, pkt
->get
<uint32_t>());
535 cpuEnabled
[ctx_id
] = pkt
->get
<uint32_t>();
538 cpuPriority
[ctx_id
] = pkt
->get
<uint32_t>();
541 cpuBpr
[ctx_id
] = pkt
->get
<uint32_t>();
544 iar
= pkt
->get
<uint32_t>();
545 if (iar
.ack_id
< SGI_MAX
) {
546 // Clear out the bit that corrseponds to the cleared int
547 uint64_t clr_int
= ULL(1) << (ctx_id
+ 8 * iar
.cpu_id
);
548 if (!(cpuSgiActive
[iar
.ack_id
] & clr_int
) &&
549 !(cpuSgiActiveExt
[ctx_id
] & (1 << iar
.ack_id
)))
550 panic("Done handling a SGI that isn't active?\n");
551 if (gem5ExtensionsEnabled
)
552 cpuSgiActiveExt
[ctx_id
] &= ~(1 << iar
.ack_id
);
554 cpuSgiActive
[iar
.ack_id
] &= ~clr_int
;
555 } else if (iar
.ack_id
< (SGI_MAX
+ PPI_MAX
) ) {
556 uint32_t int_num
= 1 << (iar
.ack_id
- SGI_MAX
);
557 if (!(cpuPpiActive
[ctx_id
] & int_num
))
558 panic("CPU %d Done handling a PPI interrupt "
559 "that isn't active?\n", ctx_id
);
560 cpuPpiActive
[ctx_id
] &= ~int_num
;
562 uint32_t int_num
= 1 << intNumToBit(iar
.ack_id
);
563 if (!(activeInt
[intNumToWord(iar
.ack_id
)] & int_num
))
564 warn("Done handling interrupt that isn't active: %d\n",
565 intNumToBit(iar
.ack_id
));
566 activeInt
[intNumToWord(iar
.ack_id
)] &= ~int_num
;
569 DPRINTF(Interrupt
, "CPU %d done handling intr IAR = %d from cpu %d\n",
570 ctx_id
, iar
.ack_id
, iar
.cpu_id
);
573 panic("Tried to write Gic cpu at offset %#x\n", daddr
);
576 if (cpuEnabled
[ctx_id
]) updateIntState(-1);
577 pkt
->makeAtomicResponse();
582 Pl390::softInt(ContextID ctx_id
, SWI swi
)
584 if (gem5ExtensionsEnabled
) {
585 switch (swi
.list_type
) {
587 // interrupt cpus specified
588 int dest
= swi
.cpu_list
;
589 DPRINTF(IPI
, "Generating softIRQ from CPU %d for CPU %d\n",
591 if (cpuEnabled
[dest
]) {
592 cpuSgiPendingExt
[dest
] |= (1 << swi
.sgi_id
);
593 DPRINTF(IPI
, "SGI[%d]=%#x\n", dest
,
594 cpuSgiPendingExt
[dest
]);
599 for (int i
= 0; i
< sys
->numContexts(); i
++) {
600 DPRINTF(IPI
, "Processing CPU %d\n", i
);
603 cpuSgiPendingExt
[i
] |= 1 << swi
.sgi_id
;
604 DPRINTF(IPI
, "SGI[%d]=%#x\n", swi
.sgi_id
,
605 cpuSgiPendingExt
[i
]);
609 // Interrupt requesting cpu only
610 DPRINTF(IPI
, "Generating softIRQ from CPU %d for CPU %d\n",
612 if (cpuEnabled
[ctx_id
]) {
613 cpuSgiPendingExt
[ctx_id
] |= (1 << swi
.sgi_id
);
614 DPRINTF(IPI
, "SGI[%d]=%#x\n", ctx_id
,
615 cpuSgiPendingExt
[ctx_id
]);
620 switch (swi
.list_type
) {
625 for (int x
= 0; x
< sys
->numContexts(); x
++)
626 cpu_list
|= cpuEnabled
[x
] ? 1 << x
: 0;
627 swi
.cpu_list
= cpu_list
;
630 // interrupt requesting cpu only
631 swi
.cpu_list
= 1 << ctx_id
;
633 // else interrupt cpus specified
636 DPRINTF(IPI
, "Generating softIRQ from CPU %d for %#x\n", ctx_id
,
638 for (int i
= 0; i
< sys
->numContexts(); i
++) {
639 DPRINTF(IPI
, "Processing CPU %d\n", i
);
642 if (swi
.cpu_list
& (1 << i
))
643 cpuSgiPending
[swi
.sgi_id
] |= (1 << i
) << (8 * ctx_id
);
644 DPRINTF(IPI
, "SGI[%d]=%#x\n", swi
.sgi_id
,
645 cpuSgiPending
[swi
.sgi_id
]);
652 Pl390::genSwiMask(int cpu
)
654 if (cpu
> sys
->numContexts())
655 panic("Invalid CPU ID\n");
656 return ULL(0x0101010101010101) << cpu
;
660 Pl390::updateIntState(int hint
)
662 for (int cpu
= 0; cpu
< sys
->numContexts(); cpu
++) {
663 if (!cpuEnabled
[cpu
])
666 /*@todo use hint to do less work. */
667 int highest_int
= SPURIOUS_INT
;
668 // Priorities below that set in ICCPMR can be ignored
669 uint8_t highest_pri
= cpuPriority
[cpu
];
672 for (int swi
= 0; swi
< SGI_MAX
; swi
++) {
673 if (!cpuSgiPending
[swi
] && !cpuSgiPendingExt
[cpu
])
675 if ((cpuSgiPending
[swi
] & genSwiMask(cpu
)) ||
676 (cpuSgiPendingExt
[cpu
] & (1 << swi
)))
677 if (highest_pri
> bankedIntPriority
[cpu
][swi
]) {
678 highest_pri
= bankedIntPriority
[cpu
][swi
];
684 if (cpuPpiPending
[cpu
]) {
685 for (int ppi
= 0; ppi
< PPI_MAX
; ppi
++) {
686 if (cpuPpiPending
[cpu
] & (1 << ppi
))
687 if (highest_pri
> bankedIntPriority
[cpu
][SGI_MAX
+ ppi
]) {
688 highest_pri
= bankedIntPriority
[cpu
][SGI_MAX
+ ppi
];
689 highest_int
= SGI_MAX
+ ppi
;
694 bool mp_sys
= sys
->numRunningContexts() > 1;
696 for (int x
= 0; x
< (itLines
/INT_BITS_MAX
); x
++) {
697 if (intEnabled
[x
] & pendingInt
[x
]) {
698 for (int y
= 0; y
< INT_BITS_MAX
; y
++) {
699 uint32_t int_nm
= x
* INT_BITS_MAX
+ y
;
700 DPRINTF(GIC
, "Checking for interrupt# %d \n",int_nm
);
701 /* Set current pending int as highest int for current cpu
702 if the interrupt's priority higher than current prioirty
703 and if currrent cpu is the target (for mp configs only)
705 if ((bits(intEnabled
[x
], y
) & bits(pendingInt
[x
], y
)) &&
706 (intPriority
[int_nm
] < highest_pri
))
708 (!gem5ExtensionsEnabled
&& (cpuTarget
[int_nm
] & (1 << cpu
))) ||
709 (gem5ExtensionsEnabled
&& (cpuTarget
[int_nm
] == cpu
))
711 highest_pri
= intPriority
[int_nm
];
712 highest_int
= int_nm
;
718 cpuHighestInt
[cpu
] = highest_int
;
720 if (highest_int
== SPURIOUS_INT
)
723 /* @todo make this work for more than one cpu, need to handle 1:N, N:N
725 if (enabled
&& cpuEnabled
[cpu
] && (highest_pri
< cpuPriority
[cpu
]) &&
726 !(activeInt
[intNumToWord(highest_int
)]
727 & (1 << intNumToBit(highest_int
)))) {
729 DPRINTF(Interrupt
, "Posting interrupt %d to cpu%d\n", highest_int
,
731 postInt(cpu
, curTick() + intLatency
);
737 Pl390::updateRunPri()
739 for (int cpu
= 0; cpu
< sys
->numContexts(); cpu
++) {
740 if (!cpuEnabled
[cpu
])
742 uint8_t maxPriority
= 0xff;
743 for (int i
= 0; i
< itLines
; i
++){
745 if (((cpuSgiActive
[i
] & genSwiMask(cpu
)) ||
746 (cpuSgiActiveExt
[cpu
] & (1 << i
))) &&
747 (bankedIntPriority
[cpu
][i
] < maxPriority
))
748 maxPriority
= bankedIntPriority
[cpu
][i
];
749 } else if (i
< (SGI_MAX
+ PPI_MAX
)) {
750 if ((cpuPpiActive
[cpu
] & ( 1 << (i
- SGI_MAX
))) &&
751 (bankedIntPriority
[cpu
][i
] < maxPriority
))
752 maxPriority
= bankedIntPriority
[cpu
][i
];
755 if (activeInt
[intNumToWord(i
)] & (1 << intNumToBit(i
)))
756 if (intPriority
[i
] < maxPriority
)
757 maxPriority
= intPriority
[i
];
760 iccrpr
[cpu
] = maxPriority
;
765 Pl390::sendInt(uint32_t num
)
767 DPRINTF(Interrupt
, "Received Interupt number %d, cpuTarget %#x: \n",
768 num
, cpuTarget
[num
]);
769 if ((cpuTarget
[num
] & (cpuTarget
[num
] - 1)) && !gem5ExtensionsEnabled
)
770 panic("Multiple targets for peripheral interrupts is not supported\n");
771 pendingInt
[intNumToWord(num
)] |= 1 << intNumToBit(num
);
772 updateIntState(intNumToWord(num
));
777 Pl390::sendPPInt(uint32_t num
, uint32_t cpu
)
779 DPRINTF(Interrupt
, "Received PPI %d, cpuTarget %#x: \n",
781 cpuPpiPending
[cpu
] |= 1 << (num
- SGI_MAX
);
782 updateIntState(intNumToWord(num
));
786 Pl390::clearInt(uint32_t number
)
788 /* @todo assume edge triggered only at the moment. Nothing to do. */
792 Pl390::clearPPInt(uint32_t num
, uint32_t cpu
)
794 DPRINTF(Interrupt
, "Clearing PPI %d, cpuTarget %#x: \n",
796 cpuPpiPending
[cpu
] &= ~(1 << (num
- SGI_MAX
));
797 updateIntState(intNumToWord(num
));
801 Pl390::postInt(uint32_t cpu
, Tick when
)
803 if (!(postIntEvent
[cpu
]->scheduled()))
804 eventq
->schedule(postIntEvent
[cpu
], when
);
808 Pl390::getAddrRanges() const
810 AddrRangeList ranges
;
811 ranges
.push_back(RangeSize(distAddr
, DIST_SIZE
));
812 ranges
.push_back(RangeSize(cpuAddr
, CPU_SIZE
));
818 Pl390::serialize(CheckpointOut
&cp
) const
820 DPRINTF(Checkpoint
, "Serializing Arm GIC\n");
822 SERIALIZE_SCALAR(distAddr
);
823 SERIALIZE_SCALAR(cpuAddr
);
824 SERIALIZE_SCALAR(distPioDelay
);
825 SERIALIZE_SCALAR(cpuPioDelay
);
826 SERIALIZE_SCALAR(enabled
);
827 SERIALIZE_SCALAR(itLines
);
828 SERIALIZE_SCALAR(itLinesLog2
);
829 SERIALIZE_ARRAY(intEnabled
, INT_BITS_MAX
);
830 SERIALIZE_ARRAY(pendingInt
, INT_BITS_MAX
);
831 SERIALIZE_ARRAY(activeInt
, INT_BITS_MAX
);
832 SERIALIZE_ARRAY(iccrpr
, CPU_MAX
);
833 SERIALIZE_ARRAY(intPriority
, INT_LINES_MAX
);
834 SERIALIZE_ARRAY(cpuTarget
, INT_LINES_MAX
);
835 SERIALIZE_ARRAY(intConfig
, INT_BITS_MAX
* 2);
836 SERIALIZE_ARRAY(cpuEnabled
, CPU_MAX
);
837 SERIALIZE_ARRAY(cpuPriority
, CPU_MAX
);
838 SERIALIZE_ARRAY(cpuBpr
, CPU_MAX
);
839 SERIALIZE_ARRAY(cpuHighestInt
, CPU_MAX
);
840 SERIALIZE_ARRAY(cpuSgiActive
, SGI_MAX
);
841 SERIALIZE_ARRAY(cpuSgiPending
, SGI_MAX
);
842 SERIALIZE_ARRAY(cpuSgiActiveExt
, CPU_MAX
);
843 SERIALIZE_ARRAY(cpuSgiPendingExt
, CPU_MAX
);
844 SERIALIZE_ARRAY(cpuPpiActive
, CPU_MAX
);
845 SERIALIZE_ARRAY(cpuPpiPending
, CPU_MAX
);
846 SERIALIZE_ARRAY(*bankedIntPriority
, CPU_MAX
* (SGI_MAX
+ PPI_MAX
));
847 SERIALIZE_SCALAR(irqEnable
);
848 Tick interrupt_time
[CPU_MAX
];
849 for (uint32_t cpu
= 0; cpu
< CPU_MAX
; cpu
++) {
850 interrupt_time
[cpu
] = 0;
851 if (postIntEvent
[cpu
]->scheduled()) {
852 interrupt_time
[cpu
] = postIntEvent
[cpu
]->when();
855 SERIALIZE_ARRAY(interrupt_time
, CPU_MAX
);
856 SERIALIZE_SCALAR(gem5ExtensionsEnabled
);
860 Pl390::unserialize(CheckpointIn
&cp
)
862 DPRINTF(Checkpoint
, "Unserializing Arm GIC\n");
864 UNSERIALIZE_SCALAR(distAddr
);
865 UNSERIALIZE_SCALAR(cpuAddr
);
866 UNSERIALIZE_SCALAR(distPioDelay
);
867 UNSERIALIZE_SCALAR(cpuPioDelay
);
868 UNSERIALIZE_SCALAR(enabled
);
869 UNSERIALIZE_SCALAR(itLines
);
870 UNSERIALIZE_SCALAR(itLinesLog2
);
871 UNSERIALIZE_ARRAY(intEnabled
, INT_BITS_MAX
);
872 UNSERIALIZE_ARRAY(pendingInt
, INT_BITS_MAX
);
873 UNSERIALIZE_ARRAY(activeInt
, INT_BITS_MAX
);
874 UNSERIALIZE_ARRAY(iccrpr
, CPU_MAX
);
875 UNSERIALIZE_ARRAY(intPriority
, INT_LINES_MAX
);
876 UNSERIALIZE_ARRAY(cpuTarget
, INT_LINES_MAX
);
877 UNSERIALIZE_ARRAY(intConfig
, INT_BITS_MAX
* 2);
878 UNSERIALIZE_ARRAY(cpuEnabled
, CPU_MAX
);
879 UNSERIALIZE_ARRAY(cpuPriority
, CPU_MAX
);
880 UNSERIALIZE_ARRAY(cpuBpr
, CPU_MAX
);
881 UNSERIALIZE_ARRAY(cpuHighestInt
, CPU_MAX
);
882 UNSERIALIZE_ARRAY(cpuSgiActive
, SGI_MAX
);
883 UNSERIALIZE_ARRAY(cpuSgiPending
, SGI_MAX
);
884 UNSERIALIZE_ARRAY(cpuSgiActiveExt
, CPU_MAX
);
885 UNSERIALIZE_ARRAY(cpuSgiPendingExt
, CPU_MAX
);
886 UNSERIALIZE_ARRAY(cpuPpiActive
, CPU_MAX
);
887 UNSERIALIZE_ARRAY(cpuPpiPending
, CPU_MAX
);
888 UNSERIALIZE_ARRAY(*bankedIntPriority
, CPU_MAX
* (SGI_MAX
+ PPI_MAX
));
889 UNSERIALIZE_SCALAR(irqEnable
);
891 Tick interrupt_time
[CPU_MAX
];
892 UNSERIALIZE_ARRAY(interrupt_time
, CPU_MAX
);
894 for (uint32_t cpu
= 0; cpu
< CPU_MAX
; cpu
++) {
895 if (interrupt_time
[cpu
])
896 schedule(postIntEvent
[cpu
], interrupt_time
[cpu
]);
898 if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled
))
899 gem5ExtensionsEnabled
= false;
903 Pl390Params::create()
905 return new Pl390(this);
908 /* Functions for debugging and testing */
910 Pl390::driveSPI(unsigned int spiVect
)
912 DPRINTF(GIC
, "Received SPI Vector:%x Enable: %d\n", spiVect
, irqEnable
);
913 pendingInt
[1] |= spiVect
;
914 if (irqEnable
&& enabled
) {
920 Pl390::driveIrqEn( bool state
)
923 DPRINTF(GIC
, " Enabling Irq\n");
928 Pl390::driveLegIRQ(bool state
)
930 if (irqEnable
&& !(!enabled
&& cpuEnabled
[0])) {
932 DPRINTF(GIC
, "Driving Legacy Irq\n");
933 platform
->intrctrl
->post(0, ArmISA::INT_IRQ
, 0);
935 else platform
->intrctrl
->clear(0, ArmISA::INT_IRQ
, 0);
940 Pl390::driveLegFIQ(bool state
)
943 platform
->intrctrl
->post(0, ArmISA::INT_FIQ
, 0);
944 else platform
->intrctrl
->clear(0, ArmISA::INT_FIQ
, 0);