Browse Source

esp_wifi: optimize WiFi TX performance

liu zhifu 6 năm trước cách đây
mục cha
commit
fa9a5c0be5

+ 6 - 0
components/esp_common/src/esp_err_to_name.c

@@ -354,6 +354,12 @@ static const esp_err_msg_t esp_err_msg_table[] = {
 #   endif
 #   ifdef      ESP_ERR_WIFI_STOP_STATE
     ERR_TBL_IT(ESP_ERR_WIFI_STOP_STATE),                        /* 12308 0x3014 Returned when WiFi is stopping */
+#   endif
+#   ifdef      ESP_ERR_WIFI_NOT_ASSOC
+    ERR_TBL_IT(ESP_ERR_WIFI_NOT_ASSOC),                         /* 12309 0x3015 The WiFi connection is not associated */
+#   endif
+#   ifdef      ESP_ERR_WIFI_TX_DISALLOW
+    ERR_TBL_IT(ESP_ERR_WIFI_TX_DISALLOW),                       /* 12310 0x3016 The WiFi TX is disallowed */
 #   endif
     // components/wpa_supplicant/include/esp_supplicant/esp_wps.h
 #   ifdef      ESP_ERR_WIFI_REGISTRAR

+ 16 - 0
components/esp_netif/include/esp_netif.h

@@ -815,6 +815,22 @@ esp_netif_t *esp_netif_next(esp_netif_t *esp_netif);
  */
 size_t esp_netif_get_nr_of_ifs(void);
 
+/**
+ * @brief increase the reference counter of net stack buffer
+ *
+ * @param[in]  netstack_buf the net stack buffer
+ *
+ */
+void esp_netif_netstack_buf_ref(void *netstack_buf);
+
+/**
+ * @brief free the netstack buffer
+ *
+ * @param[in]  netstack_buf the net stack buffer
+ *
+ */
+void esp_netif_netstack_buf_free(void *netstack_buf);
+
 /**
  * @}
  */

+ 14 - 0
components/esp_netif/include/esp_netif_net_stack.h

@@ -69,6 +69,20 @@ void* esp_netif_get_netif_impl(esp_netif_t *esp_netif);
   */
 esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len);
 
