Merge branch 'bugfix/ethernet_add_reference_counter' into 'master'

ethernet: add reference counter for mac and phy && add gpio config outof Kconfig

Closes IDF-1056

See merge request espressif/esp-idf!6682
This commit is contained in:
Angus Gratton
2019-11-21 06:58:13 +08:00
32 changed files with 784 additions and 535 deletions

View File

@@ -1,34 +1,30 @@
set(srcs) # If ethernet disabled in Kconfig, this is a config-only component
set(srcs)
set(include)
set(linker)
# If Ethernet disabled in Kconfig, this is a config-only component
if(CONFIG_ETH_ENABLED)
set(srcs "src/esp_eth.c")
set(include "include")
set(linker "linker.lf")
if(CONFIG_ETH_USE_ESP32_EMAC)
list(APPEND srcs "src/esp_eth_mac_esp32.c"
"src/esp_eth_phy_dp83848.c"
"src/esp_eth_phy_ip101.c"
"src/esp_eth_phy_lan8720.c"
"src/esp_eth_phy_rtl8201.c"
)
"src/esp_eth_phy_dp83848.c"
"src/esp_eth_phy_ip101.c"
"src/esp_eth_phy_lan8720.c"
"src/esp_eth_phy_rtl8201.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_DM9051)
list(APPEND srcs "src/esp_eth_mac_dm9051.c"
"src/esp_eth_phy_dm9051.c")
"src/esp_eth_phy_dm9051.c")
endif()
if(CONFIG_ETH_USE_OPENETH)
list(APPEND srcs "src/esp_eth_mac_openeth.c")
endif()
endif()
if(CONFIG_ETH_USE_OPENETH)
list(APPEND srcs "src/esp_eth_mac_openeth.c")
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${include}
LDFRAGMENTS ${linker}
REQUIRES "esp_event"
PRIV_REQUIRES "esp_netif" "driver" "log")
INCLUDE_DIRS ${include}
REQUIRES "esp_event"
PRIV_REQUIRES "esp_netif" "driver" "log")

View File

@@ -1,7 +1,6 @@
menu "Ethernet"
# Invisible item that is enabled if any Ethernet
# selection is made
# Invisible item that is enabled if any Ethernet selection is made
config ETH_ENABLED
bool
@@ -81,36 +80,6 @@ menu "Ethernet"
endif
endif
config ETH_SMI_MDC_GPIO
int "SMI MDC GPIO number"
default 23
range 0 33
help
Set the GPIO number used by SMI MDC.
config ETH_SMI_MDIO_GPIO
int "SMI MDIO GPIO number"
default 18
range 0 33
help
Set the GPIO number used by SMI MDIO.
config ETH_PHY_USE_RST
bool "Use Reset Pin of PHY Chip"
default y
help
Set this option to true if you want to control PHY chip's reset using a GPIO.
Check the schematic of you board to make sure if it's necessary to use this feature.
if ETH_PHY_USE_RST
config ETH_PHY_RST_GPIO
int "PHY RST GPIO number"
default 5
range 0 33
help
Set the GPIO number used by the PHY chip's RST pin.
endif
config ETH_DMA_BUFFER_SIZE
int "Ethernet DMA buffer size (Byte)"
range 256 1600
@@ -143,27 +112,19 @@ menu "Ethernet"
ESP-IDF can also support some SPI-Ethernet modules.
if ETH_USE_SPI_ETHERNET
menuconfig ETH_SPI_ETHERNET_DM9051
config ETH_SPI_ETHERNET_DM9051
bool "Use DM9051"
default y
help
DM9051 is a fast Ethernet controller with an SPI interface.
It's also integrated with a 10/100M PHY and MAC.
Set true to enable DM9051 driver.
if ETH_SPI_ETHERNET_DM9051
config ETH_DM9051_INT_GPIO
int "DM9051 Interrupt GPIO number"
default 4
range 0 33
help
Set the GPIO number used by DM9051's Interrupt pin.
endif
endif
menuconfig ETH_USE_OPENETH
bool "Support OpenCores Ethernet MAC (for use with QEMU)"
default n
select ETH_ENABLED
help
OpenCores Ethernet MAC driver can be used when an ESP-IDF application
is executed in QEMU. This driver is not supported when running on a

View File

@@ -3,7 +3,6 @@
#
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS := src
COMPONENT_ADD_LDFRAGMENTS += linker.lf
ifndef CONFIG_ETH_USE_ESP32_EMAC
COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o

View File

