[PATCH 1/3] bsps/i386: replace global interrupt disable by SMP build supporting locking.

pisa at cmp.felk.cvut.cz pisa at cmp.felk.cvut.cz
Wed Oct 12 08:26:26 UTC 2016


From: Pavel Pisa <pisa at cmp.felk.cvut.cz>

---
 c/src/lib/libbsp/i386/pc386/clock/ckinit.c     | 19 ++++++---
 c/src/lib/libbsp/i386/pc386/console/inch.c     | 10 +++--
 c/src/lib/libbsp/i386/pc386/console/keyboard.c | 55 ++++++++++++--------------
 c/src/lib/libbsp/i386/pc386/console/vt.c       | 13 +++---
 c/src/lib/libbsp/i386/pc386/include/bsp.h      |  5 +++
 c/src/lib/libbsp/i386/pc386/timer/timer.c      | 45 ++++++++++++++++++---
 c/src/lib/libbsp/i386/shared/irq/idt.c         | 34 ++++++++++------
 c/src/lib/libbsp/i386/shared/irq/irq.c         | 32 ++++++++++-----
 c/src/lib/libbsp/i386/shared/irq/irq_init.c    |  7 +++-
 9 files changed, 148 insertions(+), 72 deletions(-)

diff --git a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c
index 67f4bf7..e7fe50a 100644
--- a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c
+++ b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c
@@ -84,15 +84,18 @@ static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
 {
   uint32_t                 irqs;
   uint8_t                  lsb, msb;
-  rtems_interrupt_level    level;
+  rtems_interrupt_lock_context lock_context;
 
   /*
    * Fetch all the data in an interrupt critical section.
    */
-  rtems_interrupt_disable(level);
+
+  rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
+
     READ_8254(lsb, msb);
     irqs = Clock_driver_ticks;
-  rtems_interrupt_enable(level);
+
+  rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
 
   return (irqs + 1) * pc386_microseconds_per_isr - ((msb << 8) | lsb);
 }
@@ -141,6 +144,7 @@ static void calibrate_tsc(void)
 
 static void clockOn(void)
 {
+  rtems_interrupt_lock_context lock_context;
   pc386_isrs_per_tick        = 1;
   pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
 
@@ -150,8 +154,6 @@ static void clockOn(void)
   }
   pc386_clock_click_count = US_TO_TICK(pc386_microseconds_per_isr);
 
-  bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER - BSP_IRQ_VECTOR_BASE );
-
   #if 0
     printk( "configured usecs per tick=%d \n",
       rtems_configuration_get_microseconds_per_tick() );
@@ -160,9 +162,13 @@ static void clockOn(void)
     printk( "final timer counts=%d\n", pc386_clock_click_count );
   #endif
 
+  rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
   outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
   outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 0 & 0xff);
   outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 8 & 0xff);
+  rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
+
+  bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER - BSP_IRQ_VECTOR_BASE );
 
   /*
    * Now calibrate cycles per tick. Do this every time we
@@ -174,10 +180,13 @@ static void clockOn(void)
 
 static void clockOff(void)
 {
+  rtems_interrupt_lock_context lock_context;
+  rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
   /* reset timer mode to standard (BIOS) value */
   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);
 } /* Clock_exit */
 
 bool Clock_isr_enabled = false;
diff --git a/c/src/lib/libbsp/i386/pc386/console/inch.c b/c/src/lib/libbsp/i386/pc386/console/inch.c
index 047269e..f5d5079 100644
--- a/c/src/lib/libbsp/i386/pc386/console/inch.c
+++ b/c/src/lib/libbsp/i386/pc386/console/inch.c
@@ -260,13 +260,17 @@ int BSP_wait_polled_input(void)
 int rtems_kbpoll( void )
 {
   int                    rc;
-  rtems_interrupt_level level;
 
-  rtems_interrupt_disable(level);
+  /*
+   * The locking or disable of interrupts does not help
+   * there because if interrupts are enabled after leave of this
+   * function the state can change without notice anyway.
+   */
+  RTEMS_COMPILER_MEMORY_BARRIER();
 
   rc = ( kbd_first != kbd_last ) ? TRUE : FALSE;
 
-  rtems_interrupt_enable(level);
+  RTEMS_COMPILER_MEMORY_BARRIER();
 
   return rc;
 }