+/**
+  * @brief  Outputs packets from the TCP/IP stack to the media to be transmitted
+  *
+  * This function gets called from network stack to output packets to IO driver.
+  *
+  * @param[in]  esp_netif Handle to esp-netif instance
+  * @param[in]  data Data to be transmitted
+  * @param[in]  len Length of the data frame
+  * @param[in]  netstack_buf net stack buffer
+  *
+  * @return   ESP_OK on success, an error passed from the I/O driver otherwise
+  */
+esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *netstack_buf);
+
 /**
   * @brief  Free the rx buffer allocated by the media driver
   *

+ 1 - 0
components/esp_netif/include/esp_netif_types.h

@@ -187,6 +187,7 @@ typedef struct esp_netif_driver_base_s {
 struct esp_netif_driver_ifconfig {
     esp_netif_iodriver_handle handle;
     esp_err_t (*transmit)(void *h, void *buffer, size_t len);
+    esp_err_t (*transmit_wrap)(void *h, void *buffer, size_t len, void *netstack_buffer);
     void (*driver_free_rx_buffer)(void *h, void* buffer);
 };
 

+ 19 - 0
components/esp_netif/lwip/esp_netif_lwip.c

@@ -388,6 +388,9 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
         if (esp_netif_driver_config->transmit) {
             esp_netif->driver_transmit = esp_netif_driver_config->transmit;
         }
+        if (esp_netif_driver_config->transmit_wrap) {
+            esp_netif->driver_transmit_wrap = esp_netif_driver_config->transmit_wrap;
+        }
         if (esp_netif_driver_config->driver_free_rx_buffer) {
             esp_netif->driver_free_rx_buffer = esp_netif_driver_config->driver_free_rx_buffer;
         }
@@ -549,6 +552,7 @@ esp_err_t esp_netif_set_driver_config(esp_netif_t *esp_netif,
     }
     esp_netif->driver_handle = driver_config->handle;
     esp_netif->driver_transmit = driver_config->transmit;
+    esp_netif->driver_transmit_wrap = driver_config->transmit_wrap;
     esp_netif->driver_free_rx_buffer = driver_config->driver_free_rx_buffer;
     return ESP_OK;
 }
@@ -762,6 +766,16 @@ esp_err_t esp_netif_stop(esp_netif_t *esp_netif)
     return esp_netif_lwip_ipc_call(esp_netif_stop_api, esp_netif, NULL);
 }
 
+void esp_netif_netstack_buf_ref(void *pbuf)
+{
+    pbuf_ref(pbuf);
+}
+
+void esp_netif_netstack_buf_free(void *pbuf)
+{
+    pbuf_free(pbuf);
+}
+
 //
 // IO translate functions
 //
@@ -776,6 +790,11 @@ esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len)
     return (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len);
 }
 
+esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *pbuf)
+{
+    return (esp_netif->driver_transmit_wrap)(esp_netif->driver_handle, data, len, pbuf);
+}
+
 esp_err_t esp_netif_receive(esp_netif_t *esp_netif, void *buffer, size_t len, void *eb)
 {
     esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);

+ 1 - 0
components/esp_netif/lwip/esp_netif_lwip_internal.h

@@ -107,6 +107,7 @@ struct esp_netif_obj {
     // io driver related
     void* driver_handle;
     esp_err_t (*driver_transmit)(void *h, void *buffer, size_t len);
+    esp_err_t (*driver_transmit_wrap)(void *h, void *buffer, size_t len, void *pbuf);
     void (*driver_free_rx_buffer)(void *h, void* buffer);
 
     // dhcp related

+ 14 - 2
components/esp_wifi/Kconfig

@@ -90,6 +90,19 @@ menu "Wi-Fi"
             layer can deliver frames faster than WiFi layer can transmit. In these cases, we may run out
             of TX buffers.
 
+    config ESP32_WIFI_CACHE_TX_BUFFER_NUM
+        int "Max number of WiFi cache TX buffers"
+        depends on (ESP32_SPIRAM_SUPPORT || ESP32S2_SPIRAM_SUPPORT)
+        range 16 128
+        default 32
+        help
+            Set the number of WiFi cache TX buffer number.
+
+            For each TX packet from uplayer, such as LWIP etc, WiFi driver needs to allocate a static TX
+            buffer and makes a copy of uplayer packet. If WiFi driver fails to allocate the static TX buffer,
+            it caches the uplayer packets to a dedicated buffer queue, this option is used to configure the
+            size of the cached TX queue.
+
     config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
         int "Max number of WiFi dynamic TX buffers"
         depends on ESP32_WIFI_DYNAMIC_TX_BUFFER
@@ -139,8 +152,7 @@ menu "Wi-Fi"
     config ESP32_WIFI_RX_BA_WIN
         int "WiFi AMPDU RX BA window size"
         depends on ESP32_WIFI_AMPDU_RX_ENABLED
-        range 2 32 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
-        range 16 32 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
+        range 2 32
         default 6 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         default 16 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         help

+ 65 - 13
components/esp_wifi/include/esp_private/wifi.h

@@ -119,15 +119,6 @@ esp_err_t esp_wifi_init_internal(const wifi_init_config_t *config);
  */
 esp_err_t esp_wifi_deinit_internal(void);
 
