SMP: Add support for linking spinlocks into a special, non-cached memory region.
This commit is contained in:
parent
1d06e786e1
commit
e3fe320e08
@ -69,8 +69,8 @@
|
|||||||
* so that it will be ready for the next pause operation.
|
* so that it will be ready for the next pause operation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
|
static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
|
static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
|
@ -105,7 +105,7 @@ void up_idle(void)
|
|||||||
* should not matter which, however.
|
* should not matter which, however.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static volatile spinlock_t lock = SP_UNLOCKED;
|
static volatile spinlock_t lock SP_SECTION = SP_UNLOCKED;
|
||||||
|
|
||||||
/* The one that gets the lock is the one that executes the IDLE operations */
|
/* The one that gets the lock is the one that executes the IDLE operations */
|
||||||
|
|
||||||
|
@ -214,8 +214,8 @@ extern volatile int g_uart_data_available;
|
|||||||
* so that it will be ready for the next pause operation.
|
* so that it will be ready for the next pause operation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
|
volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
|
volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -54,39 +54,64 @@
|
|||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
|
static spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
static spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
|
static spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: xtensa_pause_handler
|
* Name: up_cpu_pausereq
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This is the handler for CPU_INTCODE_PAUSE CPU interrupt. This
|
* Return true if a pause request is pending for this CPU.
|
||||||
* implements up_cpu_pause() by performing the following operations:
|
|
||||||
*
|
|
||||||
* 1. The current task state at the head of the current assigned task
|
|
||||||
* list was saved when the interrupt was entered.
|
|
||||||
* 2. This function simply waits on a spinlock, then returns.
|
|
||||||
* 3. Upon return, the interrupt exit logic will restore the state of
|
|
||||||
* the new task at the head of the ready to run list.
|
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* None
|
* cpu - The index of the CPU to be queried
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* None
|
* true = a pause request is pending.
|
||||||
|
* false = no pasue request is pending.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void xtensa_pause_handler(void)
|
bool up_cpu_pausereq(int cpu)
|
||||||
|
{
|
||||||
|
return spin_islocked(&g_cpu_paused[cpu]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_paused
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Handle a pause request from another CPU. Normally, this logic is
|
||||||
|
* executed from interrupt handling logic within the architecture-specific
|
||||||
|
* However, it is sometimes necessary necessary to perform the pending
|
||||||
|
* pause operation in other contexts where the interrupt cannot be taken
|
||||||
|
* in order to avoid deadlocks.
|
||||||
|
*
|
||||||
|
* This function performs the following operations:
|
||||||
|
*
|
||||||
|
* 1. It saves the current task state at the head of the current assigned
|
||||||
|
* task list.
|
||||||
|
* 2. It waits on a spinlock, then
|
||||||
|
* 3. Returns from interrupt, restoring the state of the new task at the
|
||||||
|
* head of the ready to run list.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU to be paused
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* On success, OK is returned. Otherwise, a negated errno value indicating
|
||||||
|
* the nature of the failure is returned.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_paused(int cpu)
|
||||||
{
|
{
|
||||||
FAR struct tcb_s *otcb = this_task();
|
FAR struct tcb_s *otcb = this_task();
|
||||||
FAR struct tcb_s *ntcb;
|
FAR struct tcb_s *ntcb;
|
||||||
int cpu = up_cpu_index();
|
|
||||||
|
|
||||||
/* Update scheduler parameters */
|
/* Update scheduler parameters */
|
||||||
|
|
||||||
@ -128,6 +153,32 @@ void xtensa_pause_handler(void)
|
|||||||
spin_unlock(&g_cpu_wait[cpu]);
|
spin_unlock(&g_cpu_wait[cpu]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: xtensa_pause_handler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This is the handler for CPU_INTCODE_PAUSE CPU interrupt. This
|
||||||
|
* implements up_cpu_pause() by performing the following operations:
|
||||||
|
*
|
||||||
|
* 1. The current task state at the head of the current assigned task
|
||||||
|
* list was saved when the interrupt was entered.
|
||||||
|
* 2. This function simply waits on a spinlock, then returns.
|
||||||
|
* 3. Upon return, the interrupt exit logic will restore the state of
|
||||||
|
* the new task at the head of the ready to run list.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void xtensa_pause_handler(void)
|
||||||
|
{
|
||||||
|
(void)up_cpu_paused(up_cpu_index());
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_cpu_pause
|
* Name: up_cpu_pause
|
||||||
*
|
*
|
||||||
|
@ -59,11 +59,11 @@
|
|||||||
|
|
||||||
/* Single parameter passed with the inter-CPU interrupt */
|
/* Single parameter passed with the inter-CPU interrupt */
|
||||||
|
|
||||||
static volatile uint8_t g_intcode[CONFIG_SMP_NCPUS];
|
static volatile uint8_t g_intcode[CONFIG_SMP_NCPUS] SP_SECTION;
|
||||||
|
|
||||||
/* Spinlock protects parameter array */
|
/* Spinlock protects parameter array */
|
||||||
|
|
||||||
static volatile spinlock_t g_intercpu_spin[CONFIG_SMP_NCPUS] =
|
static volatile spinlock_t g_intercpu_spin[CONFIG_SMP_NCPUS] SP_SECTION =
|
||||||
{
|
{
|
||||||
SP_UNLOCKED, SP_UNLOCKED
|
SP_UNLOCKED, SP_UNLOCKED
|
||||||
};
|
};
|
||||||
|
@ -69,16 +69,29 @@
|
|||||||
* DSB - Data syncrhonization barrier.
|
* DSB - Data syncrhonization barrier.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define HAVE_DMB 1
|
#undef __SP_UNLOCK_FUNCTION
|
||||||
#ifndef SP_DMB
|
#if !defined(SP_DMB)
|
||||||
# define SP_DMB()
|
# define SP_DMB()
|
||||||
# undef HAVE_DMB
|
#else
|
||||||
|
# define __SP_UNLOCK_FUNCTION 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SP_DSB
|
#if !defined(SP_DSB)
|
||||||
# define SP_DSB()
|
# define SP_DSB()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If the target CPU supports a data cache then it may be necessary to
|
||||||
|
* manage spinlocks in a special way, perhaps linking them all into a
|
||||||
|
* special non-cacheable memory region.
|
||||||
|
*
|
||||||
|
* SP_SECTION - Special storage attributes may be required to force
|
||||||
|
* spinlocks into a special, non-cacheable section.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(SP_SECTION)
|
||||||
|
# define SP_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -244,7 +257,7 @@ void spin_lockr(FAR struct spinlock_s *lock);
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_DMB
|
#ifdef __SP_UNLOCK_FUNCTION
|
||||||
void spin_unlock(FAR volatile spinlock_t *lock);
|
void spin_unlock(FAR volatile spinlock_t *lock);
|
||||||
#else
|
#else
|
||||||
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
|
# define spin_unlock(l) do { *(l) = SP_UNLOCKED; } while (0)
|
||||||
|
@ -65,12 +65,12 @@ extern FAR xcpt_t g_irqvector[NR_IRQS];
|
|||||||
* disabled.
|
* disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern volatile spinlock_t g_cpu_irqlock;
|
extern volatile spinlock_t g_cpu_irqlock SP_SECTION;
|
||||||
|
|
||||||
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
||||||
|
|
||||||
extern volatile spinlock_t g_cpu_irqsetlock;
|
extern volatile spinlock_t g_cpu_irqsetlock SP_SECTION;
|
||||||
extern volatile cpu_set_t g_cpu_irqset;
|
extern volatile cpu_set_t g_cpu_irqset SP_SECTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -60,12 +60,12 @@
|
|||||||
* disabled.
|
* disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile spinlock_t g_cpu_irqlock = SP_UNLOCKED;
|
volatile spinlock_t g_cpu_irqlock SP_SECTION = SP_UNLOCKED;
|
||||||
|
|
||||||
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
||||||
|
|
||||||
volatile spinlock_t g_cpu_irqsetlock;
|
volatile spinlock_t g_cpu_irqsetlock SP_SECTION;
|
||||||
volatile cpu_set_t g_cpu_irqset;
|
volatile cpu_set_t g_cpu_irqset SP_SECTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -353,12 +353,12 @@ extern volatile uint32_t g_cpuload_total;
|
|||||||
* least one CPU has pre-emption disabled.
|
* least one CPU has pre-emption disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern volatile spinlock_t g_cpu_schedlock;
|
extern volatile spinlock_t g_cpu_schedlock SP_SECTION;
|
||||||
|
|
||||||
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
||||||
|
|
||||||
extern volatile spinlock_t g_cpu_locksetlock;
|
extern volatile spinlock_t g_cpu_locksetlock SP_SECTION;
|
||||||
extern volatile cpu_set_t g_cpu_lockset;
|
extern volatile cpu_set_t g_cpu_lockset SP_SECTION;
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
@ -109,12 +109,12 @@
|
|||||||
* least one CPU has pre-emption disabled.
|
* least one CPU has pre-emption disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile spinlock_t g_cpu_schedlock = SP_UNLOCKED;
|
volatile spinlock_t g_cpu_schedlock SP_SECTION = SP_UNLOCKED;
|
||||||
|
|
||||||
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
/* Used to keep track of which CPU(s) hold the IRQ lock. */
|
||||||
|
|
||||||
volatile spinlock_t g_cpu_locksetlock;
|
volatile spinlock_t g_cpu_locksetlock SP_SECTION;
|
||||||
volatile cpu_set_t g_cpu_lockset;
|
volatile cpu_set_t g_cpu_lockset SP_SECTION;
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void spin_lock(FAR volatile spinlock_t *lock)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_DMB
|
#ifdef __SP_UNLOCK_FUNCTION
|
||||||
void spin_unlock(FAR volatile spinlock_t *lock)
|
void spin_unlock(FAR volatile spinlock_t *lock)
|
||||||
{
|
{
|
||||||
*lock = SP_UNLOCKED;
|
*lock = SP_UNLOCKED;
|
||||||
@ -218,8 +218,11 @@ void spin_lockr(FAR struct spinlock_s *lock)
|
|||||||
up_irq_restore(flags);
|
up_irq_restore(flags);
|
||||||
sched_yield();
|
sched_yield();
|
||||||
flags = up_irq_save();
|
flags = up_irq_save();
|
||||||
|
SP_DSB();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SP_DMB();
|
||||||
|
|
||||||
/* Take one count on the lock */
|
/* Take one count on the lock */
|
||||||
|
|
||||||
lock->sp_cpu = cpu;
|
lock->sp_cpu = cpu;
|
||||||
@ -238,8 +241,10 @@ void spin_lockr(FAR struct spinlock_s *lock)
|
|||||||
while (up_testset(&lock->sp_lock) == SP_LOCKED)
|
while (up_testset(&lock->sp_lock) == SP_LOCKED)
|
||||||
{
|
{
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
SP_DSB()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SP_DMB();
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user