From 6b54dcbbef6a003ae4c5fb9ae77f2f261f82dbf9 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 12 Oct 2016 09:40:41 +0200 Subject: bsps/i386: replace global interrupt disable by SMP build supporting locking. --- c/src/lib/libbsp/i386/pc386/timer/timer.c | 45 ++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'c/src/lib/libbsp/i386/pc386/timer/timer.c') diff --git a/c/src/lib/libbsp/i386/pc386/timer/timer.c b/c/src/lib/libbsp/i386/pc386/timer/timer.c index 0e4d6a9c37..5bef139d38 100644 --- a/c/src/lib/libbsp/i386/pc386/timer/timer.c +++ b/c/src/lib/libbsp/i386/pc386/timer/timer.c @@ -44,6 +44,9 @@ #define CMD_READ_BACK_STATUS 0xE2 /* command read back status */ +RTEMS_INTERRUPT_LOCK_DEFINE( /* visible global variable */ , + rtems_i386_i8254_access_lock, "rtems_i386_i8254_access_lock" ); + /* * Global Variables */ @@ -115,23 +118,35 @@ static uint32_t tsc_read_timer(void) */ static void timerOff(const rtems_raw_irq_connect_data* used) { + rtems_interrupt_lock_context lock_context; /* * disable interrrupt at i8259 level */ - bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE); + bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE); + + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); + /* reset timer mode to standard (DOS) value */ - outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); - outport_byte(TIMER_CNTR0, 0); - outport_byte(TIMER_CNTR0, 0); + outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); + outport_byte(TIMER_CNTR0, 0); + outport_byte(TIMER_CNTR0, 0); + + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); } static void timerOn(const rtems_raw_irq_connect_data* used) { + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); + /* load timer for US_PER_ISR microsecond period */ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff); outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff); + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); + /* * enable interrrupt at i8259 level */ @@ -199,10 +214,14 @@ static uint32_t i386_read_timer(void) { register uint32_t total, clicks; register uint8_t lsb, msb; + rtems_interrupt_lock_context lock_context; + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); inport_byte(TIMER_CNTR0, lsb); inport_byte(TIMER_CNTR0, msb); + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); + clicks = (msb << 8) | lsb; total = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks)); @@ -273,10 +292,13 @@ static unsigned short lastLoadedValue; */ static void loadTimerValue( unsigned short loadedValue ) { + rtems_interrupt_lock_context lock_context; + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); lastLoadedValue = loadedValue; outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_SQWAVE); outport_byte(TIMER_CNTR0, loadedValue & 0xff); outport_byte(TIMER_CNTR0, (loadedValue >> 8) & 0xff); + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); } /* @@ -290,6 +312,8 @@ static unsigned int readTimer0(void) unsigned short lsb, msb; unsigned char status; unsigned int count; + rtems_interrupt_lock_context lock_context; + rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context); outport_byte( TIMER_MODE, @@ -298,6 +322,9 @@ static unsigned int readTimer0(void) inport_byte(TIMER_CNTR0, status); inport_byte(TIMER_CNTR0, lsb); inport_byte(TIMER_CNTR0, msb); + + rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); + count = ( msb << 8 ) | lsb ; if (status & RB_OUTPUT ) count += lastLoadedValue; @@ -337,7 +364,13 @@ Calibrate_loop_1ms(void) rtems_interrupt_level level; int retries = 0; - rtems_interrupt_disable(level); + /* + * This code is designed to run before interrupt management + * is enabled and running it on multiple CPUs and or after + * secondary CPUs are bring up seems really broken. + * Disabling of local interrupts is enough. + */ + rtems_interrupt_local_disable(level); retry: if ( ++retries >= 5 ) { @@ -506,7 +539,7 @@ retry: #ifdef DEBUG_CALIBRATE printk("slowLoop1ms = %u, fastLoop1ms = %u\n", slowLoop1ms, fastLoop1ms); #endif - rtems_interrupt_enable(level); + rtems_interrupt_local_enable(level); } -- cgit v1.2.3