-/**
-  * @brief  get whether the wifi driver is allowed to transmit data or not
-  *
-  * @return
-  *     - true  : upper layer should stop to transmit data to wifi driver
-  *     - false : upper layer can transmit data to wifi driver
-  */
-bool esp_wifi_internal_tx_is_stop(void);
-
 /**
   * @brief  free the rx buffer which allocated by wifi driver
   *
@@ -138,18 +129,79 @@ void esp_wifi_internal_free_rx_buffer(void* buffer);
 /**
   * @brief  transmit the buffer via wifi driver
   *
+  * This API makes a copy of the input buffer and then forwards the buffer
+  * copy to WiFi driver.
+  *
   * @param  wifi_interface_t wifi_if : wifi interface id
   * @param  void *buffer : the buffer to be tansmit
   * @param  uint16_t len : the length of buffer
   *
   * @return
-  *    - ERR_OK  : Successfully transmit the buffer to wifi driver
-  *    - ERR_MEM : Out of memory
-  *    - ERR_IF : WiFi driver error
-  *    - ERR_ARG : Invalid argument
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - ESP_ERR_NO_MEM: out of memory
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF : WiFi interface is invalid
+  *    - ESP_ERR_WIFI_CONN : WiFi interface is not created, e.g. send the data to STA while WiFi mode is AP mode
+  *    - ESP_ERR_WIFI_NOT_STARTED : WiFi is not started
+  *    - ESP_ERR_WIFI_STATE : WiFi internal state is not ready, e.g. WiFi is not started
+  *    - ESP_ERR_WIFI_NOT_ASSOC : WiFi is not associated
+  *    - ESP_ERR_WIFI_TX_DISALLOW : WiFi TX is disallowed, e.g. WiFi hasn't pass the authentication 
+  *    - ESP_ERR_WIFI_POST : caller fails to post event to WiFi task
   */
 int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, uint16_t len);
 
+/**
+  * @brief     The net stack buffer reference counter callback function
+  *
+  */
+typedef void (*wifi_netstack_buf_ref_cb_t)(void *netstack_buf);
+
+/**
+  * @brief     The net stack buffer free callback function
+  *
+  */
+typedef void (*wifi_netstack_buf_free_cb_t)(void *netstack_buf);
+
+/**
+  * @brief  transmit the buffer by reference via wifi driver
+  *
+  * This API firstly increases the reference counter of the input buffer and
+  * then forwards the buffer to WiFi driver. The WiFi driver will free the buffer
+  * after processing it. Use esp_wifi_internal_tx() if the uplayer buffer doesn't
+  * supports reference counter.
+  * 
+  * @param  wifi_if : wifi interface id
+  * @param  buffer : the buffer to be tansmit
+  * @param  len : the length of buffer
+  * @param  netstack_buf : the netstack buffer related to bufffer
+  *
+  * @return
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - ESP_ERR_NO_MEM: out of memory
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF : WiFi interface is invalid
+  *    - ESP_ERR_WIFI_CONN : WiFi interface is not created, e.g. send the data to STA while WiFi mode is AP mode
+  *    - ESP_ERR_WIFI_NOT_STARTED : WiFi is not started
+  *    - ESP_ERR_WIFI_STATE : WiFi internal state is not ready, e.g. WiFi is not started
+  *    - ESP_ERR_WIFI_NOT_ASSOC : WiFi is not associated
+  *    - ESP_ERR_WIFI_TX_DISALLOW : WiFi TX is disallowed, e.g. WiFi hasn't pass the authentication 
+  *    - ESP_ERR_WIFI_POST : caller fails to post event to WiFi task
+  */
+esp_err_t esp_wifi_internal_tx_by_ref(wifi_interface_t ifx, void *buffer, size_t len, void *netstack_buf);
+
+/**
+  * @brief  register the net stack buffer reference increasing and free callback
+  *
+  * @param  ref : net stack buffer reference callback
+  * @param  free: net stack buffer free callback
+  *
+  * @return
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - others  : failed to register the callback
+  */
+esp_err_t esp_wifi_internal_reg_netstack_buf_cb(wifi_netstack_buf_ref_cb_t ref, wifi_netstack_buf_free_cb_t free);
+
+
 /**
   * @brief     The WiFi RX callback function
   *

+ 11 - 8
components/esp_wifi/include/esp_wifi.h

@@ -88,6 +88,8 @@ extern "C" {
 #define ESP_ERR_WIFI_POST        (ESP_ERR_WIFI_BASE + 18)  /*!< Failed to post the event to WiFi task */
 #define ESP_ERR_WIFI_INIT_STATE  (ESP_ERR_WIFI_BASE + 19)  /*!< Invalod WiFi state when init/deinit is called */
 #define ESP_ERR_WIFI_STOP_STATE  (ESP_ERR_WIFI_BASE + 20)  /*!< Returned when WiFi is stopping */
