From 0e701e1caccff50c6ed91f8cfd2a9b359cdbf35c Mon Sep 17 00:00:00 2001 From: shangke Date: Fri, 6 Jan 2017 13:49:42 +0800 Subject: [PATCH] ethernet: support flow control --- components/esp32/include/soc/dport_reg.h | 18 ++- components/esp32/phy_init.c | 4 +- components/esp32/system_api.c | 10 +- components/ethernet/emac_common.h | 10 ++ components/ethernet/emac_dev.c | 31 ++++- components/ethernet/emac_dev.h | 21 +++- components/ethernet/emac_main.c | 137 ++++++++++++++++------ components/ethernet/include/esp_eth.h | 4 + docs/api/esp_eth.rst | 1 + examples/17_ethernet/main/ethernet_main.c | 25 +++- examples/17_ethernet/main/tlk110_phy.h | 10 +- 11 files changed, 211 insertions(+), 60 deletions(-) diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index f84346717c..ef231e316e 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -1035,14 +1035,20 @@ #define DPORT_WIFI_CLK_EN_V 0xFFFFFFFF #define DPORT_WIFI_CLK_EN_S 0 -#define DPORT_WIFI_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) -/* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ +#define DPORT_CORE_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) +/* DPORT_CORE_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: */ +#define DPROT_RW_BTLP_RST (BIT(10)) +#define DPROT_RW_BTMAC_RST (BIT(9)) +#define DPORT_MACPWR_RST (BIT(8)) +#define DPORT_EMAC_RST (BIT(7)) +#define DPORT_SDIO_HOST_RST (BIT(6)) +#define DPORT_SDIO_RST (BIT(5)) +#define DPORT_BTMAC_RST (BIT(4)) +#define DPORT_BT_RST (BIT(3)) #define DPORT_MAC_RST (BIT(2)) -#define DPORT_WIFI_RST 0xFFFFFFFF -#define DPORT_WIFI_RST_M ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S)) -#define DPORT_WIFI_RST_V 0xFFFFFFFF -#define DPORT_WIFI_RST_S 0 +#define DPORT_FE_RST (BIT(1)) +#define DPORT_BB_RST (BIT(0)) #define DPORT_BT_LPCK_DIV_INT_REG (DR_REG_DPORT_BASE + 0x0D4) /* DPORT_BTEXTWAKEUP_REQ : R/W ;bitpos:[12] ;default: 1'b0 ; */ diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 6154beae90..bfc5a15f5e 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -39,8 +39,8 @@ esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, assert(calibration_data); // Initialize PHY pointer table phy_get_romfunc_addr(); - REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); - REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); + REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); + REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); // Enable WiFi peripheral clock SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", diff --git a/components/esp32/system_api.c b/components/esp32/system_api.c index 63a28de533..60fa1796cd 100644 --- a/components/esp32/system_api.c +++ b/components/esp32/system_api.c @@ -111,9 +111,13 @@ void IRAM_ATTR esp_restart(void) uart_tx_wait_idle(1); uart_tx_wait_idle(2); - // Reset wifi/bluetooth (bb/mac) - SET_PERI_REG_MASK(DPORT_WIFI_RST_EN_REG, 0x1f); - REG_WRITE(DPORT_WIFI_RST_EN_REG, 0); + // Reset wifi/bluetooth/ethernet/sdio (bb/mac) + SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | + DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPROT_RW_BTMAC_RST | DPROT_RW_BTLP_RST); + REG_WRITE(DPORT_CORE_RST_EN_REG, 0); // Reset timer/spi/uart SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, diff --git a/components/ethernet/emac_common.h b/components/ethernet/emac_common.h index 774c287ad5..957337d2a7 100644 --- a/components/ethernet/emac_common.h +++ b/components/ethernet/emac_common.h @@ -72,6 +72,9 @@ struct emac_config_data { eth_phy_check_init_func emac_phy_check_init; eth_phy_get_speed_mode_func emac_phy_get_speed_mode; eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode; + bool emac_flow_ctrl_enable; + bool emac_flow_ctrl_partner_support; + eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable; }; enum emac_post_type { @@ -109,6 +112,13 @@ struct emac_close_cmd { #define DMA_RX_BUF_SIZE 1600 #define DMA_TX_BUF_SIZE 1600 +//rest buf num +#define FLOW_CONTROL_HIGH_WATERMARK 3 +//used buf num +#define FLOW_CONTROL_LOW_WATERMARK 6 + +#define PHY_LINK_CHECK_NUM 5 + #define EMAC_CMD_OK 0 #define EMAC_CMD_FAIL -1 diff --git a/components/ethernet/emac_dev.c b/components/ethernet/emac_dev.c index 244da08432..ba61bb750b 100644 --- a/components/ethernet/emac_dev.c +++ b/components/ethernet/emac_dev.c @@ -34,6 +34,24 @@ static const char *TAG = "emac"; +void emac_enable_flowctrl(void) +{ + REG_SET_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_TRANSMIT_FLOW_CONTROL_ENABLE); + REG_SET_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_RECEIVE_FLOW_CONTROL_ENABLE); + REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_DISABLE_ZERO_QUANTA_PAUSE); + REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_TIME, 0x1648); + REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_LOW_THRESHOLD, 0x1); +} + +void emac_disable_flowctrl(void) +{ + REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_TRANSMIT_FLOW_CONTROL_ENABLE); + REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_RECEIVE_FLOW_CONTROL_ENABLE); + REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_DISABLE_ZERO_QUANTA_PAUSE); + REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_TIME, 0); + REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_LOW_THRESHOLD, 0); +} + void emac_enable_dma_tx(void) { REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND); @@ -100,18 +118,21 @@ void emac_dma_init(void) REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FORWARD_UNDERSIZED_GOOD_FRAMES); REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPERATE_SECOND_FRAME); REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4); - REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG,EMAC_DMAOPERATION_MODE_REG); + REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_DMAOPERATION_MODE_REG); +} + +void emac_mac_enable_txrx(void) +{ + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX); + REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX); } void emac_mac_init(void) { REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACMIIGMII); - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); + REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); REG_SET_BIT(EMAC_GMACFRAMEFILTER_REG, EMAC_PROMISCUOUS_MODE); - - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX); - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX); } void emac_set_clk_rmii(void) diff --git a/components/ethernet/emac_dev.h b/components/ethernet/emac_dev.h index bc04d8d9e2..dc1045b92f 100644 --- a/components/ethernet/emac_dev.h +++ b/components/ethernet/emac_dev.h @@ -52,6 +52,9 @@ void emac_enable_dma_tx(void); void emac_enable_dma_rx(void); void emac_disable_dma_tx(void); void emac_disable_dma_rx(void); +void emac_enable_flowctrl(void); +void emac_disable_flowctrl(void); +void emac_mac_enable_txrx(void); uint32_t inline emac_read_tx_cur_reg(void) { @@ -77,22 +80,32 @@ void inline emac_poll_rx_cmd(void) void inline emac_disable_rx_intr(void) { - REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE); + REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_INTERRUPT_ENABLE); } void inline emac_enable_rx_intr(void) { - REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE); + REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_INTERRUPT_ENABLE); } void inline emac_disable_rx_unavail_intr(void) { - REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); + REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); } void inline emac_enable_rx_unavail_intr(void) { - REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); + REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE); +} + +void IRAM_ATTR inline emac_send_pause_frame_enable(void) +{ + REG_SET_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL); +} + +void inline emac_send_pause_zero_frame_enable(void) +{ + REG_CLR_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL); } #ifdef __cplusplus diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 06e641453b..9446e8ee35 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -68,6 +68,7 @@ static TimerHandle_t emac_timer = NULL; static SemaphoreHandle_t emac_rx_xMutex = NULL; static SemaphoreHandle_t emac_tx_xMutex = NULL; static const char *TAG = "emac"; +static bool pause_send = false; static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par); esp_err_t emac_post(emac_sig_t sig, emac_par_t par); @@ -96,9 +97,9 @@ static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc) tx_desc->basic.desc0 = 0; } -static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc ,uint32_t buf_ptr) +static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc , uint32_t buf_ptr) { - if(buf_ptr != 0) { + if (buf_ptr != 0) { rx_desc->basic.desc2 = buf_ptr; } rx_desc->basic.desc1 = EMAC_DESC_RX_SECOND_ADDR_CHAIN | DMA_RX_BUF_SIZE; @@ -215,6 +216,8 @@ static void emac_set_user_config_data(eth_config_t *config ) emac_config.emac_phy_check_init = config->phy_check_init; emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode; emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode; + emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable; + emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable; } static void emac_enable_intr() @@ -276,6 +279,11 @@ static esp_err_t emac_verify_args(void) ret = ESP_FAIL; } + if (emac_config.emac_flow_ctrl_enable == true && emac_config.emac_phy_get_partner_pause_enable == NULL) { + ESP_LOGE(TAG, "phy get partner pause enable func is null"); + ret = ESP_FAIL; + } + return ret; } @@ -293,13 +301,13 @@ static void emac_process_tx(void) { uint32_t cur_tx_desc = emac_read_tx_cur_reg(); - if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + if (emac_config.emac_status == EMAC_RUNTIME_STOP) { return; } xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY ); - while (((uint32_t) &(emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) { + while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) { emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx])); emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM; emac_config.cnt_tx --; @@ -317,21 +325,43 @@ void esp_eth_free_rx_buf(void *buf) { xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY ); - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]),(uint32_t) buf); + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t) buf); emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM; emac_config.cnt_rx--; - if(emac_config.cnt_rx < 0) { - ESP_LOGE(TAG, "emac rx buf err!!\n"); + if (emac_config.cnt_rx < 0) { + ESP_LOGE(TAG, "emac rx buf err!!\n"); } emac_poll_rx_cmd(); xSemaphoreGiveRecursive( emac_rx_xMutex ); + + if (emac_config.emac_flow_ctrl_partner_support == true) { + portENTER_CRITICAL(&g_emac_mux); + if (pause_send == true && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) { + emac_send_pause_zero_frame_enable(); + pause_send = false; + } + portEXIT_CRITICAL(&g_emac_mux); + } +} + +static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void) +{ + uint32_t cnt = 0; + uint32_t cur_rx_desc = emac_read_rx_cur_reg(); + struct dma_extended_desc *cur_desc = (struct dma_extended_desc *)cur_rx_desc; + + while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN) { + cnt++; + cur_desc = (struct dma_extended_desc *)cur_desc->basic.desc3; + } + return cnt; } #if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE static void emac_process_rx(void) { - if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + if (emac_config.emac_status == EMAC_RUNTIME_STOP) { return; } uint32_t cur_rx_desc = emac_read_rx_cur_reg(); @@ -341,7 +371,7 @@ static void emac_process_rx(void) emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; //if open this ,one intr can do many intrs ? @@ -353,14 +383,14 @@ static void emac_process_rx(void) static void emac_process_rx_unavail(void) { - if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + if (emac_config.emac_status == EMAC_RUNTIME_STOP) { return; } uint32_t dirty_cnt = 0; while (dirty_cnt < DMA_RX_BUF_NUM) { - if(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) { + if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) { break; } @@ -369,7 +399,7 @@ static void emac_process_rx_unavail(void) emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); + emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; } emac_enable_rx_intr(); @@ -380,7 +410,7 @@ static void emac_process_rx_unavail(void) #else static void emac_process_rx_unavail(void) { - if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + if (emac_config.emac_status == EMAC_RUNTIME_STOP) { return; } @@ -388,11 +418,11 @@ static void emac_process_rx_unavail(void) while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { - //copy data to lwip + //copy data to lwip emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); emac_config.cnt_rx++; - if(emac_config.cnt_rx > DMA_RX_BUF_NUM) { + if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { ESP_LOGE(TAG, "emac rx unavail buf err !!\n"); } emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; @@ -404,7 +434,7 @@ static void emac_process_rx_unavail(void) static void emac_process_rx(void) { - if(emac_config.emac_status == EMAC_RUNTIME_STOP) { + if (emac_config.emac_status == EMAC_RUNTIME_STOP) { return; } @@ -412,16 +442,16 @@ static void emac_process_rx(void) xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY ); - if(((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) { + if (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) { - while (((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) { + while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) { //copy data to lwip emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), - (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); emac_config.cnt_rx++; - if(emac_config.cnt_rx > DMA_RX_BUF_NUM ) { + if (emac_config.cnt_rx > DMA_RX_BUF_NUM ) { ESP_LOGE(TAG, "emac rx buf err!!\n"); } emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; @@ -429,16 +459,16 @@ static void emac_process_rx(void) cur_rx_desc = emac_read_rx_cur_reg(); } } else { - if(emac_config.cnt_rx < DMA_RX_BUF_NUM) { - if((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) { + if (emac_config.cnt_rx < DMA_RX_BUF_NUM) { + if ((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) { while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { //copy data to lwip emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), - (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); + (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL); emac_config.cnt_rx++; - if(emac_config.cnt_rx > DMA_RX_BUF_NUM) { - ESP_LOGE(TAG,"emac rx buf err!!!\n"); + if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { + ESP_LOGE(TAG, "emac rx buf err!!!\n"); } emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; @@ -462,12 +492,18 @@ static void IRAM_ATTR emac_process_intr(void *arg) if (event & EMAC_RECV_INT) { emac_disable_rx_intr(); + if (emac_config.emac_flow_ctrl_partner_support == true) { + if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && pause_send == false ) { + pause_send = true; + emac_send_pause_frame_enable(); + } + } emac_post(SIG_EMAC_RX_DONE, 0); } if (event & EMAC_RECV_BUF_UNAVAIL) { emac_disable_rx_unavail_intr(); - emac_post(SIG_EMAC_RX_UNAVAIL,0); + emac_post(SIG_EMAC_RX_UNAVAIL, 0); } if (event & EMAC_TRANS_INT) { @@ -475,25 +511,43 @@ static void IRAM_ATTR emac_process_intr(void *arg) } } +static void emac_set_macaddr_reg(void) +{ + REG_SET_FIELD(EMAC_GMACADDR0HIGH_REG, EMAC_MAC_ADDRESS0_HI, (emac_config.macaddr[0] << 8) | (emac_config.macaddr[1])); + REG_WRITE(EMAC_GMACADDR0LOW_REG, (emac_config.macaddr[2] << 24) | (emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) | (emac_config.macaddr[5])); +} + static void emac_check_phy_init(void) { emac_config.emac_phy_check_init(); - if(emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) { + if (emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) { REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); } else { REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX); } - if(emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) { + if (emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) { REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); } else { REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED); } - - emac_mac_init(); + if (emac_config.emac_flow_ctrl_enable == true) { + if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) { + emac_enable_flowctrl(); + emac_config.emac_flow_ctrl_partner_support = true; + } else { + emac_disable_flowctrl(); + emac_config.emac_flow_ctrl_partner_support = false; + } + } else { + emac_disable_flowctrl(); + emac_config.emac_flow_ctrl_partner_support = false; + } + emac_mac_enable_txrx(); } static void emac_process_link_updown(bool link_status) { system_event_t evt; + uint8_t i = 0; emac_config.phy_link_up = link_status; @@ -502,6 +556,10 @@ static void emac_process_link_updown(bool link_status) ESP_LOGI(TAG, "eth link_up!!!"); emac_enable_dma_tx(); emac_enable_dma_rx(); + for (i = 0; i < PHY_LINK_CHECK_NUM; i++) { + emac_check_phy_init(); + } + evt.event_id = SYSTEM_EVENT_ETH_CONNECTED; } else { ESP_LOGI(TAG, "eth link_down!!!"); @@ -534,7 +592,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size) } xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY ); - if (emac_config.cnt_tx == DMA_TX_BUF_NUM -1) { + if (emac_config.cnt_tx == DMA_TX_BUF_NUM - 1) { ESP_LOGD(TAG, "tx buf full"); ret = ERR_MEM; goto _exit; @@ -557,13 +615,13 @@ _exit: static void emac_init_default_data(void) { - memset((uint8_t *)&emac_config, 0,sizeof(struct emac_config_data)); + memset((uint8_t *)&emac_config, 0, sizeof(struct emac_config_data)); } -void emac_process_link_check(void) +void emac_process_link_check(void) { if (emac_config.emac_status != EMAC_RUNTIME_START || - emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { + emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { return; } @@ -580,7 +638,7 @@ void emac_process_link_check(void) void emac_link_check_func(void *pv_parameters) { - emac_post(SIG_EMAC_CHECK_LINK,0); + emac_post(SIG_EMAC_CHECK_LINK, 0); } static bool emac_link_check_timer_init(void) @@ -634,10 +692,13 @@ static void emac_start(void *param) emac_check_mac_addr(); emac_set_mac_addr(); + emac_set_macaddr_reg(); emac_set_tx_base_reg(); emac_set_rx_base_reg(); + emac_mac_init(); + emac_config.phy_init(); //ptp TODO @@ -818,7 +879,7 @@ void emac_task(void *pv) esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par) { - if(sig <= SIG_EMAC_RX_DONE) { + if (sig <= SIG_EMAC_RX_DONE) { if (emac_sig_cnt[sig]) { return ESP_OK; } else { @@ -831,11 +892,11 @@ esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par) ret = xQueueSendFromISR(emac_xqueue, &evt, &tmp); - if(tmp != pdFALSE) { + if (tmp != pdFALSE) { portYIELD_FROM_ISR(); } - if(ret != pdPASS) { + if (ret != pdPASS) { return ESP_FAIL; } } diff --git a/components/ethernet/include/esp_eth.h b/components/ethernet/include/esp_eth.h index 2aae9d2024..e36c3ebfe6 100644 --- a/components/ethernet/include/esp_eth.h +++ b/components/ethernet/include/esp_eth.h @@ -79,6 +79,7 @@ typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void); typedef void (*eth_phy_func)(void); typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb); typedef void (*eth_gpio_config_func)(void); +typedef bool (*eth_phy_get_partner_pause_enable_func)(void); /** @@ -95,6 +96,9 @@ typedef struct { eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */ eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */ eth_gpio_config_func gpio_config; /*!< gpio config func */ + bool flow_ctrl_enable; /*!< flag of flow ctrl enable */ + eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */ + } eth_config_t; /** diff --git a/docs/api/esp_eth.rst b/docs/api/esp_eth.rst index 1fcb1c2351..371aa5b233 100644 --- a/docs/api/esp_eth.rst +++ b/docs/api/esp_eth.rst @@ -28,6 +28,7 @@ Type Definitions .. doxygentypedef:: eth_phy_func .. doxygentypedef:: eth_tcpip_input_func .. doxygentypedef:: eth_gpio_config_func +.. doxygentypedef:: eth_phy_get_partner_pause_enable_func Enumerations ^^^^^^^^^^^^ diff --git a/examples/17_ethernet/main/ethernet_main.c b/examples/17_ethernet/main/ethernet_main.c index fc4347f7d8..57c6f97357 100644 --- a/examples/17_ethernet/main/ethernet_main.c +++ b/examples/17_ethernet/main/ethernet_main.c @@ -71,6 +71,22 @@ bool phy_tlk110_check_phy_link_status(void) return ((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & LINK_STATUS) == LINK_STATUS ); } +bool phy_tlk110_get_partner_pause_enable(void) +{ + if((esp_eth_smi_read(PHY_LINK_PARTNER_ABILITY_REG) & PARTNER_PAUSE) == PARTNER_PAUSE) { + return true; + } else { + return false; + } +} + +void phy_enable_flow_ctrl(void) +{ + uint32_t data = 0; + data = esp_eth_smi_read(AUTO_NEG_ADVERTISEMENT_REG); + esp_eth_smi_write(AUTO_NEG_ADVERTISEMENT_REG,data|ASM_DIR|PAUSE); +} + void phy_tlk110_init(void) { esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET); @@ -78,8 +94,12 @@ void phy_tlk110_init(void) while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) { } - esp_eth_smi_write(SOFTWARE_STAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE); + esp_eth_smi_write(SOFTWARE_STRAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE); + ets_delay_us(300); + + //if config.flow_ctrl_enable == true ,enable this + phy_enable_flow_ctrl(); } void eth_gpio_config_rmii(void) @@ -140,6 +160,9 @@ void app_main() config.phy_check_link = phy_tlk110_check_phy_link_status; config.phy_get_speed_mode = phy_tlk110_get_speed_mode; config.phy_get_duplex_mode = phy_tlk110_get_duplex_mode; + //Only FULLDUPLEX mode support flow ctrl now! + config.flow_ctrl_enable = true; + config.phy_get_partner_pause_enable = phy_tlk110_get_partner_pause_enable; ret = esp_eth_init(&config); diff --git a/examples/17_ethernet/main/tlk110_phy.h b/examples/17_ethernet/main/tlk110_phy.h index 5f2ca644dc..a21bc57aea 100644 --- a/examples/17_ethernet/main/tlk110_phy.h +++ b/examples/17_ethernet/main/tlk110_phy.h @@ -5,7 +5,15 @@ #define PHY_IDENTIFIER_REG (0x2) #define OUI_MSB_21TO6_DEF 0x2000 -#define SOFTWARE_STAP_CONTROL_REG (0x9) +#define AUTO_NEG_ADVERTISEMENT_REG (0x4) +#define ASM_DIR BIT(11) +#define PAUSE BIT(10) + +#define PHY_LINK_PARTNER_ABILITY_REG (0x5) +#define PARTNER_ASM_DIR BIT(11) +#define PARTNER_PAUSE BIT(10) + +#define SOFTWARE_STRAP_CONTROL_REG (0x9) #define SW_STRAP_CONFIG_DONE BIT(15) #define AUTO_MDIX_ENABLE BIT(14) #define AUTO_NEGOTIATION_ENABLE BIT(13)