@@ -18,10 +18,10 @@ extern "C" {
#endif
#include <stdbool.h>
#include "esp_eth_com.h"
#include <stdatomic.h>
#include "sdkconfig.h"
#include "esp_eth_com.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/gpio.h"
#include "driver/spi_master.h"
#endif
@@ -37,6 +37,12 @@ typedef struct esp_eth_mac_s esp_eth_mac_t;
*
*/
struct esp_eth_mac_s {
/**
* @brief Reference count of MAC instance
*
*/
atomic_int ref_count;
/**
* @brief Set mediator for Ethernet MAC
*
@@ -251,6 +257,8 @@ typedef struct {
uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */
uint32_t rx_task_stack_size; /*!< Stack size of the receive task */
uint32_t rx_task_prio; /*!< Priority of the receive task */
int smi_mdc_gpio_num; /*!< SMI MDC GPIO number */
int smi_mdio_gpio_num; /*!< SMI MDIO GPIO number */
} eth_mac_config_t;
/**
@@ -262,6 +270,8 @@ typedef struct {
.sw_reset_timeout_ms = 100, \
.rx_task_stack_size = 4096, \
.rx_task_prio = 15, \
.smi_mdc_gpio_num = 23, \
.smi_mdio_gpio_num = 18, \
}
#if CONFIG_ETH_USE_ESP32_EMAC
@@ -284,6 +294,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
*/
typedef struct {
spi_device_handle_t spi_hdl; /*!< Handle of SPI device driver */
int int_gpio_num; /*!< Interrupt GPIO number */
} eth_dm9051_config_t;
/**
@@ -293,6 +304,7 @@ typedef struct {
#define ETH_DM9051_DEFAULT_CONFIG(spi_device) \
{ \
.spi_hdl = spi_device, \
.int_gpio_num = 4, \
}
/**
@@ -310,6 +322,17 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
#if CONFIG_ETH_USE_OPENETH
/**
* @brief Create OpenETH MAC instance
*
* @note This API is only used for qemu simulation
*
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config);
#endif // CONFIG_ETH_USE_OPENETH

View File

@@ -18,8 +18,9 @@ extern "C" {
#endif
#include <stdbool.h>
#include "esp_eth_com.h"
#include <stdatomic.h>
#include "sdkconfig.h"
#include "esp_eth_com.h"
/**
* @brief Ethernet PHY
@@ -32,6 +33,12 @@ typedef struct esp_eth_phy_s esp_eth_phy_t;
*
*/
struct esp_eth_phy_s {
/**
* @brief Reference count of PHY instance
*
*/
atomic_int ref_count;
/**
* @brief Set mediator for PHY
*
@@ -46,7 +53,7 @@ struct esp_eth_phy_s {
esp_err_t (*set_mediator)(esp_eth_phy_t *phy, esp_eth_mediator_t *mediator);
/**
* @brief Reset Ethernet PHY
* @brief Software Reset Ethernet PHY
*
* @param[in] phy: Ethernet PHY instance
*
@@ -57,6 +64,20 @@ struct esp_eth_phy_s {
*/
esp_err_t (*reset)(esp_eth_phy_t *phy);
/**
* @brief Hardware Reset Ethernet PHY
*
* @note Hardware reset is mostly done by pull down and up PHY's nRST pin
*
* @param[in] phy: Ethernet PHY instance
*
* @return
* - ESP_OK: reset Ethernet PHY successfully
* - ESP_FAIL: reset Ethernet PHY failed because some error occurred
*
*/
esp_err_t (*reset_hw)(esp_eth_phy_t *phy);
/**
* @brief Initialize Ethernet PHY
*
@@ -165,17 +186,19 @@ typedef struct {
uint32_t phy_addr; /*!< PHY address */
uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
} eth_phy_config_t;
/**
* @brief Default configuration for Ethernet PHY object
*
*/
#define ETH_PHY_DEFAULT_CONFIG() \
{ \
.phy_addr = 1, \
.reset_timeout_ms = 100, \
.autonego_timeout_ms = 4000 \
#define ETH_PHY_DEFAULT_CONFIG() \
{ \
.phy_addr = 1, \
.reset_timeout_ms = 100, \
.autonego_timeout_ms = 4000, \
.reset_gpio_num = 5, \
}
/**

View File

@@ -1,12 +0,0 @@
[mapping:esp_eth]
archive: libesp_eth.a
entries:
if ETH_USE_ESP32_EMAC = y:
esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text)
esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text)
esp_eth_mac_esp32:emac_esp32_isr_handler (noflash_text)
if ETH_SPI_ETHERNET_DM9051 = y:
esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text)

View File

@@ -0,0 +1,162 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Registers in DM9051
*
*/
#define DM9051_NCR (0x00) // Network Control Register
#define DM9051_NSR (0x01) // Network Status Register
#define DM9051_TCR (0x02) // Tx Control Register
#define DM9051_TSR1 (0x03) // Tx Status Register I
#define DM9051_TSR2 (0x04) // Tx Status Register II
#define DM9051_RCR (0x05) // Rx Control Register
#define DM9051_RSR (0x06) // Rx Status Register
#define DM9051_ROCR (0x07) // Receive Overflow Counter Register
#define DM9051_BPTR (0x08) // Back Pressure Threshold Register
#define DM9051_FCTR (0x09) // Flow Control Threshold Register
#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register
#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register
#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register
#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low
#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High
#define DM9051_WCR (0x0F) // Wake Up Control Register
#define DM9051_PAR (0x10) // Physical Address Register
#define DM9051_MAR (0x16) // Multicast Address Hash Table Register
#define DM9051_GPCR (0x1E) // General Purpose Control Register
#define DM9051_GPR (0x1F) // General Purpose Register
#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte
#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte
#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte
#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte
#define DM9051_VIDL (0x28) // Vendor ID Low Byte
#define DM9051_VIDH (0x29) // Vendor ID High Byte
#define DM9051_PIDL (0x2A) // Product ID Low Byte
#define DM9051_PIDH (0x2B) // Product ID High Byte
#define DM9051_CHIPR (0x2C) // CHIP Revision
#define DM9051_TCR2 (0x2D) // Transmit Control Register 2
#define DM9051_ATCR (0x30) // Auto-Transmit Control Register
#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register
#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register
#define DM9051_SBCR (0x38) // SPI Bus Control Register
#define DM9051_INTCR (0x39) // INT Pin Control Register
#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register
#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register
#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register
#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register
#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register
#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register
#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register
#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register
#define DM9051_MLEDCR (0x57) // More LED Control Register
#define DM9051_MEMSCR (0x59) // Memory Control Register
#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register
#define DM9051_MBSR (0x5D) // Memory BIST Status Register
#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register
#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register
#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register
#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register
#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte
#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte
#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register
#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register
#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte
#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte
#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register
#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register
#define DM9051_ISR (0x7E) // Interrupt Status Register
#define DM9051_IMR (0x7F) // Interrupt Mask Register
/**
* @brief status and flag of DM9051 specific registers
*
*/
#define DM9051_SPI_RD (0) // Burst Read Command
#define DM9051_SPI_WR (1) // Burst Write Command
#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function
#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY
#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us
#define NSR_SPEED (1 << 7) // Speed of Internal PHY
#define NSR_LINKST (1 << 6) // Link Status of Internal PHY
#define NSR_WAKEST (1 << 5) // Wakeup Event Status
#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status
#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status
#define NSR_RXOV (1 << 1) // RX Memory Overflow Status
#define NSR_RXRDY (1 << 0) // RX Packet Ready
#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely
#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable
#define RCR_DIS_LONG (1 << 5) // Discard Long Packet
#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet
#define RCR_ALL (1 << 3) // Receive All Multicast
#define RCR_RUNT (1 << 2) // Receive Runt Packet
#define RCR_PRMSC (1 << 1) // Promiscuous Mode
#define RCR_RXEN (1 << 0) // RX Enable
#define RSR_RF (1 << 7) // Runt Frame
#define RSR_MF (1 << 6) // Multicast Frame
#define RSR_LCS (1 << 5) // Late Collision Seen
#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out
#define RSR_PLE (1 << 3) // Physical Layer Error
#define RSR_AE (1 << 2) // Alignment Error
#define RSR_CE (1 << 1) // CRC Error
#define RSR_FOE (1 << 0) // RX Memory Overflow Error
#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control
#define EPCR_REEP (1 << 5) // Reload EEPROM
#define EPCR_WEP (1 << 4) // Write EEPROM Enable
#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select
#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command
#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command
#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status
#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet
#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control
#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation
#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation
#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation
#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer
#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer
#define ISR_LNKCHGS (1 << 5) // Link Status Change
#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow
#define ISR_ROS (1 << 2) // Receive Overflow
#define ISR_PT (1 << 1) // Packet Transmitted
#define ISR_PR (1 << 0) // Packet Received
#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR)
#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode
#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt
#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt
#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt
#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt
#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt
#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI)
#ifdef __cplusplus
}
#endif

View File

@@ -148,7 +148,15 @@ static void eth_check_link_timer_cb(TimerHandle_t xTimer)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)pvTimerGetTimerID(xTimer);
esp_eth_phy_t *phy = eth_driver->phy;
/* add reference to prevent other thread deleting the phy instance */
atomic_fetch_add(&phy->ref_count, 1);
phy->get_link(phy);
/* only the timer obtains the instance, i.e. all other references to this phy has been released */
if (atomic_load(&phy->ref_count) == 1) {
phy->del(phy); // since this phy doesn't have other owners, delete it
} else {
atomic_fetch_sub(&phy->ref_count, 1);
}
}
static esp_err_t esp_eth_post_attach_driver_start(esp_netif_t * esp_netif, void * args)
@@ -206,6 +214,8 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_
ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM);
eth_driver->mac = mac;
eth_driver->phy = phy;
atomic_fetch_add(&phy->ref_count, 1);
atomic_fetch_add(&mac->ref_count, 1);
eth_driver->link = ETH_LINK_DOWN;
eth_driver->duplex = ETH_DUPLEX_HALF;
eth_driver->speed = ETH_SPEED_10M;
@@ -216,6 +226,8 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_
eth_driver->mediator.phy_reg_write = eth_phy_reg_write;
eth_driver->mediator.stack_input = eth_stack_input;
eth_driver->mediator.on_state_changed = eth_on_state_changed;
/* some PHY can't output RMII clock if in reset state, so hardware reset PHY chip firstly */
phy->reset_hw(phy);
ETH_CHECK(mac->set_mediator(mac, &eth_driver->mediator) == ESP_OK, "set mediator for mac failed", err_mediator, ESP_FAIL);
ETH_CHECK(phy->set_mediator(phy, &eth_driver->mediator) == ESP_OK, "set mediator for phy failed", err_mediator, ESP_FAIL);
ETH_CHECK(mac->init(mac) == ESP_OK, "init mac failed", err_init_mac, ESP_FAIL);
@@ -233,6 +245,8 @@ err_init_phy:
mac->deinit(mac);
err_init_mac:
err_mediator:
atomic_fetch_sub(&phy->ref_count, 1);
atomic_fetch_sub(&mac->ref_count, 1);
free(eth_driver);
err:
return ret;
@@ -250,6 +264,8 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
"send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL);
ETH_CHECK(phy->deinit(phy) == ESP_OK, "deinit phy failed", err, ESP_FAIL);
ETH_CHECK(mac->deinit(mac) == ESP_OK, "deinit mac failed", err, ESP_FAIL);
atomic_fetch_sub(&phy->ref_count, 1);
atomic_fetch_sub(&mac->ref_count, 1);
free(eth_driver);
return ESP_OK;
err:

View File

@@ -16,6 +16,7 @@
#include <sys/cdefs.h>
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "esp_system.h"
@@ -24,6 +25,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "dm9051.h"
#include "sdkconfig.h"
static const char *TAG = "emac_dm9051";
@@ -41,145 +43,6 @@ static const char *TAG = "emac_dm9051";
#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
/**
* @brief Registers in DM9051
*
*/
#define DM9051_NCR (0x00) // Network Control Register
#define DM9051_NSR (0x01) // Network Status Register
#define DM9051_TCR (0x02) // Tx Control Register
#define DM9051_TSR1 (0x03) // Tx Status Register I
#define DM9051_TSR2 (0x04) // Tx Status Register II
#define DM9051_RCR (0x05) // Rx Control Register
#define DM9051_RSR (0x06) // Rx Status Register
#define DM9051_ROCR (0x07) // Receive Overflow Counter Register
#define DM9051_BPTR (0x08) // Back Pressure Threshold Register
#define DM9051_FCTR (0x09) // Flow Control Threshold Register
#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register
#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register
#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register
#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low
#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High
#define DM9051_WCR (0x0F) // Wake Up Control Register
#define DM9051_PAR (0x10) // Physical Address Register
#define DM9051_MAR (0x16) // Multicast Address Hash Table Register
#define DM9051_GPCR (0x1E) // General Purpose Control Register
#define DM9051_GPR (0x1F) // General Purpose Register
#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte
#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte
#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte
#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte
#define DM9051_VIDL (0x28) // Vendor ID Low Byte
#define DM9051_VIDH (0x29) // Vendor ID High Byte
#define DM9051_PIDL (0x2A) // Product ID Low Byte
#define DM9051_PIDH (0x2B) // Product ID High Byte
#define DM9051_CHIPR (0x2C) // CHIP Revision
#define DM9051_TCR2 (0x2D) // Transmit Control Register 2
#define DM9051_ATCR (0x30) // Auto-Transmit Control Register
#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register
#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register
#define DM9051_SBCR (0x38) // SPI Bus Control Register
#define DM9051_INTCR (0x39) // INT Pin Control Register
#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register
#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register
#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register
#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register
#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register
#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register
#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register
#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register
#define DM9051_MLEDCR (0x57) // More LED Control Register
#define DM9051_MEMSCR (0x59) // Memory Control Register
#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register
#define DM9051_MBSR (0x5D) // Memory BIST Status Register
#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register
#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register
#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register
#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register
#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte
#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte
#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register
#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register
#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte
#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte
#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register
#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register
#define DM9051_ISR (0x7E) // Interrupt Status Register
#define DM9051_IMR (0x7F) // Interrupt Mask Register
/**
* @brief status and flag of DM9051 specific registers
*
*/
#define DM9051_SPI_RD (0) // Burst Read Command
#define DM9051_SPI_WR (1) // Burst Write Command
#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function
#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY
#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us
#define NSR_SPEED (1 << 7) // Speed of Internal PHY
#define NSR_LINKST (1 << 6) // Link Status of Internal PHY
#define NSR_WAKEST (1 << 5) // Wakeup Event Status
#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status
#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status
#define NSR_RXOV (1 << 1) // RX Memory Overflow Status
#define NSR_RXRDY (1 << 0) // RX Packet Ready
#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely
#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable
#define RCR_DIS_LONG (1 << 5) // Discard Long Packet
#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet
#define RCR_ALL (1 << 3) // Receive All Multicast
#define RCR_RUNT (1 << 2) // Receive Runt Packet
#define RCR_PRMSC (1 << 1) // Promiscuous Mode
#define RCR_RXEN (1 << 0) // RX Enable
#define RSR_RF (1 << 7) // Runt Frame
#define RSR_MF (1 << 6) // Multicast Frame
#define RSR_LCS (1 << 5) // Late Collision Seen
#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out
#define RSR_PLE (1 << 3) // Physical Layer Error
#define RSR_AE (1 << 2) // Alignment Error
#define RSR_CE (1 << 1) // CRC Error
#define RSR_FOE (1 << 0) // RX Memory Overflow Error
#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control
#define EPCR_REEP (1 << 5) // Reload EEPROM
#define EPCR_WEP (1 << 4) // Write EEPROM Enable
#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select
#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command
#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command
#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status
#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet
#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control
#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation
#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation
#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation
#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer
#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer
#define ISR_LNKCHGS (1 << 5) // Link Status Change
#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow
#define ISR_ROS (1 << 2) // Receive Overflow
#define ISR_PT (1 << 1) // Packet Transmitted
#define ISR_PR (1 << 0) // Packet Received
#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR)
#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode
#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt
#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt
#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt
#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt
#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt
#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI)
typedef struct {
uint8_t flag;
uint8_t status;
@@ -194,6 +57,7 @@ typedef struct {
SemaphoreHandle_t spi_lock;
TaskHandle_t rx_task_hdl;
uint32_t sw_reset_timeout_ms;
int int_gpio_num;
uint8_t addr[6];
bool packets_remain;
} emac_dm9051_t;
@@ -506,7 +370,7 @@ err:
return ret;
}
static void dm9051_isr_handler(void *arg)
IRAM_ATTR static void dm9051_isr_handler(void *arg)
{
emac_dm9051_t *emac = (emac_dm9051_t *)arg;
BaseType_t high_task_wakeup = pdFALSE;
@@ -806,13 +670,12 @@ static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
esp_eth_mediator_t *eth = emac->eth;
/* init gpio used by spi-ethernet interrupt */
gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO);
gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT);
gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY);
gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE);
gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO);
gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac);
gpio_pad_select_gpio(emac->int_gpio_num);
gpio_set_direction(emac->int_gpio_num, GPIO_MODE_INPUT);
gpio_set_pull_mode(emac->int_gpio_num, GPIO_PULLDOWN_ONLY);
gpio_set_intr_type(emac->int_gpio_num, GPIO_INTR_POSEDGE);
gpio_intr_enable(emac->int_gpio_num);
gpio_isr_handler_add(emac->int_gpio_num, dm9051_isr_handler, emac);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
/* reset dm9051 */
MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL);
@@ -826,8 +689,8 @@ static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac)
MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
return ESP_OK;
err:
gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
gpio_isr_handler_remove(emac->int_gpio_num);
gpio_reset_pin(emac->int_gpio_num);
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
return ret;
}
@@ -837,8 +700,8 @@ static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac)
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
esp_eth_mediator_t *eth = emac->eth;
dm9051_stop(emac);
gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO);
gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO);
gpio_isr_handler_remove(emac->int_gpio_num);
gpio_reset_pin(emac->int_gpio_num);
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
return ESP_OK;
}
@@ -846,9 +709,11 @@ static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac)
static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
{
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
vTaskDelete(emac->rx_task_hdl);
vSemaphoreDelete(emac->spi_lock);
free(emac);
if (atomic_fetch_sub(&mac->ref_count, 1) == 1) {
vTaskDelete(emac->rx_task_hdl);
vSemaphoreDelete(emac->spi_lock);
free(emac);
}
return ESP_OK;
}
@@ -860,8 +725,11 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
MAC_CHECK(mac_config, "can't set mac config to null", err, NULL);
emac = calloc(1, sizeof(emac_dm9051_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* dm9051 receive is driven by interrupt only for now*/
MAC_CHECK(dm9051_config->int_gpio_num >= 0, "error interrupt gpio number", err, NULL);
/* bind methods and attributes */
emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
emac->int_gpio_num = dm9051_config->int_gpio_num;
emac->spi_hdl = dm9051_config->spi_hdl;
emac->parent.set_mediator = emac_dm9051_set_mediator;
emac->parent.init = emac_dm9051_init;
@@ -877,6 +745,7 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
emac->parent.set_promiscuous = emac_dm9051_set_promiscuous;
emac->parent.transmit = emac_dm9051_transmit;
emac->parent.receive = emac_dm9051_receive;
atomic_init(&emac->parent.ref_count, 1);
/* create mutex */
emac->spi_lock = xSemaphoreCreateMutex();
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);

View File

@@ -16,6 +16,7 @@
#include <sys/cdefs.h>
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "esp_system.h"
@@ -50,6 +51,8 @@ typedef struct {
TaskHandle_t rx_task_hdl;
uint32_t sw_reset_timeout_ms;
uint32_t frames_remain;
int smi_mdc_gpio_num;
int smi_mdio_gpio_num;
uint8_t addr[6];
uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM];
uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM];
@@ -264,17 +267,17 @@ static void emac_esp32_rx_task(void *arg)
vTaskDelete(NULL);
}
static void emac_esp32_init_smi_gpio(void)
static void emac_esp32_init_smi_gpio(emac_esp32_t *emac)
{
/* Setup SMI MDC GPIO */
gpio_set_direction(CONFIG_ETH_SMI_MDC_GPIO, GPIO_MODE_OUTPUT);
gpio_matrix_out(CONFIG_ETH_SMI_MDC_GPIO, EMAC_MDC_O_IDX, false, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDC_GPIO], PIN_FUNC_GPIO);
gpio_set_direction(emac->smi_mdc_gpio_num, GPIO_MODE_OUTPUT);
gpio_matrix_out(emac->smi_mdc_gpio_num, EMAC_MDC_O_IDX, false, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdc_gpio_num], PIN_FUNC_GPIO);
/* Setup SMI MDIO GPIO */
gpio_set_direction(CONFIG_ETH_SMI_MDIO_GPIO, GPIO_MODE_INPUT_OUTPUT);
gpio_matrix_out(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDO_O_IDX, false, false);
gpio_matrix_in(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDI_I_IDX, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDIO_GPIO], PIN_FUNC_GPIO);
gpio_set_direction(emac->smi_mdio_gpio_num, GPIO_MODE_INPUT_OUTPUT);
gpio_matrix_out(emac->smi_mdio_gpio_num, EMAC_MDO_O_IDX, false, false);
gpio_matrix_in(emac->smi_mdio_gpio_num, EMAC_MDI_I_IDX, false);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[emac->smi_mdio_gpio_num], PIN_FUNC_GPIO);
}
static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
@@ -287,12 +290,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
/* enable clock, config gpio, etc */
emac_hal_lowlevel_init(&emac->hal);
/* init gpio used by gpio */
emac_esp32_init_smi_gpio();
#if CONFIG_ETH_PHY_USE_RST
gpio_pad_select_gpio(CONFIG_ETH_PHY_RST_GPIO);
gpio_set_direction(CONFIG_ETH_PHY_RST_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 1);
#endif
emac_esp32_init_smi_gpio(emac);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
/* software reset */
emac_hal_reset(&emac->hal);
@@ -327,9 +325,6 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_eth_mediator_t *eth = emac->eth;
#if CONFIG_ETH_PHY_USE_RST
gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0);
#endif
emac_hal_stop(&emac->hal);
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
periph_module_disable(PERIPH_EMAC_MODULE);
@@ -339,21 +334,23 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_intr_free(emac->intr_hdl);
vTaskDelete(emac->rx_task_hdl);
int i = 0;
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->hal.rx_buf[i]);
if (atomic_fetch_sub(&mac->ref_count, 1) == 1) {
esp_intr_free(emac->intr_hdl);
vTaskDelete(emac->rx_task_hdl);
int i = 0;
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->hal.rx_buf[i]);
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->hal.tx_buf[i]);
}
free(emac->hal.descriptors);
free(emac);
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->hal.tx_buf[i]);
}
free(emac->hal.descriptors);
free(emac);
return ESP_OK;
}
void emac_esp32_isr_handler(void *args)
IRAM_ATTR void emac_esp32_isr_handler(void *args)
{
emac_hal_context_t *hal = (emac_hal_context_t *)args;
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
@@ -394,6 +391,8 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
/* initialize hal layer driver */
emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num;
emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num;
emac->parent.set_mediator = emac_esp32_set_mediator;
emac->parent.init = emac_esp32_init;
emac->parent.deinit = emac_esp32_deinit;
@@ -408,6 +407,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
emac->parent.transmit = emac_esp32_transmit;
emac->parent.receive = emac_esp32_receive;
atomic_init(&emac->parent.ref_count, 1);
/* Interrupt configuration */
MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler,
&emac->hal, &(emac->intr_hdl)) == ESP_OK,
@@ -440,7 +440,7 @@ err:
return ret;
}
void emac_hal_rx_complete_cb(void *arg)
IRAM_ATTR void emac_hal_rx_complete_cb(void *arg)
{
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
@@ -452,7 +452,7 @@ void emac_hal_rx_complete_cb(void *arg)
}
}
void emac_hal_rx_unavail_cb(void *arg)
IRAM_ATTR void emac_hal_rx_unavail_cb(void *arg)
{
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);