diff --git a/c/src/lib/libbsp/i386/pc386/console/keyboard.c b/c/src/lib/libbsp/i386/pc386/console/keyboard.c
index 3a33c54..0c8991b 100644
--- a/c/src/lib/libbsp/i386/pc386/console/keyboard.c
+++ b/c/src/lib/libbsp/i386/pc386/console/keyboard.c
@@ -9,6 +9,7 @@
 #include <rtems/kd.h>
 #include <bsp.h>
 #include <bsp/bootcard.h>
+#include <stdatomic.h>
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
@@ -28,59 +29,53 @@
 #define KBD_DEFLOCK 0
 #endif
 
-static int set_bit(int nr, unsigned long * addr)
+static int kbd_test_and_set_bit(int nr, atomic_uint_least32_t * addr)
 {
-  int                   mask;
+  uint_least32_t        mask;
   int                   retval;
-  rtems_interrupt_level level;
 
   addr += nr >> 5;
-  mask = 1 << (nr & 0x1f);
-  rtems_interrupt_disable(level);
-    retval = (mask & *addr) != 0;
-    *addr |= mask;
-  rtems_interrupt_enable(level);
+  mask = 1UL << (nr & 0x1f);
+
+  retval = (atomic_fetch_or(addr, mask) & mask) != 0;
+
   return retval;
 }
 
-static int clear_bit(int nr, unsigned long * addr)
+static int kbd_test_and_clear_bit(int nr, atomic_uint_least32_t * addr)
 {
-  int                   mask;
+  uint_least32_t        mask;
   int                   retval;
-  rtems_interrupt_level level;
 
   addr += nr >> 5;
-  mask = 1 << (nr & 0x1f);
-  rtems_interrupt_disable(level);
-    retval = (mask & *addr) != 0;
-    *addr &= ~mask;
-  rtems_interrupt_enable(level);
+  mask = 1UL << (nr & 0x1f);
+
+  retval = (atomic_fetch_and(addr, ~mask) & mask) != 0;
+
   return retval;
 }
 
-static int test_bit(int nr, unsigned long * addr)
+static int kbd_test_bit(int nr, atomic_uint_least32_t * addr)
 {
-  int  mask;
+  unsigned long  mask;
 
   addr += nr >> 5;
   mask = 1 << (nr & 0x1f);
-  return ((mask & *addr) != 0);
+  return ((mask & atomic_load(addr)) != 0);
 }
 
-#define  test_and_set_bit(x,y)      set_bit(x,y)
-#define  test_and_clear_bit(x,y)    clear_bit(x,y)
-
 /*
  * global state includes the following, and various static variables
  * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
  * (last_console is now a global variable)
  */
-#define  BITS_PER_LONG (sizeof(long)*CHAR_BIT)
+#define  KBD_BITS_PER_ELEMENT (sizeof(atomic_uint_least32_t)*CHAR_BIT)
 
 /* shift state counters.. */
 static unsigned char k_down[NR_SHIFT] = {0, };
 /* keyboard key bitmap */
