mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 05:53:22 +00:00
初始化riscv-sbi-timer (#716)
This commit is contained in:
2
kernel/src/driver/clocksource/mod.rs
Normal file
2
kernel/src/driver/clocksource/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub mod timer_riscv;
|
131
kernel/src/driver/clocksource/timer_riscv.rs
Normal file
131
kernel/src/driver/clocksource/timer_riscv.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
use bitmap::{traits::BitMapOps, StaticBitmap};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, time::riscv_time_base_freq, CurrentIrqArch, CurrentTimeArch},
|
||||
driver::base::device::DeviceId,
|
||||
exception::{
|
||||
irqdata::{IrqHandlerData, IrqLineStatus},
|
||||
irqdesc::{
|
||||
irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
|
||||
},
|
||||
manage::irq_manager,
|
||||
InterruptArch, IrqNumber,
|
||||
},
|
||||
libs::spinlock::SpinLock,
|
||||
mm::percpu::PerCpu,
|
||||
process::ProcessManager,
|
||||
smp::core::smp_get_processor_id,
|
||||
time::TimeArch,
|
||||
};
|
||||
|
||||
pub struct RiscVSbiTimer;
|
||||
|
||||
static SBI_TIMER_INIT_BMP: SpinLock<StaticBitmap<{ PerCpu::MAX_CPU_NUM as usize }>> =
|
||||
SpinLock::new(StaticBitmap::new());
|
||||
|
||||
static mut INTERVAL_CNT: usize = 0;
|
||||
|
||||
impl RiscVSbiTimer {
|
||||
pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
|
||||
|
||||
fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
|
||||
// 更新下一次中断时间
|
||||
kdebug!(
|
||||
"riscv_sbi_timer: handle_irq: cpu_id: {}, time: {}",
|
||||
smp_get_processor_id().data(),
|
||||
CurrentTimeArch::get_cycles() as u64
|
||||
);
|
||||
sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64 + unsafe { INTERVAL_CNT } as u64);
|
||||
ProcessManager::update_process_times(trap_frame.is_from_user());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enable() {
|
||||
unsafe { riscv::register::sie::set_stimer() };
|
||||
}
|
||||
|
||||
fn disable() {
|
||||
unsafe { riscv::register::sie::clear_stimer() };
|
||||
}
|
||||
}
|
||||
|
||||
/// riscv 初始化本地调度时钟源
|
||||
#[inline(never)]
|
||||
pub fn riscv_sbi_timer_init_local() {
|
||||
assert_eq!(CurrentIrqArch::is_irq_enabled(), false);
|
||||
|
||||
if unsafe { INTERVAL_CNT } == 0 {
|
||||
// todo: 将来正式实现时,需要除以HZ
|
||||
let new = riscv_time_base_freq();
|
||||
if new == 0 {
|
||||
panic!("riscv_sbi_timer_init: failed to get timebase-frequency");
|
||||
}
|
||||
unsafe {
|
||||
INTERVAL_CNT = new;
|
||||
}
|
||||
}
|
||||
|
||||
let mut guard = SBI_TIMER_INIT_BMP.lock();
|
||||
// 如果已经初始化过了,直接返回。或者cpu id不存在
|
||||
if guard
|
||||
.get(smp_get_processor_id().data() as usize)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
irq_manager()
|
||||
.request_irq(
|
||||
RiscVSbiTimer::TIMER_IRQ,
|
||||
"riscv_clocksource".to_string(),
|
||||
&RiscvSbiTimerHandler,
|
||||
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
|
||||
Some(DeviceId::new(Some("riscv sbi timer"), None).unwrap()),
|
||||
)
|
||||
.expect("Apic timer init failed");
|
||||
|
||||
// 设置第一次中断
|
||||
sbi_rt::set_timer(CurrentTimeArch::get_cycles() as u64);
|
||||
|
||||
RiscVSbiTimer::enable();
|
||||
guard
|
||||
.set(smp_get_processor_id().data() as usize, true)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn riscv_sbi_timer_irq_desc_init() {
|
||||
let desc = irq_desc_manager().lookup(RiscVSbiTimer::TIMER_IRQ).unwrap();
|
||||
|
||||
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
||||
desc.set_handler(&RiscvSbiTimerIrqFlowHandler);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RiscvSbiTimerHandler;
|
||||
|
||||
impl IrqHandler for RiscvSbiTimerHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
// empty (只是为了让编译通过,不会被调用到。真正的处理函数在 RiscvSbiTimerIrqFlowHandler 中)
|
||||
Ok(IrqReturn::NotHandled)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RiscvSbiTimerIrqFlowHandler;
|
||||
|
||||
impl IrqFlowHandler for RiscvSbiTimerIrqFlowHandler {
|
||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, trap_frame: &mut TrapFrame) {
|
||||
RiscVSbiTimer::handle_irq(trap_frame).unwrap();
|
||||
fence(Ordering::SeqCst)
|
||||
}
|
||||
}
|
@ -1,13 +1,19 @@
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::exception::{
|
||||
handle::PerCpuDevIdIrqHandler,
|
||||
irqchip::{IrqChip, IrqChipFlags},
|
||||
irqdata::IrqData,
|
||||
irqdesc::irq_desc_manager,
|
||||
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
use crate::{
|
||||
arch::interrupt::TrapFrame,
|
||||
driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
|
||||
exception::{
|
||||
handle::PerCpuDevIdIrqHandler,
|
||||
irqchip::{IrqChip, IrqChipFlags},
|
||||
irqdata::IrqData,
|
||||
irqdesc::{irq_desc_manager, GenericIrqHandler},
|
||||
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
},
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
sched::{SchedMode, __schedule},
|
||||
};
|
||||
|
||||
static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
|
||||
@ -24,7 +30,9 @@ fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RiscvIntcChip;
|
||||
struct RiscvIntcChip {
|
||||
inner: SpinLock<InnerIrqChip>,
|
||||
}
|
||||
|
||||
impl IrqChip for RiscvIntcChip {
|
||||
fn name(&self) -> &'static str {
|
||||
@ -43,9 +51,7 @@ impl IrqChip for RiscvIntcChip {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn irq_ack(&self, irq: &Arc<IrqData>) {
|
||||
todo!()
|
||||
}
|
||||
fn irq_ack(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn can_mask_ack(&self) -> bool {
|
||||
false
|
||||
@ -75,10 +81,28 @@ impl IrqChip for RiscvIntcChip {
|
||||
}
|
||||
|
||||
fn flags(&self) -> IrqChipFlags {
|
||||
todo!()
|
||||
self.inner().flags
|
||||
}
|
||||
}
|
||||
|
||||
impl RiscvIntcChip {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: SpinLock::new(InnerIrqChip {
|
||||
flags: IrqChipFlags::empty(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqChip {
|
||||
flags: IrqChipFlags,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RiscvIntcDomainOps;
|
||||
|
||||
@ -104,14 +128,14 @@ impl IrqDomainOps for RiscvIntcDomainOps {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber) {
|
||||
fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
|
||||
todo!("riscv_intc_domain_ops::unmap");
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
||||
let intc_chip = Arc::new(RiscvIntcChip);
|
||||
let intc_chip = Arc::new(RiscvIntcChip::new());
|
||||
|
||||
unsafe {
|
||||
RISCV_INTC_CHIP = Some(intc_chip);
|
||||
@ -130,5 +154,18 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
||||
RISCV_INTC_DOMAIN = Some(intc_domain);
|
||||
}
|
||||
|
||||
riscv_sbi_timer_irq_desc_init();
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
|
||||
pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
|
||||
let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
|
||||
kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
|
||||
GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
|
||||
.ok();
|
||||
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
|
||||
__schedule(SchedMode::SM_PREEMPT);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod acpi;
|
||||
pub mod base;
|
||||
pub mod block;
|
||||
pub mod clocksource;
|
||||
pub mod disk;
|
||||
pub mod firmware;
|
||||
pub mod input;
|
||||
|
Reference in New Issue
Block a user