/ components / esp_eth / src / esp_eth_mac_esp32.c
esp_eth_mac_esp32.c
  1  // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
  2  //
  3  // Licensed under the Apache License, Version 2.0 (the "License");
  4  // you may not use this file except in compliance with the License.
  5  // You may obtain a copy of the License at
  6  //
  7  //     http://www.apache.org/licenses/LICENSE-2.0
  8  //
  9  // Unless required by applicable law or agreed to in writing, software
 10  // distributed under the License is distributed on an "AS IS" BASIS,
 11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  // See the License for the specific language governing permissions and
 13  // limitations under the License.
 14  #include <string.h>
 15  #include <stdlib.h>
 16  #include <sys/cdefs.h>
 17  #include "driver/periph_ctrl.h"
 18  #include "driver/gpio.h"
 19  #include "esp_attr.h"
 20  #include "esp_log.h"
 21  #include "esp_eth.h"
 22  #include "esp_pm.h"
 23  #include "esp_system.h"
 24  #include "esp_heap_caps.h"
 25  #include "esp_intr_alloc.h"
 26  #include "freertos/FreeRTOS.h"
 27  #include "freertos/task.h"
 28  #include "freertos/semphr.h"
 29  #include "hal/cpu_hal.h"
 30  #include "hal/emac.h"
 31  #include "soc/soc.h"
 32  #include "sdkconfig.h"
 33  #include "esp_rom_gpio.h"
 34  #include "esp_rom_sys.h"
 35  
 36  static const char *TAG = "emac_esp32";
 37  #define MAC_CHECK(a, str, goto_tag, ret_value, ...)                               \
 38      do                                                                            \
 39      {                                                                             \
 40          if (!(a))                                                                 \
 41          {                                                                         \
 42              ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 43              ret = ret_value;                                                      \
 44              goto goto_tag;                                                        \
 45          }                                                                         \
 46      } while (0)
 47  
 48  #define PHY_OPERATION_TIMEOUT_US (1000)
 49  
 50  #define FLOW_CONTROL_LOW_WATER_MARK (CONFIG_ETH_DMA_RX_BUFFER_NUM / 3)
 51  #define FLOW_CONTROL_HIGH_WATER_MARK (FLOW_CONTROL_LOW_WATER_MARK * 2)
 52  
 53  typedef struct {
 54      esp_eth_mac_t parent;
 55      esp_eth_mediator_t *eth;
 56      emac_hal_context_t hal;
 57      intr_handle_t intr_hdl;
 58      TaskHandle_t rx_task_hdl;
 59      uint32_t sw_reset_timeout_ms;
 60      uint32_t frames_remain;
 61      uint32_t free_rx_descriptor;
 62      uint32_t flow_control_high_water_mark;
 63      uint32_t flow_control_low_water_mark;
 64      int smi_mdc_gpio_num;
 65      int smi_mdio_gpio_num;
 66      uint8_t addr[6];
 67      uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM];
 68      uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM];
 69      bool isr_need_yield;
 70      bool flow_ctrl_enabled; // indicates whether the user want to do flow control
 71      bool do_flow_ctrl;  // indicates whether we need to do software flow control
 72  #ifdef CONFIG_PM_ENABLE
 73      esp_pm_lock_handle_t pm_lock;
 74  #endif
 75  } emac_esp32_t;
 76  
 77  static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
 78  {
 79      esp_err_t ret = ESP_OK;
 80      MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
 81      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
 82      emac->eth = eth;
 83      return ESP_OK;
 84  err:
 85      return ret;
 86  }
 87  
 88  static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
 89  {
 90      esp_err_t ret = ESP_OK;
 91      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
 92      MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
 93      emac_hal_set_phy_data(&emac->hal, reg_value);
 94      emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true);
 95      /* polling the busy flag */
 96      uint32_t to = 0;
 97      bool busy = true;
 98      do {
 99          esp_rom_delay_us(100);
100          busy = emac_hal_is_mii_busy(&emac->hal);
101          to += 100;
102      } while (busy && to < PHY_OPERATION_TIMEOUT_US);
103      MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
104      return ESP_OK;
105  err:
106      return ret;
107  }
108  
109  static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
110  {
111      esp_err_t ret = ESP_OK;
112      MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
113      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
114      MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
115      emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false);
116      /* polling the busy flag */
117      uint32_t to = 0;
118      bool busy = true;
119      do {
120          esp_rom_delay_us(100);
121          busy = emac_hal_is_mii_busy(&emac->hal);
122          to += 100;
123      } while (busy && to < PHY_OPERATION_TIMEOUT_US);
124      MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
125      /* Store value */
126      *reg_value = emac_hal_get_phy_data(&emac->hal);
127      return ESP_OK;
128  err:
129      return ret;
130  }
131  
132  static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
133  {
134      esp_err_t ret = ESP_OK;
135      MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
136      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
137      memcpy(emac->addr, addr, 6);
138      emac_hal_set_address(&emac->hal, emac->addr);
139      return ESP_OK;
140  err:
141      return ret;
142  }
143  
144  static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
145  {
146      esp_err_t ret = ESP_OK;
147      MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
148      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
149      memcpy(addr, emac->addr, 6);
150      return ESP_OK;
151  err:
152      return ret;
153  }
154  
155  static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link)
156  {
157      esp_err_t ret = ESP_OK;
158      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
159      switch (link) {
160      case ETH_LINK_UP:
161          MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL);
162          emac_hal_start(&emac->hal);
163          break;
164      case ETH_LINK_DOWN:
165          MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL);
166          emac_hal_stop(&emac->hal);
167          break;
168      default:
169          MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
170          break;
171      }
172      return ESP_OK;
173  err:
174      return ret;
175  }
176  
177  static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
178  {
179      esp_err_t ret = ESP_OK;
180      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
181      switch (speed) {
182      case ETH_SPEED_10M:
183          emac_hal_set_speed(&emac->hal, EMAC_SPEED_10M);
184          ESP_LOGD(TAG, "working in 10Mbps");
185          break;
186      case ETH_SPEED_100M:
187          emac_hal_set_speed(&emac->hal, EMAC_SPEED_100M);
188          ESP_LOGD(TAG, "working in 100Mbps");
189          break;
190      default:
191          MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
192          break;
193      }
194      return ESP_OK;
195  err:
196      return ret;
197  }
198  
199  static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
200  {
201      esp_err_t ret = ESP_OK;
202      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
203      switch (duplex) {
204      case ETH_DUPLEX_HALF:
205          emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_HALF);
206          ESP_LOGD(TAG, "working in half duplex");
207          break;
208      case ETH_DUPLEX_FULL:
209          emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_FULL);
210          ESP_LOGD(TAG, "working in full duplex");
211          break;
212      default:
213          MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
214          break;
215      }
216      return ESP_OK;
217  err:
218      return ret;
219  }
220  
221  static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable)
222  {
223      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
224      emac_hal_set_promiscuous(&emac->hal, enable);
225      return ESP_OK;
226  }
227  
228  static esp_err_t emac_esp32_enable_flow_ctrl(esp_eth_mac_t *mac, bool enable)
229  {
230      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
231      emac->flow_ctrl_enabled = enable;
232      return ESP_OK;
233  }
234  
235  static esp_err_t emac_esp32_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t ability)
236  {
237      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
238      // we want to enable flow control, and peer does support pause function
239      // then configure the MAC layer to enable flow control feature
240      if (emac->flow_ctrl_enabled && ability) {
241          emac_hal_enable_flow_ctrl(&emac->hal, true);
242          emac->do_flow_ctrl = true;
243      } else {
244          emac_hal_enable_flow_ctrl(&emac->hal, false);
245          emac->do_flow_ctrl = false;
246          ESP_LOGD(TAG, "Flow control not enabled for the link");
247      }
248      return ESP_OK;
249  }
250  
251  static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
252  {
253      esp_err_t ret = ESP_OK;
254      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
255      uint32_t sent_len = emac_hal_transmit_frame(&emac->hal, buf, length);
256      MAC_CHECK(sent_len == length, "insufficient TX buffer size", err, ESP_ERR_INVALID_SIZE);
257      return ESP_OK;
258  err:
259      return ret;
260  }
261  
262  static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
263  {
264      esp_err_t ret = ESP_OK;
265      uint32_t expected_len = *length;
266      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
267      MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
268      uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, expected_len, &emac->frames_remain, &emac->free_rx_descriptor);
269      /* we need to check the return value in case the buffer size is not enough */
270      ESP_LOGD(TAG, "receive len= %d", receive_len);
271      MAC_CHECK(expected_len >= receive_len, "received buffer longer than expected", err, ESP_ERR_INVALID_SIZE);
272      *length = receive_len;
273      return ESP_OK;
274  err:
275      *length = expected_len;
276      return ret;
277  }
278  
279  static void emac_esp32_rx_task(void *arg)
280  {
281      emac_esp32_t *emac = (emac_esp32_t *)arg;
282      uint8_t *buffer = NULL;
283      uint32_t length = 0;
284      while (1) {
285          // block indefinitely until got notification from underlay event
286          ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
287          do {
288              length = ETH_MAX_PACKET_SIZE;
289              buffer = malloc(length);
290              if (!buffer) {
291                  ESP_LOGE(TAG, "no mem for receive buffer");
292              } else if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
293                  /* pass the buffer to stack (e.g. TCP/IP layer) */
294                  if (length) {
295                      emac->eth->stack_input(emac->eth, buffer, length);
296                  } else {
297                      free(buffer);
298                  }
299              } else {
300                  free(buffer);
301              }
302              // we need to do extra checking of remained frames in case there are no unhandled frames left, but pause frame is still undergoing
303              if ((emac->free_rx_descriptor < emac->flow_control_low_water_mark) && emac->do_flow_ctrl && emac->frames_remain) {
304                  emac_hal_send_pause_frame(&emac->hal, true);
305              } else if ((emac->free_rx_descriptor > emac->flow_control_high_water_mark) || !emac->frames_remain) {
306                  emac_hal_send_pause_frame(&emac->hal, false);
307              }
308          } while (emac->frames_remain);
309      }
310      vTaskDelete(NULL);
311  }
312  
313  static void emac_esp32_init_smi_gpio(emac_esp32_t *emac)
314  {
315      if (emac->smi_mdc_gpio_num >= 0) {
316          /* Setup SMI MDC GPIO */
317          gpio_set_direction(emac->smi_mdc_gpio_num, GPIO_MODE_OUTPUT);
318          esp_rom_gpio_connect_out_signal(emac->smi_mdc_gpio_num, EMAC_MDC_O_IDX, false, false);
319          PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdc_gpio_num], PIN_FUNC_GPIO);
320      }
321      if (emac->smi_mdio_gpio_num >= 0) {
322          /* Setup SMI MDIO GPIO */
323          gpio_set_direction(emac->smi_mdio_gpio_num, GPIO_MODE_INPUT_OUTPUT);
324          esp_rom_gpio_connect_out_signal(emac->smi_mdio_gpio_num, EMAC_MDO_O_IDX, false, false);
325          esp_rom_gpio_connect_in_signal(emac->smi_mdio_gpio_num, EMAC_MDI_I_IDX, false);
326          PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdio_gpio_num], PIN_FUNC_GPIO);
327      }
328  }
329  
330  static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
331  {
332      esp_err_t ret = ESP_OK;
333      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
334      esp_eth_mediator_t *eth = emac->eth;
335      /* enable peripheral clock */
336      periph_module_enable(PERIPH_EMAC_MODULE);
337      /* init clock, config gpio, etc */
338      emac_hal_lowlevel_init(&emac->hal);
339      /* init gpio used by smi interface */
340      emac_esp32_init_smi_gpio(emac);
341      MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
342      /* software reset */
343      emac_hal_reset(&emac->hal);
344      uint32_t to = 0;
345      for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
346          if (emac_hal_is_reset_done(&emac->hal)) {
347              break;
348          }
349          vTaskDelay(pdMS_TO_TICKS(10));
350      }
351      MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
352      /* set smi clock */
353      emac_hal_set_csr_clock_range(&emac->hal);
354      /* reset descriptor chain */
355      emac_hal_reset_desc_chain(&emac->hal);
356      /* init mac registers by default */
357      emac_hal_init_mac_default(&emac->hal);
358      /* init dma registers by default */
359      emac_hal_init_dma_default(&emac->hal);
360      /* get emac address from efuse */
361      MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
362      /* set MAC address to emac register */
363      emac_hal_set_address(&emac->hal, emac->addr);
364  #ifdef CONFIG_PM_ENABLE
365      esp_pm_lock_acquire(emac->pm_lock);
366  #endif
367      return ESP_OK;
368  err:
369      eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
370      periph_module_disable(PERIPH_EMAC_MODULE);
371      return ret;
372  }
373  
374  static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
375  {
376      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
377      esp_eth_mediator_t *eth = emac->eth;
378  #ifdef CONFIG_PM_ENABLE
379      esp_pm_lock_release(emac->pm_lock);
380  #endif
381      emac_hal_stop(&emac->hal);
382      eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
383      periph_module_disable(PERIPH_EMAC_MODULE);
384      return ESP_OK;
385  }
386  
387  static esp_err_t emac_esp32_start(esp_eth_mac_t *mac)
388  {
389      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
390      emac_hal_start(&emac->hal);
391      return ESP_OK;
392  }
393  
394  static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac)
395  {
396      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
397      emac_hal_stop(&emac->hal);
398      return ESP_OK;
399  }
400  
401  static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
402  {
403      emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
404      esp_intr_free(emac->intr_hdl);
405  #ifdef CONFIG_PM_ENABLE
406      if (emac->pm_lock) {
407          esp_pm_lock_delete(emac->pm_lock);
408      }
409  #endif
410      vTaskDelete(emac->rx_task_hdl);
411      int i = 0;
412      for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
413          free(emac->hal.rx_buf[i]);
414      }
415      for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
416          free(emac->hal.tx_buf[i]);
417      }
418      free(emac->hal.descriptors);
419      free(emac);
420      return ESP_OK;
421  }
422  
423  // To achieve a better performance, we put the ISR always in IRAM
424  IRAM_ATTR void emac_esp32_isr_handler(void *args)
425  {
426      emac_hal_context_t *hal = (emac_hal_context_t *)args;
427      emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
428      emac_hal_isr(args);
429      if (emac->isr_need_yield) {
430          emac->isr_need_yield = false;
431          portYIELD_FROM_ISR();
432      }
433  }
434  
435  esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
436  {
437      esp_err_t ret_code = ESP_OK;
438      esp_eth_mac_t *ret = NULL;
439      void *descriptors = NULL;
440      emac_esp32_t *emac = NULL;
441      MAC_CHECK(config, "can't set mac config to null", err, NULL);
442      if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
443          emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
444      } else {
445          emac = calloc(1, sizeof(emac_esp32_t));
446      }
447      MAC_CHECK(emac, "calloc emac failed", err, NULL);
448      /* alloc memory for ethernet dma descriptor */
449      uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
450                           CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
451      descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
452      MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL);
453      int i = 0;
454      /* alloc memory for ethernet dma buffer */
455      for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
456          emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
457          if (!(emac->rx_buf[i])) {
458              goto err;
459          }
460      }
461      for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
462          emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
463          if (!(emac->tx_buf[i])) {
464              goto err;
465          }
466      }
467      /* initialize hal layer driver */
468      emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
469      emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
470      emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num;
471      emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num;
472      emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK;
473      emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK;
474      emac->parent.set_mediator = emac_esp32_set_mediator;
475      emac->parent.init = emac_esp32_init;
476      emac->parent.deinit = emac_esp32_deinit;
477      emac->parent.start = emac_esp32_start;
478      emac->parent.stop = emac_esp32_stop;
479      emac->parent.del = emac_esp32_del;
480      emac->parent.write_phy_reg = emac_esp32_write_phy_reg;
481      emac->parent.read_phy_reg = emac_esp32_read_phy_reg;
482      emac->parent.set_addr = emac_esp32_set_addr;
483      emac->parent.get_addr = emac_esp32_get_addr;
484      emac->parent.set_speed = emac_esp32_set_speed;
485      emac->parent.set_duplex = emac_esp32_set_duplex;
486      emac->parent.set_link = emac_esp32_set_link;
487      emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
488      emac->parent.set_peer_pause_ability = emac_esp32_set_peer_pause_ability;
489      emac->parent.enable_flow_ctrl = emac_esp32_enable_flow_ctrl;
490      emac->parent.transmit = emac_esp32_transmit;
491      emac->parent.receive = emac_esp32_receive;
492      /* Interrupt configuration */
493      if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
494          ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM,
495                                    emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl));
496      } else {
497          ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0,
498                                    emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl));
499      }
500      MAC_CHECK(ret_code == ESP_OK, "alloc emac interrupt failed", err, NULL);
501  #ifdef CONFIG_PM_ENABLE
502      MAC_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK,
503                "create pm lock failed", err, NULL);
504  #endif
505      /* create rx task */
506      BaseType_t core_num = tskNO_AFFINITY;
507      if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) {
508          core_num = cpu_hal_get_core_id();
509      }
510      BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
511                             config->rx_task_prio, &emac->rx_task_hdl, core_num);
512      MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL);
513      return &(emac->parent);
514  
515  err:
516      if (emac) {
517          if (emac->rx_task_hdl) {
518              vTaskDelete(emac->rx_task_hdl);
519          }
520          if (emac->intr_hdl) {
521              esp_intr_free(emac->intr_hdl);
522          }
523          for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
524              free(emac->tx_buf[i]);
525          }
526          for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
527              free(emac->rx_buf[i]);
528          }
529  #ifdef CONFIG_PM_ENABLE
530          if (emac->pm_lock) {
531              esp_pm_lock_delete(emac->pm_lock);
532          }
533  #endif
534          free(emac);
535      }
536      if (descriptors) {
537          free(descriptors);
538      }
539      return ret;
540  }
541  
542  IRAM_ATTR void emac_hal_rx_complete_cb(void *arg)
543  {
544      emac_hal_context_t *hal = (emac_hal_context_t *)arg;
545      emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
546      BaseType_t high_task_wakeup;
547      /* notify receive task */
548      vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
549      if (high_task_wakeup == pdTRUE) {
550          emac->isr_need_yield = true;
551      }
552  }
553  
554  IRAM_ATTR void emac_hal_rx_unavail_cb(void *arg)
555  {
556      emac_hal_context_t *hal = (emac_hal_context_t *)arg;
557      emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
558      BaseType_t high_task_wakeup;
559      /* notify receive task */
560      vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
561      if (high_task_wakeup == pdTRUE) {
562          emac->isr_need_yield = true;
563      }
564  }
565  
566  IRAM_ATTR void emac_hal_rx_early_cb(void *arg)
567  {
568      emac_hal_context_t *hal = (emac_hal_context_t *)arg;
569      emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
570      BaseType_t high_task_wakeup;
571      /* notify receive task */
572      vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
573      if (high_task_wakeup == pdTRUE) {
574          emac->isr_need_yield = true;
575      }
576  }