-static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
+static atomic_uint_least32_t
+  key_down[(256 + KBD_BITS_PER_ELEMENT - 1) / KBD_BITS_PER_ELEMENT] = { 0, };
 
 static int dead_key_next = 0;
 /*
@@ -243,10 +238,10 @@ void handle_scancode(unsigned char scancode, int down)
 
   if (up_flag) {
     rep = 0;
-    if(!test_and_clear_bit(keycode, key_down))
+    if(!kbd_test_and_clear_bit(keycode, key_down))
         up_flag = kbd_unexpected_up(keycode);
   } else
-    rep = test_and_set_bit(keycode, key_down);
+    rep = kbd_test_and_set_bit(keycode, key_down);
 
 #ifdef CONFIG_MAGIC_SYSRQ    /* Handle the SysRq Hack */
   if (keycode == SYSRQ_KEY) {
@@ -695,10 +690,10 @@ void compute_shiftstate(void)
     k_down[i] = 0;
 
   for(i=0; i < SIZE(key_down); i++)
-    if(key_down[i]) {  /* skip this word if not a single bit on */
-      k = i*BITS_PER_LONG;
-      for(j=0; j<BITS_PER_LONG; j++,k++)
-        if(test_bit(k, key_down)) {
+    if(atomic_load(key_down + i)) {  /* skip this word if not a single bit on */
+      k = i*KBD_BITS_PER_ELEMENT;
+      for(j=0; j<KBD_BITS_PER_ELEMENT; j++,k++)
+        if(kbd_test_bit(k, key_down)) {
     sym = U(plain_map[k]);
     if(KTYP(sym) == KT_SHIFT) {
       val = KVAL(sym);
diff --git a/c/src/lib/libbsp/i386/pc386/console/vt.c b/c/src/lib/libbsp/i386/pc386/console/vt.c
index 4a38f9d..022cb5d 100644
--- a/c/src/lib/libbsp/i386/pc386/console/vt.c
+++ b/c/src/lib/libbsp/i386/pc386/console/vt.c
@@ -18,6 +18,7 @@
 #include <sys/types.h>
 #include <errno.h>
 
+#include <bsp.h>
 #include <i386_io.h>
 #include <rtems.h>
 #include <rtems/kd.h>
@@ -69,21 +70,21 @@ static void
 _kd_mksound(unsigned int hz, unsigned int ticks)
 {
   unsigned int          count = 0;
-  rtems_interrupt_level level;
+  rtems_interrupt_lock_context lock_context;
 
   if (hz > 20 && hz < 32767)
     count = 1193180 / hz;
 
-   rtems_interrupt_disable(level);
+  rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
 /*  del_timer(&sound_timer);  */
   if (count) {
     /* enable counter 2 */
     outb_p(inb_p(0x61)|3, 0x61);
     /* set command for counter 2, 2 byte write */
-    outb_p(0xB6, 0x43);
+    outb_p(0xB6, TIMER_MODE);
     /* select desired HZ */
-    outb_p(count & 0xff, 0x42);
-    outb((count >> 8) & 0xff, 0x42);
+    outb_p(count & 0xff, TIMER_CNTR2);
+    outb((count >> 8) & 0xff, TIMER_CNTR2);
 
 /*
     if (ticks) {
@@ -94,7 +95,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
   } else
     kd_nosound(0);
 
-   rtems_interrupt_enable(level);
+  rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
   return;
 }
 
diff --git a/c/src/lib/libbsp/i386/pc386/include/bsp.h b/c/src/lib/libbsp/i386/pc386/include/bsp.h
index cdfbce6..4f42fc4 100644
--- a/c/src/lib/libbsp/i386/pc386/include/bsp.h
+++ b/c/src/lib/libbsp/i386/pc386/include/bsp.h
@@ -146,6 +146,11 @@ extern int rtems_3c509_driver_attach(struct rtems_bsdnet_ifconfig *config);
 
 #define	TIMER_TICK     1193182  /* The internal tick rate in ticks per second */
 
+#if defined( RTEMS_SMP )
+  extern ISR_lock_Control rtems_i386_i8254_access_lock;
+#endif
+
+
 /*-------------------------------------------------------------------------+
 | Console Defines
 |      WARNING: These Values MUST match the order in
diff --git a/c/src/lib/libbsp/i386/pc386/timer/timer.c b/c/src/lib/libbsp/i386/pc386/timer/timer.c
index 0e4d6a9..5bef139 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);
 
 }
 
diff --git a/c/src/lib/libbsp/i386/shared/irq/idt.c b/c/src/lib/libbsp/i386/shared/irq/idt.c
index ee6f8e0..ac79a97 100644
--- a/c/src/lib/libbsp/i386/shared/irq/idt.c
+++ b/c/src/lib/libbsp/i386/shared/irq/idt.c
@@ -19,6 +19,16 @@
 #include <rtems/score/cpu.h>
 #include <bsp/irq.h>
 
+/*
+ * This locking is not enough if IDT is changed at runtime
+ * and entry can be changed for vector which is enabled
+ * at change time. But such use is broken anyway.
+ * Protect code only against concurrent changes.
+ * Even that is probably unnecessary if different
+ * entries are changed concurrently.
+ */
+RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_idt_access_lock, "rtems_idt_access_lock" );
+
 static rtems_raw_irq_connect_data* 	raw_irq_table;
 static rtems_raw_irq_connect_data  	default_raw_irq_entry;
 static interrupt_gate_descriptor   	default_idt_entry;
@@ -60,7 +70,7 @@ int i386_set_idt_entry  (const rtems_raw_irq_connect_data* irq)
 {
     interrupt_gate_descriptor* 	idt_entry_tbl;
     unsigned			limit;
-    rtems_interrupt_level       level;
+    rtems_interrupt_lock_context lock_context;
 
     i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
 
@@ -81,14 +91,14 @@ int i386_set_idt_entry  (const rtems_raw_irq_connect_data* irq)
       return 0;
     }
 
-    rtems_interrupt_disable(level);
+    rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
 
     raw_irq_table [irq->idtIndex] = *irq;
     create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
     if (irq->on)
       irq->on(irq);
 
-    rtems_interrupt_enable(level);
+    rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
     return 1;
 }
 
@@ -99,7 +109,7 @@ void _CPU_ISR_install_vector (uint32_t vector,
     interrupt_gate_descriptor* 	idt_entry_tbl;
     unsigned			limit;
     interrupt_gate_descriptor	new;
-    rtems_interrupt_level       level;
+    rtems_interrupt_lock_context lock_context;
 
     i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
 
@@ -109,14 +119,14 @@ void _CPU_ISR_install_vector (uint32_t vector,
     if (vector >= limit) {
       return;
     }
-    rtems_interrupt_disable(level);
+    rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
     * ((unsigned int *) oldHdl) = idt_entry_tbl[vector].low_offsets_bits |
 	(idt_entry_tbl[vector].high_offsets_bits << 16);
 
     create_interrupt_gate_descriptor(&new,  hdl);
     idt_entry_tbl[vector] = new;
 
-    rtems_interrupt_enable(level);
+    rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
 }
 
 int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq)
@@ -143,7 +153,7 @@ int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
 {
     interrupt_gate_descriptor* 	idt_entry_tbl;
     unsigned			limit;
-    rtems_interrupt_level       level;
+    rtems_interrupt_lock_context lock_context;
 
     i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
 
@@ -163,7 +173,7 @@ int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
     if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){
       return 0;
     }
-    rtems_interrupt_disable(level);
+    rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
 
     idt_entry_tbl[irq->idtIndex] = default_idt_entry;
 
@@ -173,7 +183,7 @@ int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
     raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
     raw_irq_table[irq->idtIndex].idtIndex = irq->idtIndex;
 
-    rtems_interrupt_enable(level);
+    rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
 
     return 1;
 }
@@ -185,7 +195,7 @@ int i386_init_idt (rtems_raw_irq_global_settings* config)
 {
     unsigned			limit;
     unsigned 			i;
-    rtems_interrupt_level       level;
+    rtems_interrupt_lock_context lock_context;
     interrupt_gate_descriptor*	idt_entry_tbl;
 
     i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
@@ -203,7 +213,7 @@ int i386_init_idt (rtems_raw_irq_global_settings* config)
     local_settings 		= config;
     default_raw_irq_entry 	= config->defaultRawEntry;
 
-    rtems_interrupt_disable(level);
+    rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
 
     create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl);
 
@@ -218,7 +228,7 @@ int i386_init_idt (rtems_raw_irq_global_settings* config)
 	raw_irq_table[i].off(&raw_irq_table[i]);
       }
     }
-    rtems_interrupt_enable(level);
+    rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
 
     return 1;
 }
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq.c b/c/src/lib/libbsp/i386/shared/irq/irq.c
index 887a120..f4ffd8c 100644
--- a/c/src/lib/libbsp/i386/shared/irq/irq.c
+++ b/c/src/lib/libbsp/i386/shared/irq/irq.c
@@ -23,6 +23,8 @@
 
 #include "elcr.h"
 
+RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_i8259_access_lock, "rtems_i8259_access_lock" );
+
 /*
  * pointer to the mask representing the additionnal irq vectors
  * that must be disabled when a particular entry is activated.
@@ -130,9 +132,9 @@ static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport)
 static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
 {
   unsigned short        mask;
-  rtems_interrupt_level level;
+  rtems_interrupt_lock_context lock_context;
 
-  rtems_interrupt_disable(level);
+  rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
 
   mask = 1 << irqLine;
   i8259a_imr_cache |= mask;
@@ -146,7 +148,7 @@ static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
     BSP_i8259a_irq_update_slave_imr();
   }
 
-  rtems_interrupt_enable(level);
+  rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
 
   return 0;
 }
@@ -161,11 +163,11 @@ static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
 static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine)
 {
   unsigned short        mask;
-  rtems_interrupt_level level;
+  rtems_interrupt_lock_context lock_context;
   uint8_t               isr;
   uint8_t               irr;
 
-  rtems_interrupt_disable(level);
+  rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
 
   mask = 1 << irqLine;
   i8259a_imr_cache &= ~mask;
@@ -186,7 +188,7 @@ static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine)
   if (((isr ^ irr) & mask) != 0)
     printk("i386: isr=%x irr=%x\n", isr, irr);
 
-  rtems_interrupt_enable(level);
+  rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
 
   return 0;
 } /* mask_irq */
@@ -239,11 +241,11 @@ static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
 
 static void compute_i8259_masks_from_prio (void)
 {
-  rtems_interrupt_level level;
+  rtems_interrupt_lock_context lock_context;
   unsigned int i;
   unsigned int j;
 
-  rtems_interrupt_disable(level);
+  rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
 
   /*
    * Always mask at least current interrupt to prevent re-entrance
@@ -260,7 +262,7 @@ static void compute_i8259_masks_from_prio (void)
     }
   }
 
-  rtems_interrupt_enable(level);
+  rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
 }
 
 static inline bool bsp_interrupt_vector_is_valid(rtems_vector_number vector)
@@ -314,6 +316,7 @@ void BSP_dispatch_isr(int vector);
 
 void BSP_dispatch_isr(int vector)
 {
+  rtems_interrupt_lock_context lock_context;
   rtems_i8259_masks in_progress_save = 0;
 
   if (vector < BSP_IRQ_VECTOR_NUMBER) {
@@ -321,6 +324,9 @@ void BSP_dispatch_isr(int vector)
      * Hardware?
      */
     if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+
+      rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
+
       /*
        * See if this is a spurious interrupt.
        */
@@ -335,6 +341,7 @@ void BSP_dispatch_isr(int vector)
           uint8_t isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
           if ((isr & (1 << 7)) == 0) {
             ++spurious_count;
+            rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
             return;
           }
         }
@@ -355,6 +362,8 @@ void BSP_dispatch_isr(int vector)
        * Do not use auto-EOI as some slave PIC do not work correctly.
        */
       BSP_irq_ack_at_i8259a(vector);
+
+      rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
     }
 
     /*
@@ -378,6 +387,9 @@ void BSP_dispatch_isr(int vector)
     RTEMS_COMPILER_MEMORY_BARRIER();
 
     if (vector <= BSP_IRQ_MAX_ON_i8259A) {
+
+      rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
+
       /*
        * Put the mask back but keep this vector masked if the trigger type is
        * level. The driver or a thread level interrupt server needs to enable it
@@ -388,6 +400,8 @@ void BSP_dispatch_isr(int vector)
         BSP_i8259a_irq_update_master_imr();
         BSP_i8259a_irq_update_slave_imr();
       }
+
+      rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
     }
   }
 }
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq_init.c b/c/src/lib/libbsp/i386/shared/irq/irq_init.c
index c401f29..fdf4801 100644
--- a/c/src/lib/libbsp/i386/shared/irq/irq_init.c
+++ b/c/src/lib/libbsp/i386/shared/irq/irq_init.c
@@ -124,7 +124,12 @@ void  rtems_irq_mngt_init(void)
        while(1);
     }
 
-    rtems_interrupt_disable(level);
+    /*
+     * The interrupt management can be initialized only once
+     * during system bootup and that should happen on boot
+     * CPU so there is no need to synchronize with others CPUs.
+     */
+    rtems_interrupt_local_disable(level);
 
     /*
      * Init the complete IDT vector table with defaultRawIrq value
-- 
1.9.1




More information about the devel mailing list