| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2018/10/01 Bernard The first version
- * 2018/12/27 Jesven Change irq enable/disable to cpu0
- */
- #include <plic.h>
- #include <mmu.h>
- #include "tick.h"
- #include "encoding.h"
- #include "riscv.h"
- #include "interrupt.h"
- struct rt_irq_desc irq_desc[MAX_HANDLERS];
- #ifdef RT_USING_SMP
- #include "sbi.h"
- struct rt_irq_desc ipi_desc[RT_MAX_IPI];
- uint8_t ipi_vectors[RT_CPUS_NR] = { 0 };
- #endif /* RT_USING_SMP */
- static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
- {
- rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
- return RT_NULL;
- }
- int rt_hw_plic_irq_enable(int irq_number)
- {
- plic_irq_enable(irq_number);
- return 0;
- }
- int rt_hw_plic_irq_disable(int irq_number)
- {
- plic_irq_disable(irq_number);
- return 0;
- }
- /**
- * This function will un-mask a interrupt.
- * @param vector the interrupt number
- */
- void rt_hw_interrupt_umask(int vector)
- {
- plic_set_priority(vector, 1);
- rt_hw_plic_irq_enable(vector);
- }
- /**
- * This function will install a interrupt service routine to a interrupt.
- * @param vector the interrupt number
- * @param new_handler the interrupt service routine to be installed
- * @param old_handler the old interrupt service routine
- */
- rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
- void *param, const char *name)
- {
- rt_isr_handler_t old_handler = RT_NULL;
- if (vector < MAX_HANDLERS)
- {
- old_handler = irq_desc[vector].handler;
- if (handler != RT_NULL)
- {
- irq_desc[vector].handler = (rt_isr_handler_t)handler;
- irq_desc[vector].param = param;
- #ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
- irq_desc[vector].counter = 0;
- #endif
- }
- }
- return old_handler;
- }
- void rt_hw_interrupt_init()
- {
- /* Enable machine external interrupts. */
- // set_csr(sie, SIP_SEIP);
- int idx = 0;
- /* init exceptions table */
- for (idx = 0; idx < MAX_HANDLERS; idx++)
- {
- irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
- irq_desc[idx].param = RT_NULL;
- #ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
- irq_desc[idx].counter = 0;
- #endif
- }
- plic_set_threshold(0);
- }
- #ifdef RT_USING_SMP
- void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
- {
- plic_set_priority(vector, priority);
- }
- unsigned int rt_hw_interrupt_get_priority(int vector)
- {
- return (*(uint32_t *)PLIC_PRIORITY(vector));
- }
- rt_bool_t rt_hw_interrupt_is_disabled(void)
- {
- /* Determine the interrupt enable state */
- rt_ubase_t sstatus;
- __asm__ volatile("csrr %0, sstatus" : "=r"(sstatus));
- return (sstatus & SSTATUS_SIE) == 0;
- }
- void rt_hw_spin_lock_init(rt_hw_spinlock_t *_lock)
- {
- _lock->slock = 0;
- }
- void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
- {
- /* Use ticket lock implemented on top of the 32/64-bit atomic AMO ops.
- * The combined word layout (slock) maps two uint16_t fields:
- * low 16 bits: owner
- * high 16 bits: next (ticket allocator)
- * We atomically increment the "next" field by (1 << 16) and use the
- * returned old value to compute our ticket. Then wait until owner == ticket.
- */
- rt_atomic_t prev;
- rt_atomic_t ticket;
- rt_atomic_t owner;
- /* Allocate a ticket by adding (1 << 16) to slock, prev holds previous value */
- prev = rt_hw_atomic_add((volatile rt_atomic_t *)&lock->slock, (rt_atomic_t)(1UL << 16));
- ticket = (prev >> 16) & 0xffffUL;
- /* Wait until owner equals our ticket */
- for (;;)
- {
- owner = rt_hw_atomic_load((volatile rt_atomic_t *)&lock->slock) & 0xffffUL;
- if (owner == ticket)
- break;
- /* TODO: low-power wait for interrupt while spinning */
- }
- /* Ensure all following memory accesses are ordered after acquiring the lock */
- __asm__ volatile("fence rw, rw" ::: "memory");
- }
- void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
- {
- /* Ensure memory operations before unlock are visible before owner increment */
- __asm__ volatile("fence rw, rw" ::: "memory");
- /* Increment owner (low 16 bits) to hand over lock to next ticket.
- * Use an atomic load of the combined slock word and compare the low
- * 16-bit owner field.If owner would overflow (0xffff), clear the owner field
- * atomically by ANDing with 0xffff0000; otherwise increment owner by 1.
- */
- if ((rt_hw_atomic_load((volatile rt_atomic_t *)&lock->slock) & (rt_atomic_t)0xffffUL) == (rt_atomic_t)0xffffUL)
- {
- /* Atomic clear owner (low 16 bits) when it overflows. Keep next ticket field. */
- rt_hw_atomic_and((volatile rt_atomic_t *)&lock->slock, (rt_atomic_t)0xffff0000UL);
- }
- else
- {
- rt_hw_atomic_add((volatile rt_atomic_t *)&lock->slock, (rt_atomic_t)1);
- }
- // TODO: IPI interrupt to wake up other harts waiting for the lock
- /* Make the increment visible to other harts */
- __asm__ volatile("fence rw, rw" ::: "memory");
- }
- void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
- {
- int cpuid = __builtin_ctz(cpu_mask); // get the bit position of the lowest set bit
- ipi_vectors[cpuid] |= (uint8_t)ipi_vector;
- sbi_send_ipi((const unsigned long *)&cpu_mask);
- }
- void rt_hw_ipi_init(void)
- {
- int idx = 0, cpuid = rt_cpu_get_id();
- ipi_vectors[cpuid] = 0;
- /* init exceptions table */
- for (idx = 0; idx < RT_MAX_IPI; idx++)
- {
- ipi_desc[idx].handler = RT_NULL;
- ipi_desc[idx].param = RT_NULL;
- #ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(ipi_desc[idx].name, RT_NAME_MAX - 1, "default");
- ipi_desc[idx].counter = 0;
- #endif
- }
- set_csr(sie, SIP_SSIP);
- }
- void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
- {
- if (ipi_vector < RT_MAX_IPI)
- {
- if (ipi_isr_handler != RT_NULL)
- {
- ipi_desc[ipi_vector].handler = (rt_isr_handler_t)ipi_isr_handler;
- ipi_desc[ipi_vector].param = RT_NULL;
- }
- }
- }
- void rt_hw_ipi_handler(void)
- {
- rt_uint32_t ipi_vector;
- ipi_vector = ipi_vectors[rt_cpu_get_id()];
- while (ipi_vector)
- {
- int bitpos = __builtin_ctz(ipi_vector);
- ipi_vector &= ~(1 << bitpos);
- if (bitpos < RT_MAX_IPI && ipi_desc[bitpos].handler != RT_NULL)
- {
- rt_hw_atomic_and((volatile rt_atomic_t *)&ipi_vectors[rt_cpu_get_id()], ~((rt_atomic_t)(1 << bitpos)));
- /* call the irq service routine */
- ipi_desc[bitpos].handler(bitpos, ipi_desc[bitpos].param);
- }
- }
- // TODO: Clear the software interrupt pending bit in CLINT
- clear_csr(sip, SIP_SSIP);
- }
- #endif /* RT_USING_SMP */
|