Commit Graph

13 Commits

Author SHA1 Message Date
Marcin Niestroj
70efb83fd2 drivers: wifi: esp: process received packets in esp_rx thread
So far received packets were parsed (at AT command level) and allocated
in [esp_rx] thread. Then they were submitted to [esp_workq] thread for
processing (calling application callback).

This flow results in following deadlock when esp_workq thread waits on
response to some AT command:

  - [esp_rx] waits on allocation of new RX packet
  - [esp_workq] waits for [esp_rx] to process response to AT command
    that was just sent
  - blocked [esp_workq] prevents processing and deallocating RX packets
  - [esp_rx] times out on allocation and closes socket

Process RX packets directly from [esp_rx] thread to prevent above
deadlock.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-02-05 11:42:03 -05:00
Marcin Niestroj
705eb1d2b0 drivers: wifi: esp: access socket type and ip_proto from net_context
net_context contains both net_sock_type and net_ip_protocol, which are
static during the lifetime of net_context. net_context has basically the
ownership of esp_socket, so we can be sure 'type' and 'ip_proto' are
always accessible through net_context API.

Remove 'type' and 'ip_proto' members from 'esp_socket' structure, as
those are already accessible by net_context API.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-01-26 14:47:46 -05:00
Marcin Niestroj
cad292e17f drivers: wifi: esp: add thread-safety on esp_socket operations
Change type of esp_socket->flags from uint8_t to atomic_t, so that read
and write access to those flags is done in atomic (thread-safe) manner.

Introduce esp_socket_ref() and esp_socket_unref() functions, which
operate on atomic refcount variable. esp_socket_ref() role is to
increase refcount if it was already non-zero. If it was zero then NULL
is returned, which means that socket is not used by net_context at the
moment.

Role of refcount:
 * socket instance is assured to be between net_offload->get() and
   net_offload->put() when refcount > 0,
 * makes sure that socket instance can be used (its members can be
   dereferenced) when refcount > 0,
 * 'context' member is always valid and its members can be dereferenced
   when refcount > 0.

esp_socket_get() gets unused socket, as previously. Additionally it sets
refcount to 1 at the end of call, which basically means that from that
point such socket can be referenced by other parts of the driver. Each
esp_socket_get() call should be followed by esp_socket_unref() and
esp_socket_put() to properly invalidate socket and prevent other parts
of driver from using it.

Add ESP_SOCK_WORKQ_STOPPED flag, which is now used to prevent scheduling
more work into driver workqueue. This flag is set in net_offload->put()
callback, so that no more socket work (such as processing RX/TX packets
or closing socket because of errors) is submitted after that.

Introduce mutex lock, which has following role:
 * protects dst, connect_cb + conn_user_data, recv_cb + recv_user_data,
 * assures that checking ESP_SOCK_WORKQ_STOPPED flag and actually
   submitting (or not if net_offload->put was already called) new socket
   work to workqueue is done in atomic way.

As there is a mechanism to prevent submitting new work items to
workqueue when net_offload->put() has been executed, then there is no
need to explicitly call esp_socket_ref() in esp_workq thread. This is
because one reference is being held by net_context (after calling
net_context->get()). This is why all the esp_socket_in_use() were simply
dropped. Code running from esp_rx thread on the other hand always uses
esp_socket_ref_from_link_id() helper function (which is backed by
esp_socket_ref()), so that it replaces previous esp_socket_in_use()
calls and additionally makes sure that socket stays valid ("in use")
until esp_socket_unref() is called.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-01-26 14:47:46 -05:00
Marcin Niestroj
956923f8e5 drivers: wifi: esp: schedule each RX packet on separate work
So far a dedicated FIFO was used for all RX packets, which was consumed
in single submitted work. This work was also responsible for closing
socket and notifying uppper network layers if some errors occurred
previously or socket was simply closed by peer. There is however a
potential race condition in scenario described below:

  esp_rx thread             | esp_workq thread
  --------------------------|-----------------------------
                            | ---- esp_recv_work ----
                            | handle RX packets from FIFO
                            |
  ---- on_cmd_ipd ----      |
  put new RX packet to FIFO |
  ---- on_cmd_ipd ----      |
                            |
  ---- on_cmd_closed ----   |
  mark socket as closed     |
  ---- on_cmd_closed ----   |
                            |
                            | handle close
                            | ---- esp_recv_work ----

