| 
									
										
										
										
											2017-12-19 15:47:00 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |     Copyright (C) 2016-2017 Espressif Shanghai PTE LTD | 
					
						
							|  |  |  |     Copyright (C) 2015 Real Time Engineers Ltd. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All rights reserved | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FreeRTOS is free software; you can redistribute it and/or modify it under | 
					
						
							|  |  |  |     the terms of the GNU General Public License (version 2) as published by the | 
					
						
							|  |  |  |     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*************************************************************************** | 
					
						
							|  |  |  |     >>!   NOTE: The modification to the GPL is included to allow you to     !<< | 
					
						
							|  |  |  |     >>!   distribute a combined work that includes FreeRTOS without being   !<< | 
					
						
							|  |  |  |     >>!   obliged to provide the source code for proprietary components     !<< | 
					
						
							|  |  |  |     >>!   outside of the FreeRTOS kernel.                                   !<< | 
					
						
							|  |  |  | 	*************************************************************************** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY | 
					
						
							|  |  |  |     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
					
						
							|  |  |  |     FOR A PARTICULAR PURPOSE.  Full license text is available on the following | 
					
						
							|  |  |  |     link: http://www.freertos.org/a00114.html
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |   Warning: funky preprocessor hackery ahead. Including these headers will generate two | 
					
						
							|  |  |  |   functions, which names are defined by the preprocessor macros  | 
					
						
							|  |  |  |   PORTMUX_AQUIRE_MUX_FN_NAME and PORTMUX_RELEASE_MUX_FN_NAME. In order to do the compare | 
					
						
							|  |  |  |   and exchange function, they will use whatever PORTMUX_COMPARE_SET_FN_NAME resolves to. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   In some scenarios, this header is included *twice* in portmux_impl.h: one time  | 
					
						
							|  |  |  |   for the 'normal' mux code which uses a compare&exchange routine, another time  | 
					
						
							|  |  |  |   to generate code for a second set of these routines that use a second mux  | 
					
						
							|  |  |  |   (in internal ram) to fake a compare&exchange on a variable in external memory. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool __attribute__((always_inline)) | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles, const char *fnName, int line) { | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) { | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !CONFIG_FREERTOS_UNICORE
 | 
					
						
							|  |  |  | 	uint32_t res; | 
					
						
							|  |  |  | 	portBASE_TYPE coreID, otherCoreID; | 
					
						
							|  |  |  | 	uint32_t ccount_start; | 
					
						
							|  |  |  | 	bool set_timeout = timeout_cycles > portMUX_NO_TIMEOUT; | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 	if (!set_timeout) { | 
					
						
							|  |  |  | 		timeout_cycles = 10000; // Always set a timeout in debug mode
 | 
					
						
							|  |  |  | 		set_timeout = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	if (set_timeout) { // Timeout
 | 
					
						
							|  |  |  | 		RSR(CCOUNT, ccount_start); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 	uint32_t owner = mux->owner; | 
					
						
							|  |  |  | 	if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { | 
					
						
							|  |  |  | 		ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line); | 
					
						
							|  |  |  | 		mux->owner=portMUX_FREE_VAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Spin until we own the core */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	RSR(PRID, coreID); | 
					
						
							|  |  |  | 	/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
 | 
					
						
							|  |  |  | 	   not the 0/1 value returned by xPortGetCoreID() | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	otherCoreID = CORE_ID_XOR_SWAP ^ coreID; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
 | 
					
						
							|  |  |  | 		   CORE_ID_APP: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		   - If portMUX_FREE_VAL, we want to atomically set to 'coreID'. | 
					
						
							|  |  |  | 		   - If "our" coreID, we can drop through immediately. | 
					
						
							|  |  |  | 		   - If "otherCoreID", we spin here. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		res = coreID; | 
					
						
							|  |  |  | 		PORTMUX_COMPARE_SET_FN_NAME(&mux->owner, portMUX_FREE_VAL, &res); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (res != otherCoreID) { | 
					
						
							|  |  |  | 			break; // mux->owner is "our" coreID
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (set_timeout) { | 
					
						
							|  |  |  | 			uint32_t ccount_now; | 
					
						
							|  |  |  | 			RSR(CCOUNT, ccount_now); | 
					
						
							|  |  |  | 			if (ccount_now - ccount_start > (unsigned)timeout_cycles) { | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 				ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line); | 
					
						
							|  |  |  | 				ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */ | 
					
						
							|  |  |  | 	assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */ | 
					
						
							|  |  |  |     assert(mux->count < 0xFF); /* Bad count value implies memory corruption */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now we own it, we can increment the refcount */ | 
					
						
							|  |  |  | 	mux->count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 	if (res==portMUX_FREE_VAL) { //initial lock
 | 
					
						
							|  |  |  | 		mux->lastLockedFn=fnName; | 
					
						
							|  |  |  | 		mux->lastLockedLine=line; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1, | 
					
						
							|  |  |  | 				   mux->lastLockedFn, mux->lastLockedLine, fnName, line); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif /* CONFIG_FREERTOS_PORTMUX_DEBUG */
 | 
					
						
							|  |  |  | #endif /* CONFIG_FREERTOS_UNICORE */
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux, const char *fnName, int line) { | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) { | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !CONFIG_FREERTOS_UNICORE
 | 
					
						
							|  |  |  | 	portBASE_TYPE coreID; | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 	const char *lastLockedFn=mux->lastLockedFn; | 
					
						
							|  |  |  | 	int lastLockedLine=mux->lastLockedLine; | 
					
						
							|  |  |  | 	mux->lastLockedFn=fnName; | 
					
						
							|  |  |  | 	mux->lastLockedLine=line; | 
					
						
							|  |  |  | 	uint32_t owner = mux->owner; | 
					
						
							|  |  |  | 	if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) { | 
					
						
							|  |  |  | 		ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
 | 
					
						
							|  |  |  | 	RSR(PRID, coreID); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 | 
					
						
							|  |  |  | 	if (coreID != mux->owner) { | 
					
						
							|  |  |  | 		ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux); | 
					
						
							|  |  |  | 		ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mux->count--; | 
					
						
							|  |  |  | 	if(mux->count == 0) { | 
					
						
							|  |  |  | 		mux->owner = portMUX_FREE_VAL; | 
					
						
							| 
									
										
										
										
											2018-07-30 14:24:03 +10:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		assert(mux->count < 0x100); // Indicates memory corruption
 | 
					
						
							| 
									
										
										
										
											2017-12-19 15:47:00 +08:00
										 |  |  | #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
 | 
					
						
							|  |  |  | 		ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-07-30 14:24:03 +10:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-19 15:47:00 +08:00
										 |  |  | #endif //!CONFIG_FREERTOS_UNICORE
 | 
					
						
							|  |  |  | } |