mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
wifi_drv: use task for sending frames
Until now the client called the Linux code directly through the EP when sending ethernet frames and was not part of the driver's internal task scheduling. This will lead to problems if the sending code needs to grab a lock as those depend on running from within a Lx::Task. Although this has only happend recently when using 8260 devices, this is an issue that needs to be fix. This commit addresses the issue by using a dedicated transmit task in whose context the Linux code sends the ethernet frame or rather newly allocated skb. Fixes #2559.
This commit is contained in:
parent
bb95121ee5
commit
2f32308c0b
@ -48,21 +48,50 @@ class Wifi_session_component : public Nic::Session_component
|
||||
net_device *_ndev;
|
||||
bool _has_link = !(_ndev->state & 1UL << __LINK_STATE_NOCARRIER);
|
||||
|
||||
struct Tx_data
|
||||
{
|
||||
net_device *ndev;
|
||||
struct sk_buff *skb;
|
||||
} _tx_data;
|
||||
|
||||
static void _run_tx_task(void *args)
|
||||
{
|
||||
Tx_data *data = static_cast<Tx_data*>(args);
|
||||
|
||||
while (1) {
|
||||
Lx::scheduler().current()->block_and_schedule();
|
||||
|
||||
net_device *ndev = data->ndev;
|
||||
struct sk_buff *skb = data->skb;
|
||||
|
||||
ndev->netdev_ops->ndo_start_xmit(skb, ndev);
|
||||
}
|
||||
}
|
||||
|
||||
Lx::Task _tx_task { _run_tx_task, &_tx_data, "tx_task",
|
||||
Lx::Task::PRIORITY_1, Lx::scheduler() };
|
||||
|
||||
protected:
|
||||
|
||||
bool _send()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
/*
|
||||
* We must not be called from another task, just from the
|
||||
* packet stream dispatcher.
|
||||
*/
|
||||
if (Lx::scheduler().active()) {
|
||||
warning("scheduler active");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
if (!_tx.sink()->ready_to_ack()) { return false; }
|
||||
if (!_tx.sink()->packet_avail()) { return false; }
|
||||
|
||||
Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.size()) {
|
||||
Genode::warning("invalid tx packet");
|
||||
warning("invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -71,18 +100,29 @@ class Wifi_session_component : public Nic::Session_component
|
||||
unsigned char *data = lxc_skb_put(skb, packet.size());
|
||||
Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size());
|
||||
|
||||
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
|
||||
_tx_data.ndev = _ndev;
|
||||
_tx_data.skb = skb;
|
||||
|
||||
_tx_task.unblock();
|
||||
Lx::scheduler().schedule();
|
||||
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handle_packet_stream()
|
||||
void _handle_rx()
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
while (_rx.source()->ack_avail()) {
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
}
|
||||
}
|
||||
|
||||
while (_send()) ;
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
_handle_rx();
|
||||
|
||||
while (_send()) { continue; }
|
||||
}
|
||||
|
||||
public:
|
||||
@ -117,7 +157,7 @@ class Wifi_session_component : public Nic::Session_component
|
||||
|
||||
void receive(struct sk_buff *skb)
|
||||
{
|
||||
_handle_packet_stream();
|
||||
_handle_rx();
|
||||
|
||||
if (!_rx.source()->ready_to_submit()) {
|
||||
Genode::warning("not ready to receive packet");
|
||||
|
Loading…
x
Reference in New Issue
Block a user