hw: implement multi-processor support for rpi3

Fix #3522
This commit is contained in:
Stefan Kalkowski 2019-10-10 14:39:49 +02:00 committed by Christian Helmuth
parent 1cbd77c806
commit 87a6368ba1
6 changed files with 123 additions and 38 deletions

View File

@ -8,4 +8,6 @@ SRC_S += bootstrap/spec/arm_64/crt0.s
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
NR_OF_CPUS = 4
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc

View File

@ -2,17 +2,17 @@ INC_DIR += $(REP_DIR)/src/core/spec/rpi3
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
# add C++ sources
SRC_CC += platform_services.cc
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/cpu_up.cc
SRC_CC += kernel/lock.cc
SRC_CC += spec/arm_v8/cpu.cc
SRC_CC += spec/arm_v8/kernel/thread.cc
SRC_CC += spec/arm_v8/kernel/cpu.cc
SRC_CC += spec/arm/platform_support.cc
SRC_CC += platform_services.cc
SRC_CC += spec/64bit/memory_map.cc
SRC_CC += spec/arm/bcm2837_pic.cc
SRC_CC += spec/arm/generic_timer.cc
SRC_CC += spec/64bit/memory_map.cc
SRC_CC += spec/arm/kernel/lock.cc
SRC_CC += spec/arm/platform_support.cc
SRC_CC += spec/arm_v8/cpu.cc
SRC_CC += spec/arm_v8/kernel/cpu.cc
SRC_CC += spec/arm_v8/kernel/thread.cc
#add assembly sources
SRC_S += spec/arm_v8/exception_vector.s
@ -20,5 +20,7 @@ SRC_S += spec/arm_v8/crt0.s
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
NR_OF_CPUS = 4
# include less specific configuration
include $(REP_DIR)/lib/mk/core-hw.inc

View File

@ -23,7 +23,7 @@ namespace Board {
struct Cpu : Hw::Arm_64_cpu
{
static void wake_up_all_cpus(void*) {}
static void wake_up_all_cpus(void*);
};
struct Pic { }; /* dummy object */

View File

@ -26,3 +26,12 @@ Bootstrap::Platform::Board::Board()
::Board::LOCAL_IRQ_CONTROLLER_SIZE },
Memory_region { ::Board::IRQ_CONTROLLER_BASE,
::Board::IRQ_CONTROLLER_SIZE }) {}
extern unsigned int _crt0_qemu_start_secondary_cpus;
void Board::Cpu::wake_up_all_cpus(void *)
{
_crt0_qemu_start_secondary_cpus = 1;
asm volatile("dsb #0; sev");
}

View File

