cpu: remove unnecessary data ptr from O3 internal read() funcs
[gem5.git] / src / dev / arm / gic_pl390.cc
1 /*
2 * Copyright (c) 2010, 2013, 2015 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 iccrpr[x] = 0xff;
64 cpuEnabled[x] = false;
65 cpuPriority[x] = 0xff;
66 cpuBpr[x] = 0;
67 // Initialize cpu highest int
68 cpuHighestInt[x] = SPURIOUS_INT;
69 postIntEvent[x] = new PostIntEvent(x, p->platform);
70 }
71 DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
72 cpuEnabled[1]);
73
74 for (int x = 0; x < INT_BITS_MAX; x++) {
75 intEnabled[x] = 0;
76 pendingInt[x] = 0;
77 activeInt[x] = 0;
78 }
79
80 for (int x = 0; x < INT_LINES_MAX; x++) {
81 intPriority[x] = 0;
82 cpuTarget[x] = 0;
83 }
84
85 for (int x = 0; x < INT_BITS_MAX*2; x++) {
86 intConfig[x] = 0;
87 }
88
89 for (int x = 0; x < SGI_MAX; x++) {
90 cpuSgiActive[x] = 0;
91 cpuSgiPending[x] = 0;
92 }
93 for (int x = 0; x < CPU_MAX; x++) {
94 cpuPpiActive[x] = 0;
95 cpuPpiPending[x] = 0;
96 cpuSgiActiveExt[x] = 0;
97 cpuSgiPendingExt[x] = 0;
98 }
99
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;
103 }
104 }
105
106 gem5ExtensionsEnabled = false;
107 }
108
109 Tick
110 Pl390::read(PacketPtr pkt)
111 {
112
113 Addr addr = pkt->getAddr();
114
115 if (addr >= distAddr && addr < distAddr + DIST_SIZE)
116 return readDistributor(pkt);
117 else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
118 return readCpu(pkt);
119 else
120 panic("Read to unknown address %#x\n", pkt->getAddr());
121 }
122
123
124 Tick
125 Pl390::write(PacketPtr pkt)
126 {
127
128 Addr addr = pkt->getAddr();
129
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);
134 else
135 panic("Write to unknown address %#x\n", pkt->getAddr());
136 }
137
138 Tick
139 Pl390::readDistributor(PacketPtr pkt)
140 {
141 Addr daddr = pkt->getAddr() - distAddr;
142
143 ContextID ctx_id = pkt->req->contextId();
144
145 DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
146
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]);
150 goto done;
151 }
152
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]);
156 goto done;
157 }
158
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]);
162 goto done;
163 }
164
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]);
168 goto done;
169 }
170
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]);
174 goto done;
175 }
176
177 if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
178 Addr int_num;
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);
182
183 uint8_t* int_p;
184 if (int_num < (SGI_MAX + PPI_MAX))
185 int_p = bankedIntPriority[ctx_id];
186 else
187 int_p = intPriority;
188
189 switch (pkt->getSize()) {
190 case 1:
191 pkt->set<uint8_t>(int_p[int_num]);
192 break;
193 case 2:
194 assert((int_num + 1) < INT_LINES_MAX);
195 pkt->set<uint16_t>(int_p[int_num] |
196 int_p[int_num+1] << 8);
197 break;
198 case 4:
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);
204 break;
205 default:
206 panic("Invalid size while reading priority regs in GIC: %d\n",
207 pkt->getSize());
208 }
209 goto done;
210 }
211
212 if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
213 Addr int_num;
214 int_num = (daddr-ICDIPTR_ST) ;
215 DPRINTF(GIC, "Reading processor target register for int# %#x \n",
216 int_num);
217 assert(int_num < INT_LINES_MAX);
218
219 // First 31 interrupts only target single processor (SGI)
220 if (int_num > 31) {
221 if (pkt->getSize() == 1) {
222 pkt->set<uint8_t>(cpuTarget[int_num]);
223 } else {
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) ;
230 }
231 } else {
232 assert(ctx_id < sys->numRunningContexts());
233 uint32_t ctx_mask;
234 if (gem5ExtensionsEnabled) {
235 ctx_mask = ctx_id;
236 } else {
237 // convert the CPU id number into a bit mask
238 ctx_mask = power(2, ctx_id);
239 }
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);
244 }
245 goto done;
246 }
247
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
252 */
253 pkt->set<uint32_t>(intConfig[(daddr-ICDICFR_ST)>>2]);
254 goto done;
255 }
256
257 switch(daddr) {
258 case ICDDCR:
259 pkt->set<uint32_t>(enabled);
260 break;
261 case ICDICTR:
262 uint32_t tmp;
263 tmp = ((sys->numRunningContexts() - 1) << 5) |
264 (itLines/INT_BITS_MAX -1) |
265 0x100;
266 /* The 0x100 is a made-up flag to show that gem5 extensions
267 * are available,
268 * write 0x200 to this register to enable it.
269 */
270 pkt->set<uint32_t>(tmp);
271 break;
272 default:
273 panic("Tried to read Gic distributor at offset %#x\n", daddr);
274 break;
275 }
276 done:
277 pkt->makeAtomicResponse();
278 return distPioDelay;
279 }
280
281 Tick
282 Pl390::readCpu(PacketPtr pkt)
283 {
284 Addr daddr = pkt->getAddr() - cpuAddr;
285
286 assert(pkt->req->hasContextId());
287 ContextID ctx_id = pkt->req->contextId();
288 assert(ctx_id < sys->numRunningContexts());
289
290 DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
291 ctx_id);
292
293 switch(daddr) {
294 case ICCIIDR:
295 pkt->set<uint32_t>(0);
296 break;
297 case ICCICR:
298 pkt->set<uint32_t>(cpuEnabled[ctx_id]);
299 break;
300 case ICCPMR:
301 pkt->set<uint32_t>(cpuPriority[ctx_id]);
302 break;
303 case ICCBPR:
304 pkt->set<uint32_t>(cpuBpr[ctx_id]);
305 break;
306 case ICCIAR:
307 if (enabled && cpuEnabled[ctx_id]) {
308 int active_int = cpuHighestInt[ctx_id];
309 IAR iar = 0;
310 iar.ack_id = active_int;
311 iar.cpu_id = 0;
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",
317 active_int);
318 for (int x = 0; x < sys->numRunningContexts(); x++) {
319 // See which CPU generated the interrupt
320 uint8_t cpugen =
321 bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
322 if (cpugen & (1 << ctx_id)) {
323 iar.cpu_id = x;
324 break;
325 }
326 }
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;
330 } else {
331 uint64_t sgi_num = ULL(1) << iar.ack_id;
332 cpuSgiActiveExt[ctx_id] |= sgi_num;
333 cpuSgiPendingExt[ctx_id] &= ~sgi_num;
334 }
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;
338 updateRunPri();
339 cpuPpiPending[ctx_id] &= ~int_num;
340
341 } else {
342 uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
343 activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
344 updateRunPri();
345 pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
346 }
347
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;
351 updateIntState(-1);
352 pkt->set<uint32_t>(iar);
353 platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
354 } else {
355 pkt->set<uint32_t>(SPURIOUS_INT);
356 }
357
358 break;
359 case ICCRPR:
360 pkt->set<uint32_t>(iccrpr[0]);
361 break;
362 case ICCHPIR:
363 pkt->set<uint32_t>(0);
364 panic("Need to implement HPIR");
365 break;
366 default:
367 panic("Tried to read Gic cpu at offset %#x\n", daddr);
368 break;
369 }
370 pkt->makeAtomicResponse();
371 return cpuPioDelay;
372 }
373
374 Tick
375 Pl390::writeDistributor(PacketPtr pkt)
376 {
377 Addr daddr = pkt->getAddr() - distAddr;
378
379 assert(pkt->req->hasContextId());
380 ContextID ctx_id = pkt->req->contextId();
381
382 uint32_t pkt_data M5_VAR_USED;
383 switch (pkt->getSize())
384 {
385 case 1:
386 pkt_data = pkt->get<uint8_t>();
387 break;
388 case 2:
389 pkt_data = pkt->get<uint16_t>();
390 break;
391 case 4:
392 pkt_data = pkt->get<uint32_t>();
393 break;
394 default:
395 panic("Invalid size when writing to priority regs in Gic: %d\n",
396 pkt->getSize());
397 }
398
399 DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
400 daddr, pkt->getSize(), pkt_data);
401
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>();
405 goto done;
406 }
407
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>();
411 goto done;
412 }
413
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);
419 goto done;
420 }
421
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);
427 goto done;
428 }
429
430 if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
431 Addr int_num = daddr - ICDIPR_ST;
432 assert(int_num < INT_LINES_MAX);
433 uint8_t* int_p;
434 if (int_num < (SGI_MAX + PPI_MAX))
435 int_p = bankedIntPriority[ctx_id];
436 else
437 int_p = intPriority;
438 uint32_t tmp;
439 switch(pkt->getSize()) {
440 case 1:
441 tmp = pkt->get<uint8_t>();
442 int_p[int_num] = bits(tmp, 7, 0);
443 break;
444 case 2:
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);
448 break;
449 case 4:
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);
455 break;
456 default:
457 panic("Invalid size when writing to priority regs in Gic: %d\n",
458 pkt->getSize());
459 }
460
461 updateIntState(-1);
462 updateRunPri();
463 goto done;
464 }
465
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;
474 } else {
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);
482 }
483 updateIntState((daddr-ICDIPTR_ST)>>2);
484 }
485 goto done;
486 }
487
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");
493 goto done;
494 }
495
496 switch(daddr) {
497 case ICDDCR:
498 enabled = pkt->get<uint32_t>();
499 DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
500 break;
501 case ICDICTR:
502 /* 0x200 is a made-up flag to enable gem5 extension functionality.
503 * This reg is not normally written.
504 */
505 gem5ExtensionsEnabled = !!(pkt->get<uint32_t>() & 0x200);
506 DPRINTF(GIC, "gem5 extensions %s\n", gem5ExtensionsEnabled ? "enabled" : "disabled");
507 break;
508 case ICDSGIR:
509 softInt(ctx_id, pkt->get<uint32_t>());
510 break;
511 default:
512 panic("Tried to write Gic distributor at offset %#x\n", daddr);
513 break;
514 }
515
516 done:
517 pkt->makeAtomicResponse();
518 return distPioDelay;
519 }
520
521 Tick
522 Pl390::writeCpu(PacketPtr pkt)
523 {
524 Addr daddr = pkt->getAddr() - cpuAddr;
525
526 assert(pkt->req->hasContextId());
527 ContextID ctx_id = pkt->req->contextId();
528 IAR iar;
529
530 DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
531 ctx_id, daddr, pkt->get<uint32_t>());
532
533 switch(daddr) {
534 case ICCICR:
535 cpuEnabled[ctx_id] = pkt->get<uint32_t>();
536 break;
537 case ICCPMR:
538 cpuPriority[ctx_id] = pkt->get<uint32_t>();
539 break;
540 case ICCBPR:
541 cpuBpr[ctx_id] = pkt->get<uint32_t>();
542 break;
543 case ICCEOIR:
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);
553 else
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;
561 } else {
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;
567 }
568 updateRunPri();
569 DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
570 ctx_id, iar.ack_id, iar.cpu_id);
571 break;
572 default:
573 panic("Tried to write Gic cpu at offset %#x\n", daddr);
574 break;
575 }
576 if (cpuEnabled[ctx_id]) updateIntState(-1);
577 pkt->makeAtomicResponse();
578 return cpuPioDelay;
579 }
580
581 void
582 Pl390::softInt(ContextID ctx_id, SWI swi)
583 {
584 if (gem5ExtensionsEnabled) {
585 switch (swi.list_type) {
586 case 0: {
587 // interrupt cpus specified
588 int dest = swi.cpu_list;
589 DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
590 ctx_id, dest);
591 if (cpuEnabled[dest]) {
592 cpuSgiPendingExt[dest] |= (1 << swi.sgi_id);
593 DPRINTF(IPI, "SGI[%d]=%#x\n", dest,
594 cpuSgiPendingExt[dest]);
595 }
596 } break;
597 case 1: {
598 // interrupt all
599 for (int i = 0; i < sys->numContexts(); i++) {
600 DPRINTF(IPI, "Processing CPU %d\n", i);
601 if (!cpuEnabled[i])
602 continue;
603 cpuSgiPendingExt[i] |= 1 << swi.sgi_id;
604 DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id,
605 cpuSgiPendingExt[i]);
606 }
607 } break;
608 case 2: {
609 // Interrupt requesting cpu only
610 DPRINTF(IPI, "Generating softIRQ from CPU %d for CPU %d\n",
611 ctx_id, ctx_id);
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]);
616 }
617 } break;
618 }
619 } else {
620 switch (swi.list_type) {
621 case 1:
622 // interrupt all
623 uint8_t cpu_list;
624 cpu_list = 0;
625 for (int x = 0; x < sys->numContexts(); x++)
626 cpu_list |= cpuEnabled[x] ? 1 << x : 0;
627 swi.cpu_list = cpu_list;
628 break;
629 case 2:
630 // interrupt requesting cpu only
631 swi.cpu_list = 1 << ctx_id;
632 break;
633 // else interrupt cpus specified
634 }
635
636 DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id,
637 swi.cpu_list);
638 for (int i = 0; i < sys->numContexts(); i++) {
639 DPRINTF(IPI, "Processing CPU %d\n", i);
640 if (!cpuEnabled[i])
641 continue;
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]);
646 }
647 }
648 updateIntState(-1);
649 }
650
651 uint64_t
652 Pl390::genSwiMask(int cpu)
653 {
654 if (cpu > sys->numContexts())
655 panic("Invalid CPU ID\n");
656 return ULL(0x0101010101010101) << cpu;
657 }
658
659 void
660 Pl390::updateIntState(int hint)
661 {
662 for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
663 if (!cpuEnabled[cpu])
664 continue;
665
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];
670
671 // Check SGIs
672 for (int swi = 0; swi < SGI_MAX; swi++) {
673 if (!cpuSgiPending[swi] && !cpuSgiPendingExt[cpu])
674 continue;
675 if ((cpuSgiPending[swi] & genSwiMask(cpu)) ||
676 (cpuSgiPendingExt[cpu] & (1 << swi)))
677 if (highest_pri > bankedIntPriority[cpu][swi]) {
678 highest_pri = bankedIntPriority[cpu][swi];
679 highest_int = swi;
680 }
681 }
682
683 // Check PPIs
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;
690 }
691 }
692 }
693
694 bool mp_sys = sys->numRunningContexts() > 1;
695 // Check other ints
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)
704 */
705 if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
706 (intPriority[int_nm] < highest_pri))
707 if ( (!mp_sys) ||
708 (!gem5ExtensionsEnabled && (cpuTarget[int_nm] & (1 << cpu))) ||
709 (gem5ExtensionsEnabled && (cpuTarget[int_nm] == cpu))
710 ) {
711 highest_pri = intPriority[int_nm];
712 highest_int = int_nm;
713 }
714 }
715 }
716 }
717
718 cpuHighestInt[cpu] = highest_int;
719
720 if (highest_int == SPURIOUS_INT)
721 continue;
722
723 /* @todo make this work for more than one cpu, need to handle 1:N, N:N
724 * models */
725 if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
726 !(activeInt[intNumToWord(highest_int)]
727 & (1 << intNumToBit(highest_int)))) {
728
729 DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
730 cpu);
731 postInt(cpu, curTick() + intLatency);
732 }
733 }
734 }
735
736 void
737 Pl390::updateRunPri()
738 {
739 for (int cpu = 0; cpu < sys->numContexts(); cpu++) {
740 if (!cpuEnabled[cpu])
741 continue;
742 uint8_t maxPriority = 0xff;
743 for (int i = 0; i < itLines; i++){
744 if (i < SGI_MAX) {
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];
753
754 } else {
755 if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
756 if (intPriority[i] < maxPriority)
757 maxPriority = intPriority[i];
758 }
759 }
760 iccrpr[cpu] = maxPriority;
761 }
762 }
763
764 void
765 Pl390::sendInt(uint32_t num)
766 {
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));
773
774 }
775
776 void
777 Pl390::sendPPInt(uint32_t num, uint32_t cpu)
778 {
779 DPRINTF(Interrupt, "Received PPI %d, cpuTarget %#x: \n",
780 num, cpu);
781 cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
782 updateIntState(intNumToWord(num));
783 }
784
785 void
786 Pl390::clearInt(uint32_t number)
787 {
788 /* @todo assume edge triggered only at the moment. Nothing to do. */
789 }
790
791 void
792 Pl390::clearPPInt(uint32_t num, uint32_t cpu)
793 {
794 DPRINTF(Interrupt, "Clearing PPI %d, cpuTarget %#x: \n",
795 num, cpu);
796 cpuPpiPending[cpu] &= ~(1 << (num - SGI_MAX));
797 updateIntState(intNumToWord(num));
798 }
799
800 void
801 Pl390::postInt(uint32_t cpu, Tick when)
802 {
803 if (!(postIntEvent[cpu]->scheduled()))
804 eventq->schedule(postIntEvent[cpu], when);
805 }
806
807 AddrRangeList
808 Pl390::getAddrRanges() const
809 {
810 AddrRangeList ranges;
811 ranges.push_back(RangeSize(distAddr, DIST_SIZE));
812 ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
813 return ranges;
814 }
815
816
817 void
818 Pl390::serialize(CheckpointOut &cp) const
819 {
820 DPRINTF(Checkpoint, "Serializing Arm GIC\n");
821
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();
853 }
854 }
855 SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
856 SERIALIZE_SCALAR(gem5ExtensionsEnabled);
857 }
858
859 void
860 Pl390::unserialize(CheckpointIn &cp)
861 {
862 DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
863
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);
890
891 Tick interrupt_time[CPU_MAX];
892 UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
893
894 for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
895 if (interrupt_time[cpu])
896 schedule(postIntEvent[cpu], interrupt_time[cpu]);
897 }
898 if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
899 gem5ExtensionsEnabled = false;
900 }
901
902 Pl390 *
903 Pl390Params::create()
904 {
905 return new Pl390(this);
906 }
907
908 /* Functions for debugging and testing */
909 void
910 Pl390::driveSPI(unsigned int spiVect)
911 {
912 DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
913 pendingInt[1] |= spiVect;
914 if (irqEnable && enabled) {
915 updateIntState(-1);
916 }
917 }
918
919 void
920 Pl390::driveIrqEn( bool state)
921 {
922 irqEnable = state;
923 DPRINTF(GIC, " Enabling Irq\n");
924 updateIntState(-1);
925 }
926
927 void
928 Pl390::driveLegIRQ(bool state)
929 {
930 if (irqEnable && !(!enabled && cpuEnabled[0])) {
931 if (state) {
932 DPRINTF(GIC, "Driving Legacy Irq\n");
933 platform->intrctrl->post(0, ArmISA::INT_IRQ, 0);
934 }
935 else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
936 }
937 }
938
939 void
940 Pl390::driveLegFIQ(bool state)
941 {
942 if (state)
943 platform->intrctrl->post(0, ArmISA::INT_FIQ, 0);
944 else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0);
945 }