+#define ESP_ERR_WIFI_NOT_ASSOC   (ESP_ERR_WIFI_BASE + 21)  /*!< The WiFi connection is not associated */
+#define ESP_ERR_WIFI_TX_DISALLOW (ESP_ERR_WIFI_BASE + 22)  /*!< The WiFi TX is disallowed */
 
 /**
  * @brief WiFi stack configuration parameters passed to esp_wifi_init call.
@@ -101,12 +103,12 @@ typedef struct {
     int                    tx_buf_type;            /**< WiFi TX buffer type */
     int                    static_tx_buf_num;      /**< WiFi static TX buffer number */
     int                    dynamic_tx_buf_num;     /**< WiFi dynamic TX buffer number */
+    int                    cache_tx_buf_num;       /**< WiFi TX cache buffer number */
     int                    csi_enable;             /**< WiFi channel state information enable flag */
     int                    ampdu_rx_enable;        /**< WiFi AMPDU RX feature enable flag */
     int                    ampdu_tx_enable;        /**< WiFi AMPDU TX feature enable flag */
     int                    nvs_enable;             /**< WiFi NVS flash enable flag */
     int                    nano_enable;            /**< Nano option for printf/scan family enable flag */
-    int                    tx_ba_win;              /**< WiFi Block Ack TX window size */
     int                    rx_ba_win;              /**< WiFi Block Ack RX window size */
     int                    wifi_task_core_id;      /**< WiFi Task Core ID */
     int                    beacon_max_len;         /**< WiFi softAP maximum length of the beacon */
@@ -121,6 +123,12 @@ typedef struct {
 #define WIFI_STATIC_TX_BUFFER_NUM 0
 #endif
 
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+#define WIFI_CACHE_TX_BUFFER_NUM  CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM
+#else
+#define WIFI_CACHE_TX_BUFFER_NUM  0
+#endif
+
 #ifdef CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
 #define WIFI_DYNAMIC_TX_BUFFER_NUM CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
 #else
@@ -162,12 +170,6 @@ extern uint64_t g_wifi_feature_caps;
 
 #define WIFI_INIT_CONFIG_MAGIC    0x1F2F3F4F
 
-#ifdef CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED
-#define WIFI_DEFAULT_TX_BA_WIN CONFIG_ESP32_WIFI_TX_BA_WIN
-#else
-#define WIFI_DEFAULT_TX_BA_WIN 0 /* unused if ampdu_tx_enable == false */
-#endif
-
 #ifdef CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED
 #define WIFI_DEFAULT_RX_BA_WIN CONFIG_ESP32_WIFI_RX_BA_WIN
 #else
@@ -193,6 +195,7 @@ extern uint64_t g_wifi_feature_caps;
 #endif
 
 #define CONFIG_FEATURE_WPA3_SAE_BIT     (1<<0)
+#define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1)
 
 #define WIFI_INIT_CONFIG_DEFAULT() { \
     .event_handler = &esp_event_send_internal, \
@@ -203,12 +206,12 @@ extern uint64_t g_wifi_feature_caps;
     .tx_buf_type = CONFIG_ESP32_WIFI_TX_BUFFER_TYPE,\
     .static_tx_buf_num = WIFI_STATIC_TX_BUFFER_NUM,\
     .dynamic_tx_buf_num = WIFI_DYNAMIC_TX_BUFFER_NUM,\
+    .cache_tx_buf_num = WIFI_CACHE_TX_BUFFER_NUM,\
     .csi_enable = WIFI_CSI_ENABLED,\
     .ampdu_rx_enable = WIFI_AMPDU_RX_ENABLED,\
     .ampdu_tx_enable = WIFI_AMPDU_TX_ENABLED,\
     .nvs_enable = WIFI_NVS_ENABLED,\
     .nano_enable = WIFI_NANO_FORMAT_ENABLED,\
-    .tx_ba_win = WIFI_DEFAULT_TX_BA_WIN,\
     .rx_ba_win = WIFI_DEFAULT_RX_BA_WIN,\
     .wifi_task_core_id = WIFI_TASK_CORE_ID,\
     .beacon_max_len = WIFI_SOFTAP_BEACON_MAX_LEN, \

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit c934be7c20279db86e825fd44f7bc7eef9929ac1
+Subproject commit 0848a017746bd66be29999515cba20e0fd530819

+ 4 - 0
components/esp_wifi/src/wifi_default.c

@@ -58,6 +58,10 @@ static void wifi_start(void *esp_netif, esp_event_base_t base, int32_t event_id,
         }
     }
 