@ -12,6 +12,7 @@
*/
#include <board.h>
#include <cpu.h>
#include <platform.h>
@ -21,41 +22,109 @@ Board::Pic::Pic()
bool Board::Pic::take_request(unsigned & irq)
{
Core0_irq_source::access_t src = read<Core0_irq_source>();
unsigned cpu = Genode::Cpu::executing_id();
Core_irq_source<0>::access_t src = 0;
switch (cpu) {
case 0: src = read<Core_irq_source<0>>(); break;
case 1: src = read<Core_irq_source<1>>(); break;
case 2: src = read<Core_irq_source<2>>(); break;
case 3: src = read<Core_irq_source<3>>(); break;
}
if ((1 << TIMER_IRQ) & src) {
irq = TIMER_IRQ;
return true;
}
if (0xf0 & src) {
irq = IPI;
switch (cpu) {
case 0: write<Core_mailbox_clear<0>>(1); break;
case 1: write<Core_mailbox_clear<1>>(1); break;
case 2: write<Core_mailbox_clear<2>>(1); break;
case 3: write<Core_mailbox_clear<3>>(1); break;
}
return true;
}
return false;
}
void Board::Pic::mask() { }
void Board::Pic::_timer_irq(unsigned cpu, bool enable)
{
unsigned v = enable ? 1 : 0;
switch (cpu) {
case 0:
write<Core_timer_irq_control<0>::Cnt_p_ns_irq>(v);
return;
case 1:
write<Core_timer_irq_control<1>::Cnt_p_ns_irq>(v);
return;
case 2:
write<Core_timer_irq_control<2>::Cnt_p_ns_irq>(v);
return;
case 3:
write<Core_timer_irq_control<3>::Cnt_p_ns_irq>(v);
return;
default: ;
}
}
void Board::Pic::_ipi(unsigned cpu, bool enable)
{
unsigned v = enable ? 1 : 0;
switch (cpu) {
case 0:
write<Core_mailbox_irq_control<0>>(v);
return;
case 1:
write<Core_mailbox_irq_control<1>>(v);
return;
case 2:
write<Core_mailbox_irq_control<2>>(v);
return;
case 3:
write<Core_mailbox_irq_control<3>>(v);
return;
default: ;
}
}
void Board::Pic::unmask(unsigned const i, unsigned cpu)
{
if (cpu > 0)
Genode::raw("multi-core irq controller not implemented yet");
if (i == TIMER_IRQ) {
write<Core0_timer_irq_control::Cnt_p_ns_irq>(1);
return;
switch (i) {
case TIMER_IRQ: _timer_irq(cpu, true); return;
case IPI: _ipi(cpu, true); return;
}
Genode::raw("irq of peripherals != timer not implemented yet!");
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
}
void Board::Pic::mask(unsigned const i)
{
if (i == TIMER_IRQ) {
write<Core0_timer_irq_control::Cnt_p_ns_irq>(0);
return;
unsigned cpu = Genode::Cpu::executing_id();
switch (i) {
case TIMER_IRQ: _timer_irq(cpu, false); return;
case IPI: _ipi(cpu, false); return;
}
Genode::raw("irq of peripherals != timer not implemented yet!");
Genode::raw("irq of peripherals != timer not implemented yet! (irq=", i, ")");
}
void Board::Pic::irq_mode(unsigned, unsigned, unsigned) { }
void Board::Pic::send_ipi(unsigned cpu_target)
{
switch (cpu_target) {
case 0: write<Core_mailbox_set<0>>(1); return;
case 1: write<Core_mailbox_set<1>>(1); return;
case 2: write<Core_mailbox_set<2>>(1); return;
case 3: write<Core_mailbox_set<3>>(1); return;
}
}

View File

@ -23,31 +23,34 @@ class Board::Pic : Genode::Mmio
public:
enum {
IPI = 0,
NR_OF_IRQ = 64,
/*
* dummy IPI value on non-SMP platform,
* only used in interrupt reservation within generic code
*/
IPI,
};
private:
struct Core0_timer_irq_control : Register<0x40, 32>
template <unsigned CPU_NUM>
struct Core_timer_irq_control : Register<0x40+CPU_NUM*0x4, 32>
{
struct Cnt_p_ns_irq : Bitfield<1, 1> {};
struct Cnt_p_ns_irq
: Register<0x40+CPU_NUM*0x4, 32>::template Bitfield<1, 1> {};
};
struct Core1_timer_irq_control : Register<0x44, 32> {};
struct Core2_timer_irq_control : Register<0x48, 32> {};
struct Core3_timer_irq_control : Register<0x4c, 32> {};
template <unsigned CPU_NUM>
struct Core_mailbox_irq_control : Register<0x50+CPU_NUM*0x4, 32> {};
struct Core0_irq_source : Register<0x60, 32> {};
struct Core1_irq_source : Register<0x64, 32> {};
struct Core2_irq_source : Register<0x68, 32> {};
struct Core3_irq_source : Register<0x6c, 32> {};
template <unsigned CPU_NUM>
struct Core_irq_source : Register<0x60+CPU_NUM*0x4, 32> {};
template <unsigned CPU_NUM>
struct Core_mailbox_set : Register<0x80+CPU_NUM*0x10, 32> {};
template <unsigned CPU_NUM>
struct Core_mailbox_clear : Register<0xc0+CPU_NUM*0x10, 32> {};
void _ipi(unsigned cpu, bool enable);
void _timer_irq(unsigned cpu, bool enable);
public:
@ -55,10 +58,10 @@ class Board::Pic : Genode::Mmio
bool take_request(unsigned &irq);
void finish_request() { }
void mask();
void unmask(unsigned const i, unsigned);
void mask(unsigned const i);
void irq_mode(unsigned, unsigned, unsigned);
void send_ipi(unsigned);
static constexpr bool fast_interrupts() { return false; }
};