In this case we assume that esp_workq was preempted just after
processing all RX packets from FIFO and before checking if socket was
closed. In such scenario RX packet put to FIFO just before doing close
is going to be unhandled, so application layer will miss part of the
data.

Change the way RX packets are scheduled to workqueue, by using the
already available net_pkt->work objects (used for example in native TCP
stack). Create a separate work for closing connection. As a result all
RX packets and close handlers are on the same queue and there is no risk
of handling close events before handling all previously received data.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-01-22 12:02:10 +01:00
Marcin Niestroj
dca2fd8042 drivers: wifi: esp: flush socket work items in socket put
There might be some scheduled work related to socket currently requested
to be destroyed/closed. Schedule a dummy work to make sure all
previously running work items in workqueue are finished.

When talking about TX packets, this makes sure that all previously
scheduled data is actually sent (flushed) before closing socket.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-01-22 12:02:10 +01:00
Marcin Niestroj
74e4f77fb4 drivers: wifi: esp: initialize per socket work structures only once
It is enough to initialize work structures once during driver init,
because work handlers do not change during driver lifetime.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2021-01-22 12:02:10 +01:00
Marcin Niestroj
b2b8554da8 drivers: wifi: esp: deduplicate RX data processing
Deduplicate final part of RX data processing for two supported cases:
passive (+CIPRECVDATA) and non-passive (+IPD). Move implementation to
esp_socket module, as this is strictly related to socket.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-12-17 14:38:02 +02:00
Marcin Niestroj
1814e2c8f1 drivers: wifi: esp: unify log level
2 (out of 3) components used CONFIG_WIFI_LOG_LEVEL, while the last one
didn't specify explicit log level. Always use CONFIG_WIFI_LOG_LEVEL in
all components.

While at it switch to LOG_MODULE_REGISTER(<module>, <log_level>), which
is a more compact way to define log level.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-12-17 11:42:32 +02:00
Marcin Niestroj
add649adcd drivers: wifi: esp: calculate size of each command buffer
Calculate size based on the real message, instead of assuming some
arbitrary size. This consumes slightly less stack space, but more
importantly gives an idea what has been taken into account when
calculating the size.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-12-17 11:42:16 +02:00
Marcin Niestroj
347c2501d7 drivers: wifi: esp: add esp_cmd_send() helper function
All except one invocations of modem_cmd_send() pass the same interface,
command handler and semaphore. Create a helper function in order to make
invocations slightly more readable.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-12-01 11:16:36 -05:00
Marcin Niestroj
8027612529 drivers: wifi: esp: close stream socket on allocation failure
There is no reason to keep active stream socket when there was some data
loss. Mark such socket for closing and close it when all (so far)
received packets have been processed.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
2020-11-03 09:28:45 -06:00
Kumar Gala
a1b77fd589 zephyr: replace zephyr integer types with C99 types
git grep -l 'u\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/u\(8\|16\|32\|64\)_t/uint\1_t/g"
	git grep -l 's\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/s\(8\|16\|32\|64\)_t/int\1_t/g"

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-06-08 08:23:57 -05:00
Tobias Svehagen
7b5f6bc660 drivers: wifi: Add ESP8266 and ESP32 wifi modem driver
This adds support for the Espressif ESP8266 and ESP32 devices to be used
as peripherals on a UART.

There are two main AT command versions that can be selected, 1.7 and
2.0. Since they behave a bit different it is important to select the
one that matches the used in the firmware on your device.

When downloading large amounts of data it is highly recommended to
enable CONFIG_ESP_PASSIVE_TCP and flow control on the UART so that
data is not lost due to UART speed or receive buffer size.

Currently unsupported:
- Changing UDP endpoint with a sendto()
- Bind to a specific local port
- Server socket operations, ie listen() and accept()

Official AT firmware for ESP8266 and ESP32 can be found at:
https://github.com/espressif/esp-at

Signed-off-by: Tobias Svehagen <tobias.svehagen@gmail.com>
2020-03-21 19:08:02 +02:00