spl.c (3787B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: spl.c 8 * Purpose: Interrupt Blocking 9 */ 10 #if defined(LINUX) || defined(linux) || defined(__linux__) 11 #define _XOPEN_SOURCE 600 12 #endif 13 #include <sys/types.h> 14 #include <signal.h> 15 #include <assert.h> 16 #include <sal/core/sync.h> 17 #include <pthread.h> 18 19 /* 20 * To improve spl lock performance, pthread_mutex_lock/pthread_mutex_unlock 21 * is used by default. 22 * Define SAL_SPL_USE_SAL_MUTEX to use sal_mutex on the spl lock. 23 */ 24 #ifdef SAL_SPL_USE_SAL_MUTEX 25 static sal_mutex_t spl_mutex; 26 #define SAL_SPL_LOCK_INIT(m) m = sal_mutex_create("spl mutex") 27 #define SAL_SPL_LOCK(m) sal_mutex_take(m, sal_mutex_FOREVER) 28 #define SAL_SPL_UNLOCK(m) sal_mutex_give(m) 29 #else 30 static pthread_mutex_t spl_mutex; 31 #define SAL_SPL_LOCK_INIT(m) \ 32 do {\ 33 pthread_mutexattr_t attr;\ 34 pthread_mutexattr_init(&attr);\ 35 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\ 36 pthread_mutex_init(&m, &attr);\ 37 } while(0) 38 #define SAL_SPL_LOCK(m) pthread_mutex_lock(&m) 39 #define SAL_SPL_UNLOCK(m) pthread_mutex_unlock(&m) 40 #endif /* SAL_SPL_USE_SAL_MUTEX */ 41 42 static int spl_level; 43 44 /* 45 * Function: 46 * sal_spl_init 47 * Purpose: 48 * Initialize the synchronization portion of the SAL 49 * Returns: 50 * 0 on success, -1 on failure 51 */ 52 53 int 54 sal_spl_init(void) 55 { 56 /* Initialize spl */ 57 SAL_SPL_LOCK_INIT(spl_mutex); 58 spl_level = 0; 59 60 return 0; 61 } 62 63 /* 64 * Function: 65 * sal_spl 66 * Purpose: 67 * Set interrupt level. 68 * Parameters: 69 * level - interrupt level to set. 70 * Returns: 71 * Value of interrupt level in effect prior to the call. 72 * Notes: 73 * Used most often to restore interrupts blocked by sal_splhi. 74 */ 75 76 int 77 sal_spl(int level) 78 { 79 #ifdef SAL_SPL_NO_PREEMPT 80 struct sched_param param; 81 int policy; 82 83 if (pthread_getschedparam(pthread_self(), &policy, ¶m) == 0) { 84 /* Interrupt thread uses SCHED_RR and should be left alone */ 85 if (policy != SCHED_RR) { 86 /* setting sched_priority to 0 will only change the real time priority 87 of the thread. For a non real time thread it should be 0. This is 88 very Linux specific. 89 */ 90 param.sched_priority = 0; 91 pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); 92 } 93 } 94 #endif 95 assert(level == spl_level); 96 spl_level--; 97 SAL_SPL_UNLOCK(spl_mutex); 98 return 0; 99 } 100 101 /* 102 * Function: 103 * sal_splhi 104 * Purpose: 105 * Set interrupt mask to highest level. 106 * Parameters: 107 * None 108 * Returns: 109 * Value of interrupt level in effect prior to the call. 110 */ 111 112 int 113 sal_splhi(void) 114 { 115 #ifdef SAL_SPL_NO_PREEMPT 116 struct sched_param param; 117 int policy; 118 119 if (pthread_getschedparam(pthread_self(), &policy, ¶m) == 0) { 120 /* Interrupt thread uses SCHED_RR and should be left alone */ 121 if (policy != SCHED_RR) { 122 param.sched_priority = 90; 123 pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); 124 } 125 } 126 #endif 127 SAL_SPL_LOCK(spl_mutex); 128 return ++spl_level; 129 } 130 131 /* 132 * Function: 133 * sal_int_context 134 * Purpose: 135 * Return TRUE if running in interrupt context. 136 * Parameters: 137 * None 138 * Returns: 139 * Boolean 140 */ 141 142 int 143 sal_int_context(void) 144 { 145 /* Must be provided by the virtual interrupt controller */ 146 extern int intr_int_context() __attribute__((weak)); 147 148 if (intr_int_context) { 149 return intr_int_context(); 150 } else { 151 return 0; 152 } 153 } 154 155 /* 156 * Function: 157 * sal_no_sleep 158 * Purpose: 159 * Return TRUE if current context cannot sleep. 160 * Parameters: 161 * None 162 * Returns: 163 * Boolean 164 */ 165 166 int 167 sal_no_sleep(void) 168 { 169 return 0; 170 }