+    if ((ret = esp_wifi_internal_reg_netstack_buf_cb(esp_netif_netstack_buf_ref, esp_netif_netstack_buf_free)) != ESP_OK) {
+        ESP_LOGE(TAG, "netstack cb reg failed with %d", ret);
+        return;
+    }
     esp_netif_set_mac(esp_netif, mac);
     esp_netif_action_start(esp_netif, base, event_id, data);
 }

+ 3 - 0
components/esp_wifi/src/wifi_init.c

@@ -50,6 +50,9 @@ uint64_t g_wifi_feature_caps =
 #if CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE
     CONFIG_FEATURE_WPA3_SAE_BIT |
 #endif
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+    CONFIG_FEATURE_CACHE_TX_BUF_BIT |
+#endif
 0;
 
 static const char* TAG = "wifi_init";

+ 11 - 0
components/esp_wifi/src/wifi_netif.c

@@ -63,6 +63,16 @@ static esp_err_t wifi_transmit(void *h, void *buffer, size_t len)
     return esp_wifi_internal_tx(driver->wifi_if, buffer, len);
 }
 
+static esp_err_t wifi_transmit_wrap(void *h, void *buffer, size_t len, void *netstack_buf)
+{
+    wifi_netif_driver_t driver = h;
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+    return esp_wifi_internal_tx_by_ref(driver->wifi_if, buffer, len, netstack_buf);
+#else
+    return esp_wifi_internal_tx(driver->wifi_if, buffer, len);
+#endif
+}
+
 static esp_err_t wifi_driver_start(esp_netif_t * esp_netif, void * args)
 {
     wifi_netif_driver_t driver = args;
@@ -70,6 +80,7 @@ static esp_err_t wifi_driver_start(esp_netif_t * esp_netif, void * args)
     esp_netif_driver_ifconfig_t driver_ifconfig = {
             .handle =  driver,
             .transmit = wifi_transmit,
+            .transmit_wrap= wifi_transmit_wrap,
             .driver_free_rx_buffer = wifi_free
     };
 

+ 12 - 4
components/lwip/port/esp32/netif/wlanif.c

@@ -131,10 +131,10 @@ low_level_output(struct netif *netif, struct pbuf *p)
   }
 
   struct pbuf *q = p;
-  err_t ret;
+  esp_err_t ret;
 
   if(q->next == NULL) {
-    ret = esp_netif_transmit(esp_netif, q->payload, q->len);
+    ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
 
   } else {
     LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
@@ -145,12 +145,20 @@ low_level_output(struct netif *netif, struct pbuf *p)
     } else {
       return ERR_MEM;
     }
-    ret = esp_netif_transmit(esp_netif, q->payload, q->len);
+    ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
 
     pbuf_free(q);
   }
 
-  return ret;
+  if (ret == ESP_OK) {
+    return ERR_OK;
+  } else if (ret == ESP_ERR_NO_MEM) {
+    return ERR_MEM;
+  } else if (ret == ESP_ERR_INVALID_ARG) {
+    return ERR_ARG;
+  } else {
+    return ERR_IF;
+  }
 }
 
 /**