View File

@@ -66,7 +66,7 @@ static esp_err_t emac_opencores_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32
static IRAM_ATTR void emac_opencores_isr_handler(void *args)
{
emac_opencores_t *emac = (emac_opencores_t*) args;
emac_opencores_t *emac = (emac_opencores_t *) args;
BaseType_t high_task_wakeup;
uint32_t status = REG_READ(OPENETH_INT_SOURCE_REG);
@@ -94,7 +94,7 @@ static void emac_opencores_rx_task(void *arg)
uint32_t length = 0;
while (1) {
if (ulTaskNotifyTake(pdFALSE, portMAX_DELAY)) {
while(true) {
while (true) {
buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE);
length = ETH_MAX_PACKET_SIZE;
if (emac_opencores_receive(&emac->parent, buffer, &length) == ESP_OK) {
@@ -243,7 +243,7 @@ static esp_err_t emac_opencores_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint3
while (bytes_remaining > 0) {
uint32_t will_write = MIN(bytes_remaining, DMA_BUF_SIZE);
memcpy(emac->tx_buf[emac->cur_tx_desc], buf, will_write);
openeth_tx_desc_t* desc_ptr = openeth_tx_desc(emac->cur_tx_desc);
openeth_tx_desc_t *desc_ptr = openeth_tx_desc(emac->cur_tx_desc);
openeth_tx_desc_t desc_val = *desc_ptr;
desc_val.wr = (emac->cur_tx_desc == TX_BUF_COUNT - 1);
desc_val.len = will_write;
@@ -294,7 +294,7 @@ static esp_err_t emac_opencores_init(esp_eth_mac_t *mac)
esp_eth_mediator_t *eth = emac->eth;
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
// Sanity check
if (REG_READ(OPENETH_MODER_REG) != OPENETH_MODER_DEFAULT) {
ESP_LOGE(TAG, "CONFIG_ETH_USE_OPENETH should only be used when running in QEMU.");
@@ -323,15 +323,17 @@ static esp_err_t emac_opencores_deinit(esp_eth_mac_t *mac)
static esp_err_t emac_opencores_del(esp_eth_mac_t *mac)
{
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
esp_intr_free(emac->intr_hdl);
vTaskDelete(emac->rx_task_hdl);
for (int i = 0; i < RX_BUF_COUNT; i++) {
free(emac->rx_buf[i]);
if (atomic_fetch_sub(&mac->ref_count, 1) == 1) {
esp_intr_free(emac->intr_hdl);
vTaskDelete(emac->rx_task_hdl);
for (int i = 0; i < RX_BUF_COUNT; i++) {
free(emac->rx_buf[i]);
}
for (int i = 0; i < TX_BUF_COUNT; i++) {
free(emac->tx_buf[i]);
}
free(emac);
}
for (int i = 0; i < TX_BUF_COUNT; i++) {
free(emac->tx_buf[i]);
}
free(emac);
return ESP_OK;
}
@@ -378,7 +380,8 @@ esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config)
emac->parent.set_promiscuous = emac_opencores_set_promiscuous;
emac->parent.transmit = emac_opencores_transmit;
emac->parent.receive = emac_opencores_receive;
atomic_init(&emac->parent.ref_count, 1);
// Initialize the interrupt
MAC_CHECK(esp_intr_alloc(OPENETH_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_opencores_isr_handler,
emac, &(emac->intr_hdl)) == ESP_OK,

View File

@@ -19,6 +19,7 @@
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "dm9051";
#define PHY_CHECK(a, str, goto_tag, ...) \
@@ -83,6 +84,7 @@ typedef struct {
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_dm9051_t;
static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
@@ -176,6 +178,19 @@ err:
return ESP_FAIL;
}
static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
// set reset_gpio_num minus zero can skip hardware reset phy chip
if (dm9051->reset_gpio_num >= 0) {
gpio_pad_select_gpio(dm9051->reset_gpio_num);
gpio_set_direction(dm9051->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(dm9051->reset_gpio_num, 0);
gpio_set_level(dm9051->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
@@ -261,7 +276,9 @@ err:
static esp_err_t dm9051_del(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
free(dm9051);
if (atomic_fetch_sub(&phy->ref_count, 1) == 1) {
free(dm9051);
}
return ESP_OK;
}
@@ -304,9 +321,11 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
PHY_CHECK(dm9051, "calloc dm9051 failed", err);
dm9051->addr = config->phy_addr;
dm9051->reset_timeout_ms = config->reset_timeout_ms;
dm9051->reset_gpio_num = config->reset_gpio_num;
dm9051->link_status = ETH_LINK_DOWN;
dm9051->autonego_timeout_ms = config->autonego_timeout_ms;
dm9051->parent.reset = dm9051_reset;
dm9051->parent.reset_hw = dm9051_reset_hw;
dm9051->parent.init = dm9051_init;
dm9051->parent.deinit = dm9051_deinit;
dm9051->parent.set_mediator = dm9051_set_mediator;
@@ -316,6 +335,8 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
dm9051->parent.get_addr = dm9051_get_addr;
dm9051->parent.set_addr = dm9051_set_addr;
dm9051->parent.del = dm9051_del;
atomic_init(&dm9051->parent.ref_count, 1);
return &(dm9051->parent);
err:
return NULL;

View File

@@ -19,6 +19,7 @@
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "dp83848";
#define PHY_CHECK(a, str, goto_tag, ...) \
@@ -89,6 +90,7 @@ typedef struct {
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_dp83848_t;
static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
@@ -174,6 +176,18 @@ err:
return ESP_FAIL;
}
static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
if (dp83848->reset_gpio_num >= 0) {
gpio_pad_select_gpio(dp83848->reset_gpio_num);
gpio_set_direction(dp83848->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(dp83848->reset_gpio_num, 0);
gpio_set_level(dp83848->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
@@ -260,7 +274,9 @@ err:
static esp_err_t dp83848_del(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
free(dp83848);
if (atomic_fetch_sub(&phy->ref_count, 1) == 1) {
free(dp83848);
}
return ESP_OK;
}
@@ -303,8 +319,10 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
dp83848->addr = config->phy_addr;
dp83848->reset_timeout_ms = config->reset_timeout_ms;
dp83848->link_status = ETH_LINK_DOWN;
dp83848->reset_gpio_num = config->reset_gpio_num;
dp83848->autonego_timeout_ms = config->autonego_timeout_ms;
dp83848->parent.reset = dp83848_reset;
dp83848->parent.reset_hw = dp83848_reset_hw;
dp83848->parent.init = dp83848_init;
dp83848->parent.deinit = dp83848_deinit;
dp83848->parent.set_mediator = dp83848_set_mediator;
@@ -314,6 +332,7 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
dp83848->parent.get_addr = dp83848_get_addr;
dp83848->parent.set_addr = dp83848_set_addr;
dp83848->parent.del = dp83848_del;
atomic_init(&dp83848->parent.ref_count, 1);
return &(dp83848->parent);
err:

View File

@@ -19,6 +19,7 @@
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "ip101";
#define PHY_CHECK(a, str, goto_tag, ...) \
@@ -106,6 +107,7 @@ typedef struct {
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_ip101_t;
static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page)
@@ -214,6 +216,18 @@ err:
return ESP_FAIL;
}
static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
if (ip101->reset_gpio_num >= 0) {
gpio_pad_select_gpio(ip101->reset_gpio_num);
gpio_set_direction(ip101->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(ip101->reset_gpio_num, 0);
gpio_set_level(ip101->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
@@ -297,7 +311,9 @@ err:
static esp_err_t ip101_del(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
free(ip101);
if (atomic_fetch_sub(&phy->ref_count, 1) == 1) {
free(ip101);
}
return ESP_OK;
}
@@ -336,9 +352,11 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
PHY_CHECK(ip101, "calloc ip101 failed", err);
ip101->addr = config->phy_addr;
ip101->reset_timeout_ms = config->reset_timeout_ms;
ip101->reset_gpio_num = config->reset_gpio_num;
ip101->link_status = ETH_LINK_DOWN;
ip101->autonego_timeout_ms = config->autonego_timeout_ms;
ip101->parent.reset = ip101_reset;
ip101->parent.reset_hw = ip101_reset_hw;
ip101->parent.init = ip101_init;
ip101->parent.deinit = ip101_deinit;
ip101->parent.set_mediator = ip101_set_mediator;
@@ -348,6 +366,7 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
ip101->parent.get_addr = ip101_get_addr;
ip101->parent.set_addr = ip101_set_addr;
ip101->parent.del = ip101_del;
atomic_init(&ip101->parent.ref_count, 1);
return &(ip101->parent);
err:

View File

@@ -19,6 +19,7 @@
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "lan8720";
#define PHY_CHECK(a, str, goto_tag, ...) \
@@ -161,6 +162,7 @@ typedef struct {
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_lan8720_t;
static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
@@ -256,6 +258,18 @@ err:
return ESP_FAIL;
}
static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
if (lan8720->reset_gpio_num >= 0) {
gpio_pad_select_gpio(lan8720->reset_gpio_num);
gpio_set_direction(lan8720->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(lan8720->reset_gpio_num, 0);
gpio_set_level(lan8720->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
@@ -341,7 +355,9 @@ err:
static esp_err_t lan8720_del(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
free(lan8720);
if (atomic_fetch_sub(&phy->ref_count, 1) == 1) {
free(lan8720);
}
return ESP_OK;
}
@@ -381,10 +397,12 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t));
PHY_CHECK(lan8720, "calloc lan8720 failed", err);
lan8720->addr = config->phy_addr;
lan8720->reset_gpio_num = config->reset_gpio_num;
lan8720->reset_timeout_ms = config->reset_timeout_ms;
lan8720->link_status = ETH_LINK_DOWN;
lan8720->autonego_timeout_ms = config->autonego_timeout_ms;
lan8720->parent.reset = lan8720_reset;
lan8720->parent.reset_hw = lan8720_reset_hw;
lan8720->parent.init = lan8720_init;
lan8720->parent.deinit = lan8720_deinit;
lan8720->parent.set_mediator = lan8720_set_mediator;
@@ -394,6 +412,7 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
lan8720->parent.get_addr = lan8720_get_addr;
lan8720->parent.set_addr = lan8720_set_addr;
lan8720->parent.del = lan8720_del;
atomic_init(&lan8720->parent.ref_count, 1);
return &(lan8720->parent);
err:

View File

@@ -20,6 +20,7 @@
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "rtl8201";
#define PHY_CHECK(a, str, goto_tag, ...) \
@@ -67,6 +68,7 @@ typedef struct {
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
int reset_gpio_num;
} phy_rtl8201_t;
static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page)
@@ -165,6 +167,18 @@ err:
return ESP_FAIL;
}
static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
if (rtl8201->reset_gpio_num >= 0) {
gpio_pad_select_gpio(rtl8201->reset_gpio_num);
gpio_set_direction(rtl8201->reset_gpio_num, GPIO_MODE_OUTPUT);
gpio_set_level(rtl8201->reset_gpio_num, 0);
gpio_set_level(rtl8201->reset_gpio_num, 1);
}
return ESP_OK;
}
static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
@@ -248,7 +262,9 @@ err:
static esp_err_t rtl8201_del(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
free(rtl8201);
if (atomic_fetch_sub(&phy->ref_count, 1) == 1) {
free(rtl8201);
}
return ESP_OK;
}
@@ -289,10 +305,12 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
PHY_CHECK(rtl8201, "calloc rtl8201 failed", err);
rtl8201->addr = config->phy_addr;
rtl8201->reset_gpio_num = config->reset_gpio_num;
rtl8201->reset_timeout_ms = config->reset_timeout_ms;
rtl8201->link_status = ETH_LINK_DOWN;
rtl8201->autonego_timeout_ms = config->autonego_timeout_ms;
rtl8201->parent.reset = rtl8201_reset;
rtl8201->parent.reset_hw = rtl8201_reset_hw;
rtl8201->parent.init = rtl8201_init;
rtl8201->parent.deinit = rtl8201_deinit;
rtl8201->parent.set_mediator = rtl8201_set_mediator;
@@ -302,6 +320,7 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
rtl8201->parent.get_addr = rtl8201_get_addr;
rtl8201->parent.set_addr = rtl8201_set_addr;
rtl8201->parent.del = rtl8201_del;
atomic_init(&rtl8201->parent.ref_count, 1);
return &(rtl8201->parent);
err:

View File

@@ -1,5 +1,7 @@
if(IDF_TARGET STREQUAL "esp32")
idf_build_get_property(target IDF_TARGET)
# Currently we only have unit test for esp32
if(${target} STREQUAL "esp32")
idf_component_register(SRC_DIRS .
INCLUDE_DIRS .
PRIV_REQUIRES unity test_utils esp_eth)
INCLUDE_DIRS .
PRIV_REQUIRES unity test_utils esp_eth)
endif()

View File

@@ -9,6 +9,7 @@
#include "esp_event.h"
#include "esp_eth.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
@@ -170,8 +171,6 @@ TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]")
/* wait for connection stop */
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
// "check link timer callback" might owned the reference of phy object, make sure it has release it
vTaskDelay(pdMS_TO_TICKS(2000));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
@@ -209,8 +208,6 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]")
/* wait for connection stop */
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
// "check link timer callback" might owned the reference of phy object, make sure it has release it
vTaskDelay(pdMS_TO_TICKS(2000));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
@@ -292,8 +289,6 @@ TEST_CASE("esp32 ethernet icmp test", "[ethernet][test_env=UT_T2_Ethernet]")
/* wait for connection stop */
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
// "check link timer callback" might owned the reference of phy object, make sure it has release it
vTaskDelay(pdMS_TO_TICKS(2000));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));

View File

@@ -550,7 +550,7 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t
return len;
}
void emac_hal_isr(void *arg)
IRAM_ATTR void emac_hal_isr(void *arg)
{
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus;
@@ -621,7 +621,7 @@ void emac_hal_isr(void *arg)
}
}
__attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
@@ -629,7 +629,7 @@ __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
return;
}
__attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
@@ -637,7 +637,7 @@ __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
return;
}
__attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
@@ -645,7 +645,7 @@ __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
return;
}
__attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
@@ -653,7 +653,7 @@ __attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
return;
}
__attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg)
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function

View File

@@ -14,10 +14,3 @@ entries:
spi_slave_hal_iram (noflash_text)
spi_flash_hal_iram (noflash)
lldesc (noflash_text)
if ETH_USE_ESP32_EMAC = y:
emac_hal:emac_hal_isr (noflash_text)
emac_hal:emac_hal_tx_complete_cb (noflash_text)
emac_hal:emac_hal_tx_unavail_cb (noflash_text)
emac_hal:emac_hal_rx_complete_cb (noflash_text)
emac_hal:emac_hal_rx_early_cb (noflash_text)
emac_hal:emac_hal_rx_unavail_cb (noflash_text)