gic_v3_distributor.cc (14230:94c9f25c59ae) gic_v3_distributor.cc (14231:222f6512335e)
1/*
2 * Copyright (c) 2019 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

--- 624 unchanged lines hidden (view full) ---

633
634 if (pending) {
635 DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
636 "int_id %d (SPI) pending bit set\n", int_id);
637 irqPending[int_id] = true;
638 }
639 }
640
1/*
2 * Copyright (c) 2019 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

--- 624 unchanged lines hidden (view full) ---

633
634 if (pending) {
635 DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
636 "int_id %d (SPI) pending bit set\n", int_id);
637 irqPending[int_id] = true;
638 }
639 }
640
641 updateAndInformCPUInterfaces();
641 update();
642 return;
643 } else if (GICD_ICPENDR.contains(addr)) {
644 // Interrupt Clear-Pending Registers
645 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
646
647 if (isNotSPI(first_intid)) {
648 return;
649 }

--- 8 unchanged lines hidden (view full) ---

658 continue;
659 }
660 }
661
662 bool clear = data & (1 << i) ? 1 : 0;
663
664 if (clear) {
665 irqPending[int_id] = false;
642 return;
643 } else if (GICD_ICPENDR.contains(addr)) {
644 // Interrupt Clear-Pending Registers
645 int first_intid = (addr - GICD_ICPENDR.start()) * 8;
646
647 if (isNotSPI(first_intid)) {
648 return;
649 }

--- 8 unchanged lines hidden (view full) ---

658 continue;
659 }
660 }
661
662 bool clear = data & (1 << i) ? 1 : 0;
663
664 if (clear) {
665 irqPending[int_id] = false;
666 clearIrqCpuInterface(int_id);
666 }
667 }
668
667 }
668 }
669
669 updateAndInformCPUInterfaces();
670 update();
670 return;
671 } else if (GICD_ISACTIVER.contains(addr)) {
672 // Interrupt Set-Active Registers
673 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
674
675 if (isNotSPI(first_intid)) {
676 return;
677 }

--- 264 unchanged lines hidden (view full) ---

942void
943Gicv3Distributor::sendInt(uint32_t int_id)
944{
945 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
946 panic_if(int_id > itLines, "Invalid SPI!");
947 irqPending[int_id] = true;
948 DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
949 "int_id %d (SPI) pending bit set\n", int_id);
671 return;
672 } else if (GICD_ISACTIVER.contains(addr)) {
673 // Interrupt Set-Active Registers
674 int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
675
676 if (isNotSPI(first_intid)) {
677 return;
678 }

--- 264 unchanged lines hidden (view full) ---

943void
944Gicv3Distributor::sendInt(uint32_t int_id)
945{
946 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
947 panic_if(int_id > itLines, "Invalid SPI!");
948 irqPending[int_id] = true;
949 DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
950 "int_id %d (SPI) pending bit set\n", int_id);
950 updateAndInformCPUInterfaces();
951 update();
951}
952
953void
954Gicv3Distributor::deassertSPI(uint32_t int_id)
955{
956 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
957 panic_if(int_id > itLines, "Invalid SPI!");
958 irqPending[int_id] = false;
952}
953
954void
955Gicv3Distributor::deassertSPI(uint32_t int_id)
956{
957 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
958 panic_if(int_id > itLines, "Invalid SPI!");
959 irqPending[int_id] = false;
959 updateAndInformCPUInterfaces();
960 clearIrqCpuInterface(int_id);
961
962 update();
960}
961
963}
964
962void
963Gicv3Distributor::updateAndInformCPUInterfaces()
965Gicv3CPUInterface*
966Gicv3Distributor::route(uint32_t int_id)
964{
967{
965 update();
968 IROUTER affinity_routing = irqAffinityRouting[int_id];
969 Gicv3Redistributor * target_redistributor = nullptr;
966
970
967 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
968 gic->getCPUInterface(i)->update();
971 const Gicv3::GroupId int_group = getIntGroup(int_id);
972
973 if (affinity_routing.IRM) {
974 // Interrupts routed to any PE defined as a participating node
975 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
976 Gicv3Redistributor * redistributor_i =
977 gic->getRedistributor(i);
978
979 if (redistributor_i->
980 canBeSelectedFor1toNInterrupt(int_group)) {
981 target_redistributor = redistributor_i;
982 break;
983 }
984 }
985 } else {
986 uint32_t affinity = (affinity_routing.Aff3 << 24) |
987 (affinity_routing.Aff2 << 16) |
988 (affinity_routing.Aff1 << 8) |
989 (affinity_routing.Aff0 << 0);
990 target_redistributor =
991 gic->getRedistributorByAffinity(affinity);
969 }
992 }
993
994 if (!target_redistributor) {
995 // Interrrupts targeting not present cpus must remain pending
996 return nullptr;
997 } else {
998 return target_redistributor->getCPUInterface();
999 }
970}
971
972void
1000}
1001
1002void
973Gicv3Distributor::fullUpdate()
1003Gicv3Distributor::clearIrqCpuInterface(uint32_t int_id)
974{
1004{
975 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
976 Gicv3CPUInterface * cpu_interface_i = gic->getCPUInterface(i);
977 cpu_interface_i->hppi.prio = 0xff;
978 }
979
980 update();
981
982 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
983 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
984 redistributor_i->update();
985 }
1005 auto cpu_interface = route(int_id);
1006 if (cpu_interface)
1007 cpu_interface->hppi.prio = 0xff;
986}
987
988void
989Gicv3Distributor::update()
990{
1008}
1009
1010void
1011Gicv3Distributor::update()
1012{
991 std::vector<bool> new_hppi(gic->getSystem()->numContexts(), false);
992
993 // Find the highest priority pending SPI
994 for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
995 int_id++) {
996 Gicv3::GroupId int_group = getIntGroup(int_id);
997 bool group_enabled = groupEnabled(int_group);
998
999 if (irqPending[int_id] && irqEnabled[int_id] &&
1000 !irqActive[int_id] && group_enabled) {
1013 // Find the highest priority pending SPI
1014 for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
1015 int_id++) {
1016 Gicv3::GroupId int_group = getIntGroup(int_id);
1017 bool group_enabled = groupEnabled(int_group);
1018
1019 if (irqPending[int_id] && irqEnabled[int_id] &&
1020 !irqActive[int_id] && group_enabled) {
1001 IROUTER affinity_routing = irqAffinityRouting[int_id];
1002 Gicv3Redistributor * target_redistributor = nullptr;
1003
1021
1004 if (affinity_routing.IRM) {
1005 // Interrupts routed to any PE defined as a participating node
1006 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1007 Gicv3Redistributor * redistributor_i =
1008 gic->getRedistributor(i);
1022 // Find the cpu interface where to route the interrupt
1023 Gicv3CPUInterface *target_cpu_interface = route(int_id);
1009
1024
1010 if (redistributor_i->
1011 canBeSelectedFor1toNInterrupt(int_group)) {
1012 target_redistributor = redistributor_i;
1013 break;
1014 }
1015 }
1016 } else {
1017 uint32_t affinity = (affinity_routing.Aff3 << 24) |
1018 (affinity_routing.Aff3 << 16) |
1019 (affinity_routing.Aff1 << 8) |
1020 (affinity_routing.Aff0 << 0);
1021 target_redistributor =
1022 gic->getRedistributorByAffinity(affinity);
1023 }
1025 // Invalid routing
1026 if (!target_cpu_interface) continue;
1024
1027
1025 if (!target_redistributor) {
1026 // Interrrupts targeting not present cpus must remain pending
1027 return;
1028 }
1029
1030 Gicv3CPUInterface * target_cpu_interface =
1031 target_redistributor->getCPUInterface();
1032 uint32_t target_cpu = target_redistributor->cpuId;
1033
1034 if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1028 if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1035 /*
1036 * Multiple pending ints with same priority.
1037 * Implementation choice which one to signal.
1038 * Our implementation selects the one with the lower id.
1039 */
1040 (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1041 int_id < target_cpu_interface->hppi.intid)) {
1029 (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1030 int_id < target_cpu_interface->hppi.intid)) {
1031
1042 target_cpu_interface->hppi.intid = int_id;
1043 target_cpu_interface->hppi.prio = irqPriority[int_id];
1044 target_cpu_interface->hppi.group = int_group;
1032 target_cpu_interface->hppi.intid = int_id;
1033 target_cpu_interface->hppi.prio = irqPriority[int_id];
1034 target_cpu_interface->hppi.group = int_group;
1045 new_hppi[target_cpu] = true;
1046 }
1047 }
1048 }
1049
1035 }
1036 }
1037 }
1038
1039 // Update all redistributors
1050 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1040 for (int i = 0; i < gic->getSystem()->numContexts(); i++) {
1051 Gicv3Redistributor * redistributor_i = gic->getRedistributor(i);
1052 Gicv3CPUInterface * cpu_interface_i =
1053 redistributor_i->getCPUInterface();
1054
1055 if (!new_hppi[i] && cpu_interface_i->hppi.prio != 0xff &&
1056 cpu_interface_i->hppi.intid >= (Gicv3::SGI_MAX + Gicv3::PPI_MAX) &&
1057 cpu_interface_i->hppi.intid < Gicv3::INTID_SECURE) {
1058 fullUpdate();
1059 }
1041 gic->getRedistributor(i)->update();
1060 }
1061}
1062
1063Gicv3::IntStatus
1064Gicv3Distributor::intStatus(uint32_t int_id) const
1065{
1066 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1067 panic_if(int_id > itLines, "Invalid SPI!");

--- 91 unchanged lines hidden ---
1042 }
1043}
1044
1045Gicv3::IntStatus
1046Gicv3Distributor::intStatus(uint32_t int_id) const
1047{
1048 panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1049 panic_if(int_id > itLines, "Invalid SPI!");

--- 91 unchanged lines hidden ---