esp_eth.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // Copyright 2019-2021 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 <sys/cdefs.h>
  15. #include <stdatomic.h>
  16. #include "esp_log.h"
  17. #include "esp_check.h"
  18. #include "esp_eth.h"
  19. #include "esp_event.h"
  20. #include "esp_heap_caps.h"
  21. #include "esp_timer.h"
  22. #include "soc/soc.h" // TODO: for esp_eth_ioctl API compatibility reasons, will be removed with next major release
  23. #include "freertos/FreeRTOS.h"
  24. #include "freertos/task.h"
  25. static const char *TAG = "esp_eth";
  26. ESP_EVENT_DEFINE_BASE(ETH_EVENT);
  27. typedef enum {
  28. ESP_ETH_FSM_STOP,
  29. ESP_ETH_FSM_START
  30. } esp_eth_fsm_t;
  31. /**
  32. * @brief The Ethernet driver mainly consists of PHY, MAC and
  33. * the mediator who will handle the request/response from/to MAC, PHY and Users.
  34. * Ethernet driver adopts an OS timer to check the link status periodically.
  35. * This structure preserves some important Ethernet attributes (e.g. speed, duplex, link).
  36. * Function stack_input is the channel which set by user, it will deliver all received packets.
  37. * If stack_input is set to NULL, then all received packets will be passed to tcp/ip stack.
  38. * on_lowlevel_init_done and on_lowlevel_deinit_done are callbacks set by user.
  39. * In the callback, user can do any low level operations (e.g. enable/disable crystal clock).
  40. */
  41. typedef struct {
  42. esp_eth_mediator_t mediator;
  43. esp_eth_phy_t *phy;
  44. esp_eth_mac_t *mac;
  45. esp_timer_handle_t check_link_timer;
  46. uint32_t check_link_period_ms;
  47. eth_speed_t speed;
  48. eth_duplex_t duplex;
  49. eth_link_t link;
  50. atomic_int ref_count;
  51. void *priv;
  52. _Atomic esp_eth_fsm_t fsm;
  53. esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv);
  54. esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle);
  55. esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle);
  56. esp_err_t (*customized_read_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value);
  57. esp_err_t (*customized_write_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
  58. } esp_eth_driver_t;
  59. ////////////////////////////////Mediator Functions////////////////////////////////////////////
  60. // Following functions are owned by mediator, which will get invoked by MAC or PHY.
  61. // Mediator functions need to find the right actor (MAC, PHY or user) to perform the operation.
  62. // So in the head of mediator function, we have to get the esp_eth_driver_t pointer.
  63. // With this pointer, we could deliver the task to the real actor (MAC, PHY or user).
  64. // This might sound excessive, but is helpful to separate the PHY with MAC (they can not contact with each other directly).
  65. // For more details, please refer to WiKi. https://en.wikipedia.org/wiki/Mediator_pattern
  66. //////////////////////////////////////////////////////////////////////////////////////////////
  67. static esp_err_t eth_phy_reg_read(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
  68. {
  69. esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
  70. // invoking user customized PHY IO function if necessary
  71. if (eth_driver->customized_read_phy_reg) {
  72. return eth_driver->customized_read_phy_reg(eth_driver, phy_addr, phy_reg, reg_value);
  73. }
  74. // by default, PHY device is managed by MAC's SMI interface
  75. esp_eth_mac_t *mac = eth_driver->mac;
  76. return mac->read_phy_reg(mac, phy_addr, phy_reg, reg_value);
  77. }
  78. static esp_err_t eth_phy_reg_write(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
  79. {
  80. esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
  81. // invoking user customized PHY IO function if necessary
  82. if (eth_driver->customized_write_phy_reg) {
  83. return eth_driver->customized_write_phy_reg(eth_driver, phy_addr, phy_reg, reg_value);
  84. }
  85. // by default, PHY device is managed by MAC's SMI interface
  86. esp_eth_mac_t *mac = eth_driver->mac;
  87. return mac->write_phy_reg(mac, phy_addr, phy_reg, reg_value);
  88. }
  89. static esp_err_t eth_stack_input(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length)
  90. {
  91. esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
  92. if (eth_driver->stack_input) {
  93. return eth_driver->stack_input((esp_eth_handle_t)eth_driver, buffer, length, eth_driver->priv);
  94. }
  95. // No stack input path has been installed, just drop the incoming packets
  96. free(buffer);
  97. return ESP_OK;
  98. }
  99. static esp_err_t eth_on_state_changed(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args)
  100. {
  101. esp_err_t ret = ESP_OK;
  102. esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
  103. esp_eth_mac_t *mac = eth_driver->mac;
  104. switch (state) {
  105. case ETH_STATE_LLINIT: {
  106. if (eth_driver->on_lowlevel_init_done) {
  107. ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_init_done(eth_driver), err, TAG, "extra lowlevel init failed");
  108. }
  109. break;
  110. }
  111. case ETH_STATE_DEINIT: {
  112. if (eth_driver->on_lowlevel_deinit_done) {
  113. ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_deinit_done(eth_driver), err, TAG, "extra lowlevel deinit failed");
  114. }
  115. break;
  116. }
  117. case ETH_STATE_LINK: {
  118. eth_link_t link = (eth_link_t)args;
  119. ESP_GOTO_ON_ERROR(mac->set_link(mac, link), err, TAG, "ethernet mac set link failed");
  120. eth_driver->link = link;
  121. if (link == ETH_LINK_UP) {
  122. ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &eth_driver, sizeof(esp_eth_driver_t *), 0), err,
  123. TAG, "send ETHERNET_EVENT_CONNECTED event failed");
  124. } else if (link == ETH_LINK_DOWN) {
  125. ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &eth_driver, sizeof(esp_eth_driver_t *), 0), err,
  126. TAG, "send ETHERNET_EVENT_DISCONNECTED event failed");
  127. }
  128. break;
  129. }
  130. case ETH_STATE_SPEED: {
  131. eth_speed_t speed = (eth_speed_t)args;
  132. ESP_GOTO_ON_ERROR(mac->set_speed(mac, speed), err, TAG, "ethernet mac set speed failed");
  133. eth_driver->speed = speed;
  134. break;
  135. }
  136. case ETH_STATE_DUPLEX: {
  137. eth_duplex_t duplex = (eth_duplex_t)args;
  138. ESP_GOTO_ON_ERROR(mac->set_duplex(mac, duplex), err, TAG, "ethernet mac set duplex failed");
  139. eth_driver->duplex = duplex;
  140. break;
  141. }
  142. case ETH_STATE_PAUSE: {
  143. uint32_t peer_pause_ability = (uint32_t)args;
  144. ESP_GOTO_ON_ERROR(mac->set_peer_pause_ability(mac, peer_pause_ability), err, TAG, "ethernet mac set peer pause ability failed");
  145. break;
  146. }
  147. default:
  148. ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown ethernet state: %d", state);
  149. break;
  150. }
  151. err:
  152. return ret;
  153. }
  154. static void eth_check_link_timer_cb(void *args)
  155. {
  156. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)args;
  157. esp_eth_phy_t *phy = eth_driver->phy;
  158. phy->get_link(phy);
  159. }
  160. ////////////////////////////////User face APIs////////////////////////////////////////////////
  161. // User has to pass the handle of Ethernet driver to each API.
  162. // Different Ethernet driver instance is identified with a unique handle.
  163. // It's helpful for us to support multiple Ethernet port on ESP32.
  164. //////////////////////////////////////////////////////////////////////////////////////////////
  165. esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl)
  166. {
  167. esp_err_t ret = ESP_OK;
  168. esp_eth_mac_t *mac = NULL;
  169. esp_eth_phy_t *phy = NULL;
  170. esp_eth_driver_t *eth_driver = NULL;
  171. ESP_GOTO_ON_FALSE(config && out_hdl, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  172. mac = config->mac;
  173. phy = config->phy;
  174. ESP_GOTO_ON_FALSE(mac && phy, ESP_ERR_INVALID_ARG, err, TAG, "can't set eth->mac or eth->phy to null");
  175. // eth_driver contains an atomic variable, which should not be put in PSRAM
  176. eth_driver = heap_caps_calloc(1, sizeof(esp_eth_driver_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  177. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_NO_MEM, err, TAG, "no mem for eth_driver");
  178. const esp_timer_create_args_t check_link_timer_args = {
  179. .callback = eth_check_link_timer_cb,
  180. .name = "eth_link_timer",
  181. .arg = eth_driver,
  182. .skip_unhandled_events = true
  183. };
  184. ESP_GOTO_ON_ERROR(esp_timer_create(&check_link_timer_args, &eth_driver->check_link_timer), err, TAG, "create link timer failed");
  185. atomic_init(&eth_driver->ref_count, 1);
  186. atomic_init(&eth_driver->fsm, ESP_ETH_FSM_STOP);
  187. eth_driver->mac = mac;
  188. eth_driver->phy = phy;
  189. eth_driver->link = ETH_LINK_DOWN;
  190. eth_driver->duplex = ETH_DUPLEX_HALF;
  191. eth_driver->speed = ETH_SPEED_10M;
  192. eth_driver->stack_input = config->stack_input;
  193. eth_driver->on_lowlevel_init_done = config->on_lowlevel_init_done;
  194. eth_driver->on_lowlevel_deinit_done = config->on_lowlevel_deinit_done;
  195. eth_driver->check_link_period_ms = config->check_link_period_ms;
  196. eth_driver->customized_read_phy_reg = config->read_phy_reg;
  197. eth_driver->customized_write_phy_reg = config->write_phy_reg;
  198. eth_driver->mediator.phy_reg_read = eth_phy_reg_read;
  199. eth_driver->mediator.phy_reg_write = eth_phy_reg_write;
  200. eth_driver->mediator.stack_input = eth_stack_input;
  201. eth_driver->mediator.on_state_changed = eth_on_state_changed;
  202. // set mediator for both mac and phy object, so that mac and phy are connected to each other via mediator
  203. mac->set_mediator(mac, &eth_driver->mediator);
  204. phy->set_mediator(phy, &eth_driver->mediator);
  205. // for PHY whose internal PLL has been configured to generate RMII clock, but is put in reset state during power up,
  206. // we need to deasseert the reset GPIO of PHY device first, ensure the RMII is clocked out from PHY
  207. phy->reset_hw(phy);
  208. // init MAC first, so that MAC can generate the correct SMI signals
  209. ESP_GOTO_ON_ERROR(mac->init(mac), err, TAG, "init mac failed");
  210. ESP_GOTO_ON_ERROR(phy->init(phy), err, TAG, "init phy failed");
  211. ESP_LOGD(TAG, "new ethernet driver @%p", eth_driver);
  212. *out_hdl = eth_driver;
  213. // for backward compatible to 4.0, and will get removed in 5.0
  214. #if CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER
  215. extern esp_err_t tcpip_adapter_compat_start_eth(void *eth_driver);
  216. tcpip_adapter_compat_start_eth(eth_driver);
  217. #endif
  218. return ESP_OK;
  219. err:
  220. if (eth_driver) {
  221. if (eth_driver->check_link_timer) {
  222. esp_timer_delete(eth_driver->check_link_timer);
  223. }
  224. free(eth_driver);
  225. }
  226. return ret;
  227. }
  228. esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
  229. {
  230. esp_err_t ret = ESP_OK;
  231. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  232. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  233. // check if driver has stopped
  234. esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
  235. ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP),
  236. ESP_ERR_INVALID_STATE, err, TAG, "driver not stopped yet");
  237. // don't uninstall driver unless there's only one reference
  238. int expected_ref_count = 1;
  239. ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(&eth_driver->ref_count, &expected_ref_count, 0),
  240. ESP_ERR_INVALID_STATE, err, TAG, "%d ethernet reference in use", expected_ref_count);
  241. esp_eth_mac_t *mac = eth_driver->mac;
  242. esp_eth_phy_t *phy = eth_driver->phy;
  243. ESP_GOTO_ON_ERROR(esp_timer_delete(eth_driver->check_link_timer), err, TAG, "delete link timer failed");
  244. ESP_GOTO_ON_ERROR(phy->deinit(phy), err, TAG, "deinit phy failed");
  245. ESP_GOTO_ON_ERROR(mac->deinit(mac), err, TAG, "deinit mac failed");
  246. free(eth_driver);
  247. err:
  248. return ret;
  249. }
  250. esp_err_t esp_eth_start(esp_eth_handle_t hdl)
  251. {
  252. esp_err_t ret = ESP_OK;
  253. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  254. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  255. esp_eth_phy_t *phy = eth_driver->phy;
  256. esp_eth_mac_t *mac = eth_driver->mac;
  257. // check if driver has stopped
  258. esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
  259. ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_START),
  260. ESP_ERR_INVALID_STATE, err, TAG, "driver started already");
  261. ESP_GOTO_ON_ERROR(phy->negotiate(phy), err, TAG, "phy negotiation failed");
  262. ESP_GOTO_ON_ERROR(mac->start(mac), err, TAG, "start mac failed");
  263. ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, &eth_driver, sizeof(esp_eth_driver_t *), 0),
  264. err, TAG, "send ETHERNET_EVENT_START event failed");
  265. ESP_GOTO_ON_ERROR(phy->get_link(phy), err, TAG, "phy get link status failed");
  266. ESP_GOTO_ON_ERROR(esp_timer_start_periodic(eth_driver->check_link_timer, eth_driver->check_link_period_ms * 1000),
  267. err, TAG, "start link timer failed");
  268. err:
  269. return ret;
  270. }
  271. esp_err_t esp_eth_stop(esp_eth_handle_t hdl)
  272. {
  273. esp_err_t ret = ESP_OK;
  274. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  275. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  276. esp_eth_mac_t *mac = eth_driver->mac;
  277. // check if driver has started
  278. esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_START;
  279. ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP),
  280. ESP_ERR_INVALID_STATE, err, TAG, "driver not started yet");
  281. ESP_GOTO_ON_ERROR(esp_timer_stop(eth_driver->check_link_timer), err, TAG, "stop link timer failed");
  282. ESP_GOTO_ON_ERROR(mac->stop(mac), err, TAG, "stop mac failed");
  283. ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, &eth_driver, sizeof(esp_eth_driver_t *), 0),
  284. err, TAG, "send ETHERNET_EVENT_STOP event failed");
  285. err:
  286. return ret;
  287. }
  288. esp_err_t esp_eth_update_input_path(
  289. esp_eth_handle_t hdl,
  290. esp_err_t (*stack_input)(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv),
  291. void *priv)
  292. {
  293. esp_err_t ret = ESP_OK;
  294. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  295. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  296. eth_driver->priv = priv;
  297. eth_driver->stack_input = stack_input;
  298. err:
  299. return ret;
  300. }
  301. esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length)
  302. {
  303. esp_err_t ret = ESP_OK;
  304. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  305. ESP_GOTO_ON_FALSE(buf, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf to null");
  306. ESP_GOTO_ON_FALSE(length, ESP_ERR_INVALID_ARG, err, TAG, "buf length can't be zero");
  307. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  308. esp_eth_mac_t *mac = eth_driver->mac;
  309. ret = mac->transmit(mac, buf, length);
  310. err:
  311. return ret;
  312. }
  313. esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length)
  314. {
  315. esp_err_t ret = ESP_OK;
  316. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  317. ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null");
  318. ESP_GOTO_ON_FALSE(*length > 60, ESP_ERR_INVALID_ARG, err, TAG, "length can't be less than 60");
  319. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  320. esp_eth_mac_t *mac = eth_driver->mac;
  321. ret = mac->receive(mac, buf, length);
  322. err:
  323. return ret;
  324. }
  325. esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data)
  326. {
  327. esp_err_t ret = ESP_OK;
  328. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  329. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  330. esp_eth_mac_t *mac = eth_driver->mac;
  331. esp_eth_phy_t *phy = eth_driver->phy;
  332. switch (cmd) {
  333. case ETH_CMD_S_MAC_ADDR:
  334. ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
  335. ESP_GOTO_ON_ERROR(mac->set_addr(mac, (uint8_t *)data), err, TAG, "set mac address failed");
  336. break;
  337. case ETH_CMD_G_MAC_ADDR:
  338. ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store mac addr");
  339. ESP_GOTO_ON_ERROR(mac->get_addr(mac, (uint8_t *)data), err, TAG, "get mac address failed");
  340. break;
  341. case ETH_CMD_S_PHY_ADDR:
  342. if ((uint32_t)data >= SOC_DRAM_LOW) {
  343. ESP_GOTO_ON_ERROR(phy->set_addr(phy, *(uint32_t *)data), err, TAG, "set phy address failed");
  344. } else { // TODO: for API compatibility reasons, will be removed with next major release
  345. ESP_GOTO_ON_ERROR(phy->set_addr(phy, (uint32_t)data), err, TAG, "set phy address failed");
  346. }
  347. break;
  348. case ETH_CMD_G_PHY_ADDR:
  349. ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store phy addr");
  350. ESP_GOTO_ON_ERROR(phy->get_addr(phy, (uint32_t *)data), err, TAG, "get phy address failed");
  351. break;
  352. case ETH_CMD_G_SPEED:
  353. ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store speed value");
  354. *(eth_speed_t *)data = eth_driver->speed;
  355. break;
  356. case ETH_CMD_S_PROMISCUOUS:
  357. if ((uint32_t)data >= SOC_DRAM_LOW) {
  358. ESP_GOTO_ON_ERROR(mac->set_promiscuous(mac, *(bool *)data), err, TAG, "set promiscuous mode failed");
  359. } else { // TODO: for API compatibility reasons, will be removed with next major release
  360. ESP_GOTO_ON_ERROR(mac->set_promiscuous(mac, (bool)data), err, TAG, "set promiscuous mode failed");
  361. }
  362. break;
  363. case ETH_CMD_S_FLOW_CTRL:
  364. if ((uint32_t)data >= SOC_DRAM_LOW) {
  365. ESP_GOTO_ON_ERROR(mac->enable_flow_ctrl(mac, *(bool *)data), err, TAG, "enable mac flow control failed");
  366. ESP_GOTO_ON_ERROR(phy->advertise_pause_ability(phy, *(uint32_t *)data), err, TAG, "phy advertise pause ability failed");
  367. } else { // TODO: for API compatibility reasons, will be removed with next major release
  368. ESP_GOTO_ON_ERROR(mac->enable_flow_ctrl(mac, (bool)data), err, TAG, "enable mac flow control failed");
  369. ESP_GOTO_ON_ERROR(phy->advertise_pause_ability(phy, (uint32_t)data), err, TAG, "phy advertise pause ability failed");
  370. }
  371. break;
  372. case ETH_CMD_G_DUPLEX_MODE:
  373. ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store duplex value");
  374. *(eth_duplex_t *)data = eth_driver->duplex;
  375. break;
  376. case ETH_CMD_S_PHY_LOOPBACK:
  377. if ((uint32_t)data >= SOC_DRAM_LOW) {
  378. ESP_GOTO_ON_ERROR(phy->loopback(phy, *(bool *)data), err, TAG, "configuration of phy loopback mode failed");
  379. } else { // TODO: for API compatibility reasons, will be removed with next major release
  380. ESP_GOTO_ON_ERROR(phy->loopback(phy, (bool)data), err, TAG, "configuration of phy loopback mode failed");
  381. }
  382. break;
  383. default:
  384. ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown io command: %d", cmd);
  385. break;
  386. }
  387. err:
  388. return ret;
  389. }
  390. esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl)
  391. {
  392. esp_err_t ret = ESP_OK;
  393. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  394. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  395. atomic_fetch_add(&eth_driver->ref_count, 1);
  396. err:
  397. return ret;
  398. }
  399. esp_err_t esp_eth_decrease_reference(esp_eth_handle_t hdl)
  400. {
  401. esp_err_t ret = ESP_OK;
  402. esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
  403. ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
  404. atomic_fetch_sub(&eth_driver->ref_count, 1);
  405. err:
  406. return ret;
  407. }