]> granicus.if.org Git - esp-idf/commitdiff
crosscore_int: add support for FREQ_SWITCH event
authorIvan Grokhotkov <ivan@espressif.com>
Mon, 21 Aug 2017 14:29:08 +0000 (22:29 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Wed, 18 Oct 2017 04:31:38 +0000 (12:31 +0800)
components/esp32/crosscore_int.c
components/esp32/include/esp_crosscore_int.h

index 0d5ccb35f7cae9dc70b017b7a0eb330ae57bc8f0..4a57a2b197a2b4f2c6a455b6440d7fddef287f9e 100644 (file)
 #include "freertos/portmacro.h"
 
 
-#define REASON_YIELD (1<<0)
+#define REASON_YIELD            BIT(0)
+#define REASON_FREQ_SWITCH      BIT(1)
 
-static portMUX_TYPE reasonSpinlock = portMUX_INITIALIZER_UNLOCKED;
+static portMUX_TYPE reason_spinlock = portMUX_INITIALIZER_UNLOCKED;
 static volatile uint32_t reason[ portNUM_PROCESSORS ];
 
-
 /*
 ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but
 the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that.
 */
+static void esp_crosscore_isr_handle_yield()
+{
+    portYIELD_FROM_ISR();
+}
+
 static void IRAM_ATTR esp_crosscore_isr(void *arg) {
-    uint32_t myReasonVal;
+    uint32_t my_reason_val;
     //A pointer to the correct reason array item is passed to this ISR.
-    volatile uint32_t *myReason=arg;
+    volatile uint32_t *my_reason=arg;
 
     //Clear the interrupt first.
     if (xPortGetCoreID()==0) {
@@ -56,43 +61,59 @@ static void IRAM_ATTR esp_crosscore_isr(void *arg) {
         DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0);
     }
     //Grab the reason and clear it.
-    portENTER_CRITICAL(&reasonSpinlock);
-    myReasonVal=*myReason;
-    *myReason=0;
-    portEXIT_CRITICAL(&reasonSpinlock);
+    portENTER_CRITICAL(&reason_spinlock);
+    my_reason_val=*my_reason;
+    *my_reason=0;
+    portEXIT_CRITICAL(&reason_spinlock);
 
     //Check what we need to do.
-    if (myReasonVal&REASON_YIELD) {
-        portYIELD_FROM_ISR();
+    if (my_reason_val & REASON_YIELD) {
+        esp_crosscore_isr_handle_yield();
+    }
+    if (my_reason_val & REASON_FREQ_SWITCH) {
+        /* Nothing to do here; the frequency switch event was already
+         * handled by a hook in xtensa_vectors.S. Could be used in the future
+         * to allow DFS features without the extra latency of the ISR hook.
+         */
     }
 }
 
 //Initialize the crosscore interrupt on this core. Call this once
 //on each active core.
 void esp_crosscore_int_init() {
-    portENTER_CRITICAL(&reasonSpinlock);
+    portENTER_CRITICAL(&reason_spinlock);
     reason[xPortGetCoreID()]=0;
-    portEXIT_CRITICAL(&reasonSpinlock);
+    portEXIT_CRITICAL(&reason_spinlock);
     esp_err_t err;
     if (xPortGetCoreID()==0) {
-        err = esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
+        err = esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[0], NULL);
     } else {
-        err = esp_intr_alloc(ETS_FROM_CPU_INTR1_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
+        err = esp_intr_alloc(ETS_FROM_CPU_INTR1_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[1], NULL);
     }
     assert(err == ESP_OK);
 }
 
-void IRAM_ATTR esp_crosscore_int_send_yield(int coreId) {
-    assert(coreId<portNUM_PROCESSORS);
+static void IRAM_ATTR esp_crosscore_int_send(int core_id, uint32_t reason_mask) {
+    assert(core_id<portNUM_PROCESSORS);
     //Mark the reason we interrupt the other CPU
-    portENTER_CRITICAL(&reasonSpinlock);
-    reason[coreId]|=REASON_YIELD;
-    portEXIT_CRITICAL(&reasonSpinlock);
+    portENTER_CRITICAL(&reason_spinlock);
+    reason[core_id] |= reason_mask;
+    portEXIT_CRITICAL(&reason_spinlock);
     //Poke the other CPU.
-    if (coreId==0) {
+    if (core_id==0) {
         DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);
     } else {
         DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, DPORT_CPU_INTR_FROM_CPU_1);
     }
 }
 
+void IRAM_ATTR esp_crosscore_int_send_yield(int core_id)
+{
+    esp_crosscore_int_send(core_id, REASON_YIELD);
+}
+
+void IRAM_ATTR esp_crosscore_int_send_freq_switch(int core_id)
+{
+    esp_crosscore_int_send(core_id, REASON_FREQ_SWITCH);
+}
+
index 0e4b2b83853514176ed08795a3dd1915c5597bcb..2f1c5b3becf07962fc2cd0eae101160766d8d9e2 100644 (file)
@@ -35,8 +35,20 @@ void esp_crosscore_int_init();
  * This is used internally by FreeRTOS in multicore mode
  * and should not be called by the user.
  *
- * @param coreID Core that should do the yielding
+ * @param core_id Core that should do the yielding
  */
-void esp_crosscore_int_send_yield(int coreId);
+void esp_crosscore_int_send_yield(int core_id);
 
-#endif
\ No newline at end of file
+
+/**
+ * Send an interrupt to a CPU indicating it should update its
+ * CCOMPARE1 value due to a frequency switch.
+ *
+ * This is used internally when dynamic frequency switching is
+ * enabled, and should not be called from application code.
+ *
+ * @param core_id Core that should update its CCOMPARE1 value
+ */
+void esp_crosscore_int_send_freq_switch(int core_id);
+
+#endif