📄 pcmb_smp.c
字号:
{ HAL_SMP_CPU_TYPE cpu;// PC_WRITE_SCREEN( PC_SCREEN_LINE(2)+0, '!' );#ifndef CYG_HAL_STARTUP_RAM // Wait for INIT interrupt to be deasserted while( !init_deasserted ) continue;#endif // PC_WRITE_SCREEN( PC_SCREEN_LINE(2)+1, '!' ); cpu = HAL_SMP_CPU_THIS(); // PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+6, cpu ); #ifndef CYG_HAL_STARTUP_RAM // Wait 1s for the world to settle hal_delay_us( 1000000 );// PC_WRITE_SCREEN( PC_SCREEN_LINE(2)+2, '!' ); // Setup our APIC cyg_hal_smp_init_apic();#endif // PC_WRITE_SCREEN( PC_SCREEN_LINE(2)+3, '!' ); #ifdef CYGPKG_KERNEL_SMP_SUPPORT cyg_hal_smp_cpu_running[cpu] = 1; cyg_kernel_smp_startup();#else for(;;) { void (*entry)(void); while( (entry = cyg_hal_smp_cpu_entry[cpu]) == 0 ) {#if 0 //SCREEN_DIAGNOSTICS static int n; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+10, n ); PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+15, cyg_hal_smp_cpu_sync[cpu] ); PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+30, cyg_hal_smp_cpu_sync_flag[0] ); PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+35, cyg_hal_smp_cpu_sync_flag[1] ); PC_WRITE_SCREEN_8( PC_SCREEN_LINE(2)+40, cyg_hal_smp_vsr_sync_flag ); n++;#endif hal_delay_us( 100 ); }// PC_WRITE_SCREEN( PC_SCREEN_LINE(2)+4, '!' ); cyg_hal_smp_cpu_entry[cpu] = 0; // PC_WRITE_SCREEN_32( PC_SCREEN_LINE(2)+20, entry ); if( entry != NULL ) { cyg_hal_smp_cpu_running[cpu] = 1; entry(); } }#endif }/*------------------------------------------------------------------------*/__externC void cyg_hal_smp_init(void){ if( !cyg_hal_find_smp_config() ) return; if( !cyg_hal_parse_smp_config() ) return; if( !cyg_hal_smp_init_apic() ) return; if( !cyg_hal_smp_init_ioapic() ) return;}/*------------------------------------------------------------------------*/__externC void cyg_hal_smp_cpu_start_all(void){ HAL_SMP_CPU_TYPE cpu; for( cpu = 0; cpu < HAL_SMP_CPU_COUNT(); cpu++ ) { cyg_hal_smp_cpu_sync[cpu] = 0; cyg_hal_smp_cpu_sync_flag[cpu] = 0; cyg_hal_smp_cpu_running[cpu] = 0; cyg_hal_smp_cpu_entry[cpu] = 0; if( cpu != HAL_SMP_CPU_THIS() ) cyg_hal_cpu_start( cpu ); else cyg_hal_smp_cpu_running[cpu] = 1; }}/*------------------------------------------------------------------------*/// SMP message buffers.// SMP CPUs pass messages to eachother via a small circular buffer// protected by a spinlock. Each message is a single 32 bit word with// a type code in the top 4 bits and any argument in the remaining// 28 bits.#define SMP_MSGBUF_SIZE 4static struct smp_msg_t{ HAL_SPINLOCK_TYPE lock; // protecting spinlock volatile CYG_WORD32 msgs[SMP_MSGBUF_SIZE]; // message buffer volatile CYG_WORD32 head; // head of list volatile CYG_WORD32 tail; // tail of list volatile CYG_WORD32 reschedule; // reschedule request volatile CYG_WORD32 timeslice; // timeslice request} smp_msg[HAL_SMP_CPU_MAX];/*------------------------------------------------------------------------*/// Pass a message to another CPU.#if SCREEN_DIAGNOSTICSstatic int res_msgs[2], tms_msgs[2];#endif__externC void cyg_hal_cpu_message( HAL_SMP_CPU_TYPE cpu, CYG_WORD32 msg, CYG_WORD32 arg, CYG_WORD32 wait){#if 1 CYG_INTERRUPT_STATE istate; struct smp_msg_t *m = &smp_msg[cpu]; int i; HAL_SMP_CPU_TYPE me = HAL_SMP_CPU_THIS(); HAL_DISABLE_INTERRUPTS( istate ); // Get access to the message buffer for the selected CPU HAL_SPINLOCK_SPIN( m->lock );#if 0 //SCREEN_DIAGNOSTICS if( msg == HAL_SMP_MESSAGE_RESCHEDULE ) res_msgs[me]++; else if( msg == HAL_SMP_MESSAGE_TIMESLICE ) tms_msgs[me]++; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(18+me), me); PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+40, res_msgs[me]); PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+45, tms_msgs[me]); #endif if( msg == HAL_SMP_MESSAGE_RESCHEDULE ) m->reschedule = true; else if( msg == HAL_SMP_MESSAGE_TIMESLICE ) m->timeslice = true; else { CYG_WORD32 next = (m->tail + 1) & (SMP_MSGBUF_SIZE-1); // If the buffer is full, wait for space to appear in it. // This should only need to be done very rarely. while( next == m->head ) { HAL_SPINLOCK_CLEAR( m->lock ); for( i = 0; i < 1000; i++ ); HAL_SPINLOCK_SPIN( m->lock ); } m->msgs[m->tail] = msg | arg; m->tail = next; } // Now send an interrupt to the CPU. // PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+50, cyg_hal_smp_cpu_running[cpu] ); if( cyg_hal_smp_cpu_running[cpu] ) { CYG_WORD32 icrlo, icrhi; // Set the ICR fields we want to write. Most fields are zero // except the destination in the high word and the vector // number in the low. icrhi = cpu<<24; icrlo = CYGNUM_HAL_SMP_CPU_INTERRUPT_VECTOR( cpu ); // Write the ICR register. The interrupt will be raised when // the low word is written. HAL_APIC_WRITE( HAL_APIC_ICR_HI, icrhi ); HAL_APIC_WRITE( HAL_APIC_ICR_LO, icrlo ); // Wait for the ICR to become inactive do {#if 0 //SCREEN_DIAGNOSTICS static int n; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(18+me)+55, n ); n++;#endif HAL_APIC_READ( HAL_APIC_ICR_LO, icrlo ); } while( (icrlo & 0x00001000) != 0 ); } HAL_SPINLOCK_CLEAR( m->lock ); // If we are expected to wait for the command to complete, then // spin here until it does. We actually wait for the destination // CPU to empty its input buffer. So we might wait for messages // from other CPUs as well. But this is benign. while(wait) { for( i = 0; i < 1000; i++ ); HAL_SPINLOCK_SPIN( m->lock ); if( m->head == m->tail ) wait = false; HAL_SPINLOCK_CLEAR( m->lock ); } HAL_RESTORE_INTERRUPTS( istate );#endif }/*------------------------------------------------------------------------*/#if SCREEN_DIAGNOSTICSstatic int isrs[2];static int dsrs[2];#endif__externC CYG_WORD32 cyg_hal_cpu_message_isr( CYG_WORD32 vector, CYG_ADDRWORD data ){ HAL_SMP_CPU_TYPE me = HAL_SMP_CPU_THIS(); struct smp_msg_t *m = &smp_msg[me]; CYG_WORD32 ret = 1; CYG_INTERRUPT_STATE istate; HAL_DISABLE_INTERRUPTS( istate ); HAL_SPINLOCK_SPIN( m->lock ); // First, acknowledge the interrupt. HAL_INTERRUPT_ACKNOWLEDGE( vector );#if SCREEN_DIAGNOSTICS isrs[me]++; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(18+me), me); PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+5, isrs[me]); #endif if( m->reschedule || m->timeslice ) ret |= 2; // Ask for the DSR to be called. // Now pick messages out of the buffer and handle them while( m->head != m->tail ) { CYG_WORD32 msg = m->msgs[m->head]; switch( msg & HAL_SMP_MESSAGE_TYPE ) { case HAL_SMP_MESSAGE_RESCHEDULE: ret |= 2; // Ask for the DSR to be called. break; case HAL_SMP_MESSAGE_MASK: // Mask the supplied vector// cyg_hal_interrupt_set_mask( msg&HAL_SMP_MESSAGE_ARG, false ); break; case HAL_SMP_MESSAGE_UNMASK: // Unmask the supplied vector// cyg_hal_interrupt_set_mask( msg&HAL_SMP_MESSAGE_ARG, true ); break; case HAL_SMP_MESSAGE_REVECTOR: // Deal with a change of CPU assignment for a vector. We // only actually worry about what happens when the vector // is changed to some other CPU. We just mask the // interrupt locally.// if( hal_interrupt_cpu[msg&HAL_SMP_MESSAGE_ARG] != me )// cyg_hal_interrupt_set_mask( msg&HAL_SMP_MESSAGE_ARG, false ); break; } // Update the head pointer after handling the message, so that // the wait in cyg_hal_cpu_message() completes after the action // requested. m->head = (m->head + 1) & (SMP_MSGBUF_SIZE-1); } HAL_SPINLOCK_CLEAR( m->lock ); HAL_RESTORE_INTERRUPTS( istate ); return ret;}/*------------------------------------------------------------------------*/// CPU message DSR.// This is only executed if the message was// HAL_SMP_MESSAGE_RESCHEDULE. It calls up into the kernel to effect a// reschedule.__externC void cyg_scheduler_set_need_reschedule(void);__externC void cyg_scheduler_timeslice_cpu(void);#if SCREEN_DIAGNOSTICS__externC int cyg_scheduler_sched_lock;static int rescheds[2];static int timeslices[2];#endif__externC CYG_WORD32 cyg_hal_cpu_message_dsr( CYG_WORD32 vector, CYG_ADDRWORD data ){ HAL_SMP_CPU_TYPE me = HAL_SMP_CPU_THIS(); struct smp_msg_t *m = &smp_msg[me]; CYG_INTERRUPT_STATE istate; CYG_WORD32 reschedule, timeslice; HAL_DISABLE_INTERRUPTS( istate ); HAL_SPINLOCK_SPIN( m->lock );#if SCREEN_DIAGNOSTICS dsrs[me]++; PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+10, dsrs[me]); PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+15, cyg_scheduler_sched_lock); #endif reschedule = m->reschedule; timeslice = m->timeslice; m->reschedule = m->timeslice = false; HAL_SPINLOCK_CLEAR( m->lock ); HAL_RESTORE_INTERRUPTS( istate ); if( reschedule ) {#if SCREEN_DIAGNOSTICS rescheds[me]++; PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+20, rescheds[me]);#endif cyg_scheduler_set_need_reschedule(); } if( timeslice ) {#if SCREEN_DIAGNOSTICS timeslices[me]++; PC_WRITE_SCREEN_16( PC_SCREEN_LINE(18+me)+25, timeslices[me]);#endif cyg_scheduler_timeslice_cpu(); } return 0; }/*------------------------------------------------------------------------*/#if SCREEN_DIAGNOSTICSstatic int x = 0;#endif__externC void cyg_hal_smp_halt_other_cpus(void){ int i; HAL_SMP_CPU_TYPE me = HAL_SMP_CPU_THIS(); // PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me), me ); for( i = 0 ; i < HAL_SMP_CPU_COUNT(); i++ ) { if( i != me && cyg_hal_smp_cpu_running[i] ) { CYG_WORD32 icrhi, icrlo; CYG_WORD32 oldsync; // PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me)+40, i ); oldsync = cyg_hal_smp_cpu_sync_flag[i]; cyg_hal_smp_cpu_sync[i] = 0; icrhi = i<<24; icrlo = CYGNUM_HAL_VECTOR_NMI; // not really used icrlo |= 0x00000400; // Delivery = NMI //icrlo |= 0x000C0000; // Dest = all excluding self // Write the ICR register. The interrupt will be raised when // the low word is written. HAL_APIC_WRITE( HAL_APIC_ICR_HI, icrhi ); HAL_APIC_WRITE( HAL_APIC_ICR_LO, icrlo ); // Wait for the ICR to become inactive do {#if 0 //SCREEN_DIAGNOSTICS static int n; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me)+45, n ); n++;#endif HAL_APIC_READ( HAL_APIC_ICR_LO, icrlo ); } while( (icrlo & 0x00001000) != 0 ); // Wait for CPU to halt while( cyg_hal_smp_cpu_sync_flag[i] == oldsync ) {#if 0 //SCREEN_DIAGNOSTICS PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me)+4, x ); x++; PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me)+10+(i*8), cyg_hal_smp_cpu_sync_flag[i] ); PC_WRITE_SCREEN_8( PC_SCREEN_LINE(6+me)+10+(i*8)+4, oldsync );#endif hal_delay_us( 100 ); } } } }__externC void cyg_hal_smp_release_other_cpus(void){ int i; for( i = 0 ; i < HAL_SMP_CPU_COUNT(); i++ ) { if( i != HAL_SMP_CPU_THIS() && cyg_hal_smp_cpu_running[i] ) { CYG_WORD32 oldsync = cyg_hal_smp_cpu_sync_flag[i]; cyg_hal_smp_cpu_sync[i] = 1; while( cyg_hal_smp_cpu_sync_flag[i] == oldsync ) continue; cyg_hal_smp_cpu_sync[i] = 0; } }}#endif // CYGPKG_HAL_SMP_SUPPORT/*------------------------------------------------------------------------*//* End of pcmb_smp.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -