diff --git a/repos/dde_ipxe/src/drivers/nic/main.cc b/repos/dde_ipxe/src/drivers/nic/main.cc index e805a1f6d5..6ae85c3ad3 100644 --- a/repos/dde_ipxe/src/drivers/nic/main.cc +++ b/repos/dde_ipxe/src/drivers/nic/main.cc @@ -1,6 +1,7 @@ /* * \brief NIC driver based on iPXE * \author Christian Helmuth + * \author Sebastian Sumpf * \date 2011-11-17 */ @@ -17,131 +18,133 @@ #include #include #include +#include #include #include -namespace Ipxe { +class Ipxe_session_component : public Nic::Session_component +{ + public: - class Driver : public Nic::Driver - { - public: + static Ipxe_session_component *instance; - static Driver *instance; + private: - private: + Nic::Mac_address _mac_addr; - Server::Entrypoint &_ep; + static void _rx_callback(unsigned if_index, + const char *packet, + unsigned packet_len) + { + if (instance) + instance->_receive(packet, packet_len); + } - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; - Nic::Driver_notification &_notify; + static void _link_callback() + { + if (instance) + instance->_link_state_changed(); + } - static void _rx_callback(unsigned if_index, - const char *packet, - unsigned packet_len) - { - instance->rx_handler(packet, packet_len); + bool _send() + { + using namespace Genode; + + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; } - static void _link_callback() { instance->link_state_changed(); } + if (dde_ipxe_nic_tx(1, _tx.sink()->packet_content(packet), packet.size())) + PWRN("Sending packet failed!"); - public: + _tx.sink()->acknowledge_packet(packet); + return true; + } - Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - : _ep(ep), _alloc(alloc), _notify(notify) - { - PINF("--- init callbacks"); - dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback); + void _receive(const char *packet, unsigned packet_len) + { + _handle_packet_stream(); - dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr); - PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x", - _mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff, - _mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff, - _mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff); + if (!_rx.source()->ready_to_submit()) + return; + + try { + Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_len); + Genode::memcpy(_rx.source()->packet_content(p), packet, packet_len); + _rx.source()->submit_packet(p); + } catch (...) { + PDBG("failed to process received packet"); } + } - ~Driver() { dde_ipxe_nic_unregister_callbacks(); } + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); - void rx_handler(const char *packet, unsigned packet_len) - { - try { - void *buffer = _alloc.alloc(packet_len); - Genode::memcpy(buffer, packet, packet_len); - _alloc.submit(); - } catch (...) { - PDBG("failed to process received packet"); - } - } + while (_send()) ; + } - void link_state_changed() { _notify.link_state_changed(); } + public: + + Ipxe_session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) + : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep) + { + instance = this; + + PINF("--- init callbacks"); + dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback); + + dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr); + PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x", + _mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff, + _mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff, + _mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff); + } + + ~Ipxe_session_component() + { + instance = nullptr; + dde_ipxe_nic_unregister_callbacks(); + } + + /************************************** + ** Nic::Session_component interface ** + **************************************/ + + Nic::Mac_address mac_address() override { return _mac_addr; } + + bool link_state() override + { + return dde_ipxe_nic_link_state(1); + } +}; - /*************************** - ** Nic::Driver interface ** - ***************************/ - - Nic::Mac_address mac_address() override { return _mac_addr; } - - bool link_state() override - { - return dde_ipxe_nic_link_state(1); - } - - void tx(char const *packet, Genode::size_t size) - { - if (dde_ipxe_nic_tx(1, packet, size)) - PWRN("Sending packet failed!"); - } - - /****************************** - ** Irq_activation interface ** - ******************************/ - - void handle_irq(int) { /* not used */ } - }; - -} /* namespace Ipxe */ - - -Ipxe::Driver * Ipxe::Driver::instance = 0; +Ipxe_session_component *Ipxe_session_component::instance; struct Main { - Server::Entrypoint &ep; - Genode::Sliced_heap sliced_heap; + Server::Entrypoint &ep; - struct Factory : public Nic::Driver_factory - { - Server::Entrypoint &ep; + Nic::Root root {ep, *Genode::env()->heap() }; - Factory(Server::Entrypoint &ep) : ep(ep) { } - - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - { - Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify); - return Ipxe::Driver::instance; - } - - void destroy(Nic::Driver *) - { - Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance); - Ipxe::Driver::instance = 0; - } - } factory; - - Nic::Root root; - - Main(Server::Entrypoint &ep) - : - ep(ep), - sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()), - factory(ep), - root(&ep.rpc_ep(), &sliced_heap, factory) + Main(Server::Entrypoint &ep) : ep(ep) { PINF("--- iPXE NIC driver started ---\n"); diff --git a/repos/dde_ipxe/src/drivers/nic_stat/main.cc b/repos/dde_ipxe/src/drivers/nic_stat/main.cc deleted file mode 100644 index 059edb1171..0000000000 --- a/repos/dde_ipxe/src/drivers/nic_stat/main.cc +++ /dev/null @@ -1,181 +0,0 @@ -/* - * \brief NIC driver based on iPXE for performance measurements solely - * \author Christian Helmuth - * \date 2011-11-17 - */ - -/* - * Copyright (C) 2011-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -/* Genode include */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* DDE */ -extern "C" { -#include -} - - -namespace Ipxe { - - class Driver : public Nic::Driver - { - public: - - static Driver *instance; - - private: - - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; - Nic::Driver_notification &_notify; - - Timer::Connection _timer; - Nic::Measurement _stat; - - static void _rx_callback(unsigned if_index, - const char *packet, - unsigned packet_len) - { - instance->rx_handler_stat(packet, packet_len); - } - - static void _link_callback() { instance->link_state_changed(); } - - public: - - Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - : _alloc(alloc), _notify(notify), _stat(_timer) - { - PINF("--- init iPXE NIC"); - int cnt = dde_ipxe_nic_init(&ep); - PINF(" number of devices: %d", cnt); - - PINF("--- init callbacks"); - dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback); - - dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr); - PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x", - _mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff, - _mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff, - _mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff); - - _stat.set_mac(_mac_addr.addr); - } - - void rx_handler_stat(const char *packet, unsigned packet_len) - { - Genode::addr_t test = reinterpret_cast(packet); - void * buffer = reinterpret_cast(test); - - Net::Ethernet_frame *eth = - new (buffer) Net::Ethernet_frame(packet_len); - _stat.data(eth, packet_len); - } - - void rx_handler(const char *packet, unsigned packet_len) - { - void *buffer = _alloc.alloc(packet_len); - Genode::memcpy(buffer, packet, packet_len); - - _alloc.submit(); - } - - void link_state_changed() { _notify.link_state_changed(); } - - - /*************************** - ** Nic::Driver interface ** - ***************************/ - - Nic::Mac_address mac_address() { return _mac_addr; } - - bool link_state() override - { - return dde_ipxe_nic_link_state(1); - } - - void tx(char const *packet, Genode::size_t size) - { - if (dde_ipxe_nic_tx(1, packet, size)) - PWRN("Sending packet failed!"); - } - - /****************************** - ** Irq_activation interface ** - ******************************/ - - void handle_irq(int) { /* not used */ } - }; -} /* namespace Ipxe */ - - -Ipxe::Driver * Ipxe::Driver::instance = 0; - - -struct Main -{ - Server::Entrypoint &ep; - Genode::Sliced_heap sliced_heap; - - struct Factory : public Nic::Driver_factory - { - Server::Entrypoint &ep; - - Factory(Server::Entrypoint &ep) : ep(ep) { } - - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - { - Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify); - return Ipxe::Driver::instance; - } - - void destroy(Nic::Driver *) - { - Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance); - Ipxe::Driver::instance = 0; - } - } factory; - - Nic::Root root; - - Main(Server::Entrypoint &ep) - : - ep(ep), - sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()), - factory(ep), - root(&ep.rpc_ep(), &sliced_heap, factory) - { - PINF("--- iPXE NIC driver started ---\n"); - Genode::env()->parent()->announce(ep.manage(root)); - - root.session("ram_quota=155648, tx_buf_size=65536, rx_buf_size=65536", - Genode::Affinity()); - } -}; - - -/************ - ** Server ** - ************/ - -namespace Server { - char const *name() { return "nic_drv_stat_ep"; } - size_t stack_size() { return 2*1024*sizeof(long); } - void construct(Entrypoint &ep) { static Main server(ep); } -} diff --git a/repos/dde_ipxe/src/drivers/nic_stat/target.mk b/repos/dde_ipxe/src/drivers/nic_stat/target.mk deleted file mode 100644 index 77251cfb3c..0000000000 --- a/repos/dde_ipxe/src/drivers/nic_stat/target.mk +++ /dev/null @@ -1,3 +0,0 @@ -TARGET = nic_drv_stat -LIBS = base server dde_ipxe_nic net-stat -SRC_CC = main.cc diff --git a/repos/dde_linux/src/lib/usb/include/nic/component.h b/repos/dde_linux/src/lib/usb/include/nic/component.h deleted file mode 100644 index 5fc61f668c..0000000000 --- a/repos/dde_linux/src/lib/usb/include/nic/component.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * \brief Block-session implementation for network devices - * \author Sebastian Sumpf - * \date 2012-07-05 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NIC__COMPONENT_H_ -#define _NIC__COMPONENT_H_ - -#include -#include -#include -#include -#include - -#define BENCH 0 - -namespace Nic { - - using namespace Genode; - class Session_component; - -#if BENCH - struct Counter : public Genode::Thread<8192> - { - char const *prefix; - int cnt; - int burst; - size_t size; - - void entry() - { - Timer::Connection _timer; - int interval = 5; - while(1) { - _timer.msleep(interval * 1000); - PDBG("%s: Packets %d/s (in %d burst packets) bytes/s: %d", - prefix, cnt / interval, burst / interval, size / interval); - cnt = 0; - size = 0; - burst = 0; - } - } - - void inc(size_t s) { cnt++; size += s; } - void inc_burst() { burst++; } - - Counter(char const *prefix) - : Thread("counter"), prefix(prefix), cnt(0), burst(0), size(0) - { start(); } - }; -#else - struct Counter - { - Counter(char const *) { }; - void inc(size_t) { } - void inc_burst() { } - }; -#endif - - - struct Device : ::Device - { - Session_component *_session; - - /** - * Transmit data to driver - */ - virtual bool tx(addr_t virt, size_t size) = 0; - - /** - * Return mac address of device - */ - virtual Mac_address mac_address() = 0; - - /** - * Return current link-state (true if link detected) - */ - virtual bool link_state() = 0; - - /** - * Set session belonging to this driver - */ - void session(Session_component *s) { _session = s; } - - /** - * Check for session - */ - bool session() { return _session != 0; } - - /** - * Alloc an SKB - */ - virtual sk_buff *alloc_skb() = 0; - - /** - * Submit SKB to device - */ - virtual void tx_skb(sk_buff *skb) = 0; - - /** - * Setup SKB with 'data' of 'size', return 'false' if SKB is longer than - * 'end'. - */ - virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0; - - /** - * Call driver fixup function on SKB - */ - virtual void tx_fixup(struct sk_buff *skb) = 0; - - /** - * Return true if device supports burst operations - */ - virtual bool burst() = 0; - - Device() : _session(0) { } - }; - - - class Session_component : public Nic::Packet_allocator, - public Packet_session_component - { - private: - - Device *_device; /* device this session is using */ - Tx::Sink *_tx_sink; /* client packet sink */ - bool _tx_alloc; /* get next packet from client or use _tx_packet */ - Packet_descriptor _tx_packet; /* saved packet in case of driver errors */ - - Signal_context_capability _link_state_sigh; - - void _send_packet_avail_signal() { - Signal_transmitter(_tx.sigh_packet_avail()).submit(); } - - protected: - - void _process_packets(unsigned) - { - static sk_buff work_skb; /* dummy skb for fixup calls */ - static Counter counter("TX"); - - int tx_cnt = 0; - unsigned size = 0; - sk_buff *skb = 0; - unsigned char *ptr = 0; - - /* submit received packets to lower layer */ - while (_tx_sink->packet_avail()) - { - Packet_descriptor packet = _tx_alloc ? _tx_sink->get_packet() : _tx_packet; - addr_t virt = (addr_t)_tx_sink->packet_content(packet); - - if (_device->burst()) { - if (!ptr || !_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) { - - /* submit batch to device */ - if (ptr) { - _device->tx_skb(skb); - tx_cnt++; - counter.inc_burst(); - } - - /* alloc new SKB */ - skb = _device->alloc_skb(); - - if (!skb) { - _send_packet_avail_signal(); - _tx_alloc = false; - _tx_packet = packet; - return; - } - - _tx_alloc = true; - - ptr = skb->data; - work_skb.data = 0; - _device->skb_fill(&work_skb, ptr, packet.size(), skb->end); - } - - /* copy packet to current data pos */ - Genode::memcpy(work_skb.data, (void *)virt, packet.size()); - /* call fixup on dummy SKB */ - _device->tx_fixup(&work_skb); - /* advance to next slot */ - ptr = work_skb.end; - skb->len += work_skb.truesize; - } else { - - /* send to driver */ - if (!(_device->tx(virt, packet.size()))) { - _send_packet_avail_signal(); - _tx_alloc = false; - _tx_packet = packet; - return; - } - - _tx_alloc = true; - - tx_cnt++; - } - - counter.inc(packet.size()); - - /* acknowledge to client */ - _tx_sink->acknowledge_packet(packet); - - /* it's cooperative scheduling - be nice */ - if (tx_cnt == 20) - break; - } - - /* sumbit last skb */ - if (skb) { - _device->tx_skb(skb); - counter.inc_burst(); - } - - /* for large TCP/s check RX immediately */ - Irq::check_irq(); - - /* release acknowledged packets */ - _rx_ack(false); - - if (_tx_sink->packet_avail()) - _send_packet_avail_signal(); - } - - void _rx_ack(bool block = true) - { - while (_rx.source()->ack_avail() || block) - { - - Packet_descriptor packet = _rx.source()->get_acked_packet(); - - /* free packet buffer */ - _rx.source()->release_packet(packet); - block = false; - } - } - - public: - - /** - * Constructor - */ - Session_component(Dataspace_capability tx_ds, - Dataspace_capability rx_ds, - Server::Entrypoint &ep, - ::Device *device) - : - Nic::Packet_allocator(Genode::env()->heap()), - Packet_session_component(tx_ds, rx_ds, this, ep), - _device(static_cast(device)), - _tx_sink(Session_rpc_object::_tx.sink()), - _tx_alloc(true) - { _device->session(this); } - - /** - * Link state changed (called from driver) - */ - void link_state_changed() - { - if (_link_state_sigh.valid()) - Genode::Signal_transmitter(_link_state_sigh).submit(); - } - - Mac_address mac_address() { return _device->mac_address(); } - - bool link_state() override { - return _device->link_state(); } - - void link_state_sigh(Genode::Signal_context_capability sigh) { - _link_state_sigh = sigh; } - - /** - * Send packet to client (called form driver) - */ - void rx(addr_t virt, size_t size) - { - static Counter counter("RX"); - - while (true) { - try { - Packet_descriptor p =_rx.source()->alloc_packet(size); - Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size); - _rx.source()->submit_packet(p); - counter.inc(size); - } catch (...) { - /* ack or block */ - _rx_ack(); - continue; - } - break; - } - - _rx_ack(false); - } - }; - - /* - * Shortcut for single-client root component - */ - typedef Root_component Root_component; - - /** - * Root component, handling new session requests - */ - class Root : public Packet_root - { - public: - - Root(Server::Entrypoint &ep, Allocator *md_alloc, - Device *device) - : Packet_root(ep, md_alloc, device) { } - }; -} - - -#endif /* _NIC__COMPONENT_H_ */ diff --git a/repos/dde_linux/src/lib/usb/include/signal/dispatch.h b/repos/dde_linux/src/lib/usb/include/signal/dispatch.h deleted file mode 100644 index 5a4fa248bb..0000000000 --- a/repos/dde_linux/src/lib/usb/include/signal/dispatch.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * \brief Packet-stream-session components - * \author Sebastian Sumpf - * \author Norman Feske - * \date 2012-07-06 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _SIGNAL__DISPATCHER_H_ -#define _SIGNAL__DISPATCHER_H_ - -#include "signal.h" - -#include "platform/lx_mem.h" - -/** - * Session components that overrides signal handlers - */ -template -class Packet_session_component : public RPC -{ - private: - - Genode::Signal_rpc_member _dispatcher; - - protected: - - virtual void _process_packets(unsigned) = 0; - - public: - - Packet_session_component(Genode::Dataspace_capability tx_ds, - Server::Entrypoint &ep) - : RPC(tx_ds, ep.rpc_ep()), - _dispatcher(ep, *this, &Packet_session_component::_process_packets) - { - /* - * Register '_process_packets' dispatch function as signal - * handler for packet-avail and ready-to-ack signals. - */ - RPC::_tx.sigh_packet_avail(_dispatcher); - RPC::_tx.sigh_ready_to_ack(_dispatcher); - } - - Packet_session_component(Genode::Dataspace_capability tx_ds, - Genode::Dataspace_capability rx_ds, - Genode::Range_allocator *rx_buffer_alloc, - Server::Entrypoint &ep) - : RPC(tx_ds, rx_ds, rx_buffer_alloc, ep.rpc_ep()), - _dispatcher(ep, *this, &Packet_session_component::_process_packets) - { - /* - * Register '_process_packets' dispatch function as signal - * handler for packet-avail and ready-to-ack signals. - */ - RPC::_tx.sigh_packet_avail(_dispatcher); - RPC::_tx.sigh_ready_to_ack(_dispatcher); - } -}; - - - /** - * Abstract device - */ - struct Device { }; - - - /** - * Root component, handling new session requests - */ - template - class Packet_root : public ROOT_COMPONENT - { - private: - - Server::Entrypoint &_ep; - Device *_device; - - protected: - - /** - * Always returns the singleton block-session component - */ - SESSION_COMPONENT *_create_session(const char *args) - { - using namespace Genode; - size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); - size_t rx_buf_size = - Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); - - /* delete ram quota by the memory needed for the session */ - size_t session_size = max((size_t)4096, - sizeof(SESSION_COMPONENT) - + sizeof(Allocator_avl)); - if (ram_quota < session_size) - throw Root::Quota_exceeded(); - - /* - * Check if donated ram quota suffices for both communication - * buffers. Also check both sizes separately to handle a - * possible overflow of the sum of both sizes. - */ - if (tx_buf_size > ram_quota - session_size) { - PERR("insufficient 'ram_quota', got %zd, need %zd", - ram_quota, tx_buf_size + session_size); - throw Root::Quota_exceeded(); - } - - return new (ROOT_COMPONENT::md_alloc()) - SESSION_COMPONENT(Backend_memory::alloc(tx_buf_size, CACHEABILITY), - Backend_memory::alloc(rx_buf_size, CACHEABILITY), - _ep, _device); - } - - public: - - Packet_root(Server::Entrypoint &ep, Genode::Allocator *md_alloc, - Device *device) - : ROOT_COMPONENT(&ep.rpc_ep(), md_alloc), - _ep(ep), _device(device) { } - }; - -#endif /* _SIGNAL__DISPATCHER_H_ */ diff --git a/repos/dde_linux/src/lib/usb/include/usb_nic_component.h b/repos/dde_linux/src/lib/usb/include/usb_nic_component.h new file mode 100644 index 0000000000..84f3ce1251 --- /dev/null +++ b/repos/dde_linux/src/lib/usb/include/usb_nic_component.h @@ -0,0 +1,272 @@ +/* + * \brief Block-session implementation for network devices + * \author Sebastian Sumpf + * \date 2012-07-05 + */ + +/* + * Copyright (C) 2012-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _USB_NIC_COMPONENT_H_ +#define _USB_NIC_COMPONENT_H_ + +#include +#include + +namespace Usb_nic { + using namespace Genode; + class Session_component; + struct Device; +}; + + +struct Usb_nic::Device +{ + Session_component *_session; + + /** + * Transmit data to driver + */ + virtual bool tx(addr_t virt, size_t size) = 0; + + /** + * Return mac address of device + */ + virtual Nic::Mac_address mac_address() = 0; + + /** + * Return current link-state (true if link detected) + */ + virtual bool link_state() = 0; + + /** + * Set session belonging to this driver + */ + void session(Session_component *s) { _session = s; } + + /** + * Check for session + */ + bool session() { return _session != 0; } + + /** + * Alloc an SKB + */ + virtual sk_buff *alloc_skb() = 0; + + /** + * Submit SKB to device + */ + virtual void tx_skb(sk_buff *skb) = 0; + + /** + * Setup SKB with 'data' of 'size', return 'false' if SKB is longer than + * 'end'. + */ + virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0; + + /** + * Call driver fixup function on SKB + */ + virtual void tx_fixup(struct sk_buff *skb) = 0; + + /** + * Return true if device supports burst operations + */ + virtual bool burst() = 0; + + Device() : _session(0) { } +}; + + +class Usb_nic::Session_component : public Nic::Session_component +{ + private: + + Device *_device; /* device this session is using */ + + protected: + + void _send_burst() + { + static sk_buff work_skb; /* dummy skb for fixup calls */ + static Packet_descriptor save; + + sk_buff *skb = nullptr; + unsigned char *ptr = nullptr; + + /* submit received packets to lower layer */ + while (((_tx.sink()->packet_avail() || save.valid()) && _tx.sink()->ready_to_ack())) + { + /* alloc skb */ + if (!skb) { + if (!(skb = _device->alloc_skb())) + return; + + ptr = skb->data; + work_skb.data = nullptr; + } + + Packet_descriptor packet = save.valid() ? save : _tx.sink()->get_packet(); + save = Packet_descriptor(); + + if (!_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) { + /* submit batch */ + _device->tx_skb(skb); + skb = nullptr; + save = packet; + continue; + } + + /* copy packet to current data pos */ + Genode::memcpy(work_skb.data, _tx.sink()->packet_content(packet), packet.size()); + /* call fixup on dummy SKB */ + _device->tx_fixup(&work_skb); + /* advance to next slot */ + ptr = work_skb.end; + skb->len += work_skb.truesize; + /* acknowledge to client */ + _tx.sink()->acknowledge_packet(packet); + } + + /* submit last skb */ + if (skb) + _device->tx_skb(skb); + } + + bool _send() + { + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Genode::Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; + } + + bool ret = _device->tx((addr_t)_tx.sink()->packet_content(packet), packet.size()); + _tx.sink()->acknowledge_packet(packet); + + return ret; + } + + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + if (_device->burst()) + _send_burst(); + else + while (_send()); + } + + public: + + /** + * Constructor + */ + Session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep, + Device *device) + : Nic::Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep), + _device(device) + { _device->session(this); } + + + Nic::Mac_address mac_address() override { return _device->mac_address(); } + bool link_state() override { return _device->link_state(); } + void link_state_changed() { _link_state_changed(); } + + /** + * Send packet to client (called from driver) + */ + void rx(addr_t virt, size_t size) + { + _handle_packet_stream(); + + if (!_rx.source()->ready_to_submit()) + return; + + try { + Packet_descriptor p =_rx.source()->alloc_packet(size); + Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size); + _rx.source()->submit_packet(p); + } catch (...) { + /* drop */ + return; + } + } +}; + +/* + * Shortcut for single-client root component + */ +typedef Genode::Root_component Root_component; + +/** + * Root component, handling new session requests + */ +class Root : public Root_component +{ + private: + + Server::Entrypoint &_ep; + Usb_nic::Device *_device; + + protected: + + Usb_nic::Session_component *_create_session(const char *args) + { + using namespace Genode; + + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); + + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (unsigned long)sizeof(Usb_nic::Session_component)); + if (ram_quota < session_size) + throw Genode::Root::Quota_exceeded(); + + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size + || rx_buf_size > ram_quota - session_size + || tx_buf_size + rx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + rx_buf_size + session_size); + throw Genode::Root::Quota_exceeded(); + } + + return new (Root::md_alloc()) + Usb_nic::Session_component(tx_buf_size, rx_buf_size, + *env()->heap(), + *env()->ram_session(), + _ep, _device); + } + + public: + + Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc, + Usb_nic::Device *device) + : Root_component(&ep.rpc_ep(), &md_alloc), + _ep(ep), _device(device) + { } +}; + +#endif /* _USB_NIC_COMPONENT_H_ */ diff --git a/repos/dde_linux/src/lib/usb/nic/nic.cc b/repos/dde_linux/src/lib/usb/nic/nic.cc index 0d0bea8d6f..1652ababf2 100644 --- a/repos/dde_linux/src/lib/usb/nic/nic.cc +++ b/repos/dde_linux/src/lib/usb/nic/nic.cc @@ -25,7 +25,7 @@ #include #include -#include +#include #include "signal.h" @@ -137,7 +137,7 @@ typedef struct sk_buff* (*fixup_t)(struct usbnet *, struct sk_buff *, gfp_t); /** * Net_device to session glue code */ -class Nic_device : public Nic::Device +class Nic_device : public Usb_nic::Device { public: @@ -320,7 +320,7 @@ int register_netdev(struct net_device *ndev) /* XXX: move to 'main' */ if (!announce) { - static Nic::Root root(_signal->ep(), env()->heap(), nic); + static ::Root root(_signal->ep(), *env()->heap(), nic); announce = true; @@ -333,10 +333,6 @@ int register_netdev(struct net_device *ndev) if (ndev->netdev_ops->ndo_set_rx_mode) ndev->netdev_ops->ndo_set_rx_mode(ndev); -/* - if(ndev->netdev_ops->ndo_change_mtu) - ndev->netdev_ops->ndo_change_mtu(ndev, 4000); -*/ _nic = nic; env()->parent()->announce(_signal->ep().rpc_ep().manage(&root)); } diff --git a/repos/dde_linux/src/lib/wifi/include/nic/component.h b/repos/dde_linux/src/lib/wifi/include/nic/component.h deleted file mode 100644 index 861b3dc3a0..0000000000 --- a/repos/dde_linux/src/lib/wifi/include/nic/component.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * \brief Nic-session implementation for network devices - * \author Sebastian Sumpf - * \date 2012-07-05 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _NIC__COMPONENT_H_ -#define _NIC__COMPONENT_H_ - -/* Genode includes */ -#include -#include -#include -#include - -/* local includes */ -#include - -#include -# include -#include - - -namespace Nic { - - using namespace Genode; /* FIXME */ - - struct Session_component; - struct Device; - - typedef Genode::Root_component Root_component; - - struct Root; -} - - -struct Nic::Device -{ - /** - * Transmit data to driver - */ - virtual bool tx(addr_t virt, size_t size) = 0; - - /** - * Return mac address of device - */ - virtual Mac_address mac_address() = 0; - - /** - * Return link state (true if link detected) - */ - virtual bool link_state() = 0; - - /** - * Set session belonging to this driver - */ - virtual void session(Session_component *s) = 0; - - Device() { } - virtual ~Device() { } -}; - - -class Nic::Session_component : public Nic::Packet_allocator, - public Packet_session_component -{ - private: - - Device &_device; /* device this session is using */ - Tx::Sink *_tx_sink; /* client packet sink */ - bool _tx_alloc; /* get next packet from client or use _tx_packet */ - Packet_descriptor _tx_packet; /* saved packet in case of driver errors */ - - Signal_context_capability _link_state_sigh; - - void _send_packet_avail_signal() { - Signal_transmitter(_tx.sigh_packet_avail()).submit(); } - - protected: - - void _process_packets(unsigned) - { - int tx_cnt = 0; - - /* submit received packets to lower layer */ - while (_tx_sink->packet_avail()) { - Packet_descriptor packet = _tx_alloc ? _tx_sink->get_packet() : _tx_packet; - addr_t virt = (addr_t)_tx_sink->packet_content(packet); - - /* send to driver */ - if (!(_device.tx(virt, packet.size()))) { - _send_packet_avail_signal(); - _tx_alloc = false; - _tx_packet = packet; - return; - } - - _tx_alloc = true; - tx_cnt++; - - /* acknowledge to client */ - _tx_sink->acknowledge_packet(packet); - } - - /* release acknowledged packets */ - _rx_ack(false); - - if (_tx_sink->packet_avail()) - _send_packet_avail_signal(); - } - - void _rx_ack(bool block = true) - { - while (_rx.source()->ack_avail() || block) { - Packet_descriptor packet = _rx.source()->get_acked_packet(); - - /* free packet buffer */ - _rx.source()->release_packet(packet); - block = false; - } - } - - public: - - /** - * Constructor - */ - Session_component(Dataspace_capability tx_ds, - Dataspace_capability rx_ds, - Server::Entrypoint &ep, - Device &device) - : - Nic::Packet_allocator(Genode::env()->heap()), - Packet_session_component(tx_ds, rx_ds, this, ep), - _device(device), - _tx_sink(Session_rpc_object::_tx.sink()), - _tx_alloc(true) - { _device.session(this); } - - /** - * Send packet to client (called from driver) - */ - void rx(addr_t packet, size_t psize, addr_t frag, size_t fsize) - { - size_t size = psize + fsize; - - while (true) { - try { - Packet_descriptor p =_rx.source()->alloc_packet(size); - - Genode::memcpy(_rx.source()->packet_content(p), (void*)packet, psize); - - if (fsize) - Genode::memcpy(_rx.source()->packet_content(p)+psize, (void*)frag, fsize); - - _rx.source()->submit_packet(p); - } catch (...) { - /* ack or block */ - _rx_ack(); - continue; - } - break; - } - - _rx_ack(false); - } - - /** - * Link state changed (called from driver) - */ - void link_state_changed() - { - if (_link_state_sigh.valid()) - Genode::Signal_transmitter(_link_state_sigh).submit(); - } - - /*************************** - ** Nic-session interface ** - ***************************/ - - Mac_address mac_address() override - { - return _device.mac_address(); - } - - bool link_state() // override - { - return _device.link_state(); - } - - void link_state_sigh(Genode::Signal_context_capability sigh) - { - _link_state_sigh = sigh; - } -}; - - -/** - * Root component, handling new session requests - */ -struct Nic::Root : Packet_root -{ - Root(Server::Entrypoint &ep, Allocator *md_alloc, Device &device) - : Packet_root(ep, md_alloc, device) { } -}; - -#endif /* _NIC__COMPONENT_H_ */ diff --git a/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h b/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h deleted file mode 100644 index 9c43bf889e..0000000000 --- a/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h +++ /dev/null @@ -1,143 +0,0 @@ -/** - * \brief Packet-stream-session components - * \author Sebastian Sumpf - * \author Norman Feske - * \date 2012-07-06 - */ - -/* - * Copyright (C) 2012-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _SIGNAL__DISPATCHER_H_ -#define _SIGNAL__DISPATCHER_H_ - -/* Genode includes */ -#include - -/* local includes */ -#include - - -/** - * Session components that overrides signal handlers - */ -template -class Packet_session_component : public SESSION_RPC_OBJECT -{ - private: - - Genode::Signal_rpc_member _tx_ready_to_ack_dispatcher; - Genode::Signal_rpc_member _tx_packet_avail_dispatcher; - Genode::Signal_rpc_member _rx_ack_avail_dispatcher; - Genode::Signal_rpc_member _rx_ready_to_submit_dispatcher; - - void _tx_ready_to_ack(unsigned) - { - _process_packets(0); - } - - void _tx_packet_avail(unsigned) - { - _process_packets(0); - } - - void _rx_ack_avail(unsigned) - { - _process_packets(0); - } - - void _rx_ready_to_submit(unsigned) - { - _process_packets(0); - } - - protected: - - virtual void _process_packets(unsigned) = 0; - - public: - - Packet_session_component(Genode::Dataspace_capability tx_ds, - Genode::Dataspace_capability rx_ds, - Genode::Range_allocator *rx_buffer_alloc, - Server::Entrypoint &ep) - : - SESSION_RPC_OBJECT(tx_ds, rx_ds, rx_buffer_alloc, ep.rpc_ep()), - _tx_ready_to_ack_dispatcher(ep, *this, &Packet_session_component::_tx_ready_to_ack), - _tx_packet_avail_dispatcher(ep, *this, &Packet_session_component::_tx_packet_avail), - _rx_ack_avail_dispatcher(ep, *this, &Packet_session_component::_rx_ack_avail), - _rx_ready_to_submit_dispatcher(ep, *this, &Packet_session_component::_rx_ready_to_submit) - { - SESSION_RPC_OBJECT::_tx.sigh_ready_to_ack(_tx_ready_to_ack_dispatcher); - SESSION_RPC_OBJECT::_tx.sigh_packet_avail(_tx_packet_avail_dispatcher); - SESSION_RPC_OBJECT::_rx.sigh_ack_avail(_rx_ack_avail_dispatcher); - SESSION_RPC_OBJECT::_rx.sigh_ready_to_submit(_rx_ready_to_submit_dispatcher); - } -}; - - -/** - * Root component, handling new session requests - */ -template -class Packet_root : public ROOT_COMPONENT -{ - private: - - Server::Entrypoint &_ep; - DEVICE &_device; - - protected: - - /** - * Always returns the singleton block-session component - */ - SESSION_COMPONENT *_create_session(const char *args) - { - using namespace Genode; - size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); - size_t rx_buf_size = - Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); - - /* delete ram quota by the memory needed for the session */ - size_t session_size = max((size_t)4096, - sizeof(SESSION_COMPONENT) - + sizeof(Allocator_avl)); - if (ram_quota < session_size) - throw Root::Quota_exceeded(); - - /* - * Check if donated ram quota suffices for both communication - * buffers. Also check both sizes separately to handle a - * possible overflow of the sum of both sizes. - */ - if (tx_buf_size > ram_quota - session_size) { - PERR("insufficient 'ram_quota', got %zd, need %zd", - ram_quota, tx_buf_size + session_size); - throw Root::Quota_exceeded(); - } - - return new (ROOT_COMPONENT::md_alloc()) - SESSION_COMPONENT(Lx::backend_alloc(tx_buf_size, CACHEABILITY), - Lx::backend_alloc(rx_buf_size, CACHEABILITY), - _ep, _device); - } - - public: - - Packet_root(Server::Entrypoint &ep, Genode::Allocator *md_alloc, DEVICE &device) - : ROOT_COMPONENT(&ep.rpc_ep(), md_alloc), - _ep(ep), _device(device) { } -}; - -#endif /* _SIGNAL__DISPATCHER_H_ */ diff --git a/repos/dde_linux/src/lib/wifi/nic.cc b/repos/dde_linux/src/lib/wifi/nic.cc index da5ed2f271..27bc5f5f31 100644 --- a/repos/dde_linux/src/lib/wifi/nic.cc +++ b/repos/dde_linux/src/lib/wifi/nic.cc @@ -17,17 +17,17 @@ #include #include #include -#include #include +#include +#include #include /* local includes */ #include -#include #include -# include -# include +#include +#include #include extern bool config_verbose; @@ -37,22 +37,91 @@ enum { }; /** - * Net_device to session glue code + * Nic::Session implementation */ -class Nic_device : public Nic::Device +class Wifi_session_component : public Nic::Session_component { - public: /* FIXME */ + private: - struct net_device *_ndev; - Nic::Session_component *_session = nullptr; - bool _has_link = false; + net_device *_ndev; + bool _has_link = !(_ndev->state & 1UL << __LINK_STATE_NOCARRIER); + + protected: + + bool _send() + { + using namespace Genode; + + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; + } + + struct sk_buff *skb = ::alloc_skb(packet.size() + HEAD_ROOM, GFP_KERNEL); + skb_reserve(skb, HEAD_ROOM); + + unsigned char *data = skb_put(skb, packet.size()); + Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size()); + + _ndev->netdev_ops->ndo_start_xmit(skb, _ndev); + _tx.sink()->acknowledge_packet(packet); + + return true; + } + + void _handle_packet_stream() + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + while (_send()) ; + } public: - Nic_device(struct net_device *ndev) : _ndev(ndev) { } - - void rx(sk_buff *skb) + Wifi_session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep, net_device *ndev) + : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep), + _ndev(ndev) { + _ndev->lx_nic_device = this; + } + + ~Wifi_session_component() + { + _ndev->lx_nic_device = nullptr; + } + + /** + * Report link state + */ + void link_state(bool link) + { + /* only report changes of the link state */ + if (link == _has_link) + return; + + _has_link = link; + _link_state_changed(); + } + + void receive(struct sk_buff *skb) + { + _handle_packet_stream(); + + if (!_rx.source()->ready_to_submit()) + return; + /* get mac header back */ skb_push(skb, ETH_HLEN); @@ -77,29 +146,24 @@ class Nic_device : public Nic::Device else packet_size += skb->len; - _session->rx((Genode::addr_t)packet, packet_size, (Genode::addr_t)frag, frag_size); + + try { + Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_size + frag_size); + void *buffer = _rx.source()->packet_content(p); + memcpy(buffer, packet, packet_size); + if (frag_size) + memcpy((char *)buffer + packet_size, frag, frag_size); + + _rx.source()->submit_packet(p); + } catch (...) { + PDBG("failed to process received packet"); + } } - /** - * Report link state - */ - void link_state(bool link) - { - /* only report changes of the link state */ - if (link == _has_link) - return; - _has_link = link; - - if (_session) - _session->link_state_changed(); - } - - /********************** - ** Device interface ** - **********************/ - - void session(Nic::Session_component *s) override { _session = s; } + /***************************** + ** NIC-component interface ** + *****************************/ Nic::Mac_address mac_address() override { @@ -109,32 +173,83 @@ class Nic_device : public Nic::Device } bool link_state() override { return _has_link; } - - bool tx(Genode::addr_t virt, Genode::size_t size) override - { - struct sk_buff *skb = ::alloc_skb(size + HEAD_ROOM, GFP_KERNEL); - skb_reserve(skb, HEAD_ROOM); - - unsigned char *data = skb_put(skb, size); - Genode::memcpy(data, (void*)virt, size); - - _ndev->netdev_ops->ndo_start_xmit(skb, _ndev); - return true; - } }; -static Nic_device *_nic = 0; +/** + * NIC root implementation + */ +class Root : public Genode::Root_component +{ + private: -static Server::Entrypoint *_ep; + Server::Entrypoint &_ep; -void Lx::nic_init(Server::Entrypoint &ep) { - _ep = &ep; } + protected: + + Wifi_session_component *_create_session(const char *args) + { + using namespace Genode; + + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); + + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (unsigned long)sizeof(Wifi_session_component)); + if (ram_quota < session_size) + throw Genode::Root::Quota_exceeded(); + + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size + || rx_buf_size > ram_quota - session_size + || tx_buf_size + rx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + rx_buf_size + session_size); + throw Genode::Root::Quota_exceeded(); + } + + session = new (md_alloc()) + Wifi_session_component(tx_buf_size, rx_buf_size, + *env()->heap(), + *env()->ram_session(), + _ep, device); + return session; + } + + public: + + net_device *device = nullptr; + Wifi_session_component *session = nullptr; + static Root *instance; + + Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc) + : Genode::Root_component(&ep.rpc_ep(), &md_alloc), + _ep(ep) + { } + + void announce() { Genode::env()->parent()->announce(_ep.rpc_ep().manage(this)); } +}; + + +Root *Root::instance; + + +void Lx::nic_init(Server::Entrypoint &ep) +{ + static Root root(ep, *Genode::env()->heap()); + Root::instance = &root; +} void Lx::get_mac_address(unsigned char *addr) { - Genode::memcpy(addr, _nic->_ndev->perm_addr, ETH_ALEN); + memcpy(addr, Root::instance->device->perm_addr, ETH_ALEN); } @@ -319,12 +434,12 @@ extern "C" void __dev_remove_pack(struct packet_type *pt) extern "C" struct net_device *__dev_get_by_index(struct net *net, int ifindex) { - if (!_nic || !_nic->_ndev) { + if (!Root::instance->device) { PERR("no net device registered!"); return 0; } - return _nic->_ndev; + return Root::instance->device; } @@ -387,18 +502,10 @@ extern "C" int register_netdevice(struct net_device *ndev) return -ENODEV; } - static Nic_device nic_device(ndev); - static Nic::Root nic_root(*_ep, Genode::env()->heap(), nic_device); - - /* - * XXX This is just a starting point for removing all the static stuff from - * this file... - */ - ndev->lx_nic_device = (void *)&nic_device; - _nic = &nic_device; - already_registered = true; + Root::instance->device = ndev; + ndev->state |= 1UL << __LINK_STATE_START; netif_carrier_off(ndev); @@ -424,7 +531,7 @@ extern "C" int register_netdevice(struct net_device *ndev) if (ndev->netdev_ops->ndo_set_rx_mode) ndev->netdev_ops->ndo_set_rx_mode(ndev); - Genode::env()->parent()->announce(_ep->rpc_ep().manage(&nic_root)); + Root::instance->announce(); list_add_tail_rcu(&ndev->dev_list, &init_net.dev_base_head); @@ -451,9 +558,10 @@ extern "C" void netif_carrier_on(struct net_device *dev) { dev->state &= ~(1UL << __LINK_STATE_NOCARRIER); - Nic_device *nic = (Nic_device *)dev->lx_nic_device; + Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device; - nic->link_state(true); + if (session) + session->link_state(true); } @@ -464,9 +572,10 @@ extern "C" void netif_carrier_off(struct net_device *dev) dev->state |= 1UL << __LINK_STATE_NOCARRIER; - Nic_device *nic = (Nic_device *)dev->lx_nic_device; + Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device; - nic->link_state(false); + if (session) + session->link_state(false); } @@ -481,14 +590,13 @@ extern "C" int netif_receive_skb(struct sk_buff *skb) if (ntohs(skb->protocol) == ETH_P_PAE) { /* XXX call only AF_PACKET hook */ for (Proto_hook* ph = proto_hook_list().first(); ph; ph = ph->next()) { - ph->pt.func(skb, _nic->_ndev, &ph->pt, _nic->_ndev); + ph->pt.func(skb, Root::instance->device, &ph->pt, Root::instance->device); } return NET_RX_SUCCESS; } - if (_nic && _nic->_session) { - _nic->rx(skb); - } + if (Root::instance->session) + Root::instance->session->receive(skb); dev_kfree_skb(skb); return NET_RX_SUCCESS; @@ -567,12 +675,6 @@ extern "C" struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name } -/********************** - ** linux/inerrupt.h ** - **********************/ - - - /************************* ** linux/etherdevice.h ** *************************/ diff --git a/repos/os/include/nic/component.h b/repos/os/include/nic/component.h index d679985aa8..e8ae0f2e05 100644 --- a/repos/os/include/nic/component.h +++ b/repos/os/include/nic/component.h @@ -1,11 +1,12 @@ /* - * \brief Glue between device-specific NIC driver code and Genode + * \brief Server::Entrypoint based NIC session component * \author Norman Feske - * \date 2011-05-21 + * \author Sebastian Sumpf + * \date 2015-06-22 */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -14,101 +15,64 @@ #ifndef _INCLUDE__NIC__COMPONENT_H_ #define _INCLUDE__NIC__COMPONENT_H_ -#include +#include +#include +#include #include -#include -#include -#include -#include -#include - -enum { VERBOSE_RX = false }; namespace Nic { + class Communication_buffers; class Session_component; - - /** - * Shortcut for single-client NIC root component - */ - typedef Genode::Root_component - Root_component; - - class Root; } -class Nic::Session_component : public Genode::Allocator_avl, - public Session_rpc_object, public Rx_buffer_alloc, - public Driver_notification +class Nic::Communication_buffers { - private: + protected: - Driver_factory &_driver_factory; - Driver &_driver; + Nic::Packet_allocator _rx_packet_alloc; + Genode::Attached_ram_dataspace _tx_ds, _rx_ds; + Communication_buffers(Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Genode::size_t tx_size, Genode::size_t rx_size) + : + _rx_packet_alloc(&rx_block_md_alloc), + _tx_ds(&ram_session, tx_size), + _rx_ds(&ram_session, rx_size) + { } +}; + + +class Nic::Session_component : Communication_buffers, public Session_rpc_object +{ + protected: + + Server::Entrypoint &_ep; Genode::Signal_context_capability _link_state_sigh; - /* rx packet descriptor */ - Genode::Packet_descriptor _curr_rx_packet; - enum { TX_STACK_SIZE = 8*1024 }; - class Tx_thread : public Genode::Thread + /** + * Signal link-state change to client + */ + void _link_state_changed() { - private: - - Tx::Sink *_tx_sink; - Driver &_driver; - - public: - - Tx_thread(Tx::Sink *tx_sink, Driver &driver) - : - Genode::Thread("tx"), - _tx_sink(tx_sink), _driver(driver) - { - start(); - } - - void entry() - { - using namespace Genode; - - while (true) { - - /* block for packet from client */ - Packet_descriptor packet = _tx_sink->get_packet(); - if (!packet.valid()) { - PWRN("received invalid packet"); - continue; - } - - _driver.tx(_tx_sink->packet_content(packet), - packet.size()); - - /* acknowledge packet to the client */ - if (!_tx_sink->ready_to_ack()) - PDBG("need to wait until ready-for-ack"); - _tx_sink->acknowledge_packet(packet); - } - } - } _tx_thread; - - void dump() - { - using namespace Genode; - - if (!VERBOSE_RX) return; - - char *buf = (char *)_rx.source()->packet_content(_curr_rx_packet); - size_t size = _curr_rx_packet.size(); - - printf("rx packet:"); - for (unsigned i = 0; i < size; i++) - printf("%02x,", buf[i]); - printf("\n"); + if (_link_state_sigh.valid()) + Genode::Signal_transmitter(_link_state_sigh).submit(); } + /** + * Sub-classes must implement this function, it is called upon all + * packet-stream signals. + */ + virtual void _handle_packet_stream() = 0; + + void _dispatch(unsigned) { _handle_packet_stream(); } + + Genode::Signal_rpc_member _packet_stream_dispatcher { + _ep, *this, &Session_component::_dispatch }; + public: /** @@ -116,149 +80,47 @@ class Nic::Session_component : public Genode::Allocator_avl, * * \param tx_buf_size buffer size for tx channel * \param rx_buf_size buffer size for rx channel - * \param rx_block_alloc rx block allocator + * \param rx_block_md_alloc backing store of the meta data of the + * rx block allocator + * \param ram_session RAM session to allocate tx and rx buffers * \param ep entry point used for packet stream + * channels */ - Session_component(Genode::size_t tx_buf_size, - Genode::size_t rx_buf_size, - Nic::Driver_factory &driver_factory, - Genode::Rpc_entrypoint &ep) + Session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) : - Genode::Allocator_avl(Genode::env()->heap()), - Session_rpc_object(Genode::env()->ram_session()->alloc(tx_buf_size), - Genode::env()->ram_session()->alloc(rx_buf_size), - static_cast(this), ep), - _driver_factory(driver_factory), - _driver(*driver_factory.create(*this, *this)), - _tx_thread(_tx.sink(), _driver) - { } - - /** - * Destructor - */ - ~Session_component() + Communication_buffers(rx_block_md_alloc, ram_session, + tx_buf_size, rx_buf_size), + Session_rpc_object(_tx_ds.cap(), + _rx_ds.cap(), + &_rx_packet_alloc, ep.rpc_ep()), + _ep(ep) { - _driver_factory.destroy(&_driver); + /* install data-flow signal handlers for both packet streams */ + _tx.sigh_ready_to_ack(_packet_stream_dispatcher); + _tx.sigh_packet_avail(_packet_stream_dispatcher); + _rx.sigh_ready_to_submit(_packet_stream_dispatcher); + _rx.sigh_ack_avail(_packet_stream_dispatcher); } - /*********************************** - ** Driver-notification interface ** - ***********************************/ - - void link_state_changed() override - { - if (_link_state_sigh.valid()) - Genode::Signal_transmitter(_link_state_sigh).submit(); - } - - /******************************* - ** Rx_buffer_alloc interface ** - *******************************/ - - void *alloc(Genode::size_t size) override - { - /* assign rx packet descriptor */ - _curr_rx_packet = _rx.source()->alloc_packet(size); - - return _rx.source()->packet_content(_curr_rx_packet); - } - - void submit() override - { - /* check for acknowledgements from the client */ - while (_rx.source()->ack_avail()) { - Genode::Packet_descriptor packet = _rx.source()->get_acked_packet(); - - /* free packet buffer */ - _rx.source()->release_packet(packet); - } - - dump(); - - _rx.source()->submit_packet(_curr_rx_packet); - - /* invalidate rx packet descriptor */ - _curr_rx_packet = Packet_descriptor(); - } - - - /**************************** - ** Nic::Session interface ** - ****************************/ - - Mac_address mac_address() { return _driver.mac_address(); } - bool link_state() { return _driver.link_state(); } - Tx::Sink* tx_sink() { return _tx.sink(); } - Rx::Source* rx_source() { return _rx.source(); } - - void link_state_sigh(Genode::Signal_context_capability sigh) override + void link_state_sigh(Genode::Signal_context_capability sigh) { _link_state_sigh = sigh; } -}; - -/* - * Root component, handling new session requests. - */ -class Nic::Root : public Root_component -{ - private: - - Driver_factory &_driver_factory; - Genode::Rpc_entrypoint &_ep; - - protected: - - /* - * Always returns the singleton nic-session component. + /** + * Return the current link state */ - Session_component *_create_session(const char *args) - { - using namespace Genode; + virtual bool link_state() = 0; - Genode::size_t ram_quota = - Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); - Genode::size_t tx_buf_size = - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); - Genode::size_t rx_buf_size = - Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); - - /* delete ram quota by the memory needed for the session */ - Genode::size_t session_size = max((Genode::size_t)4096, sizeof(Session_component) - + sizeof(Allocator_avl)); - if (ram_quota < session_size) - throw Root::Quota_exceeded(); - - /* - * Check if donated ram quota suffices for both - * communication buffers. Also check both sizes separately - * to handle a possible overflow of the sum of both sizes. - */ - if (tx_buf_size > ram_quota - session_size - || rx_buf_size > ram_quota - session_size - || tx_buf_size + rx_buf_size > ram_quota - session_size) { - PERR("insufficient 'ram_quota', got %zd, need %zd", - ram_quota, tx_buf_size + rx_buf_size + session_size); - throw Root::Quota_exceeded(); - } - - return new (md_alloc()) Session_component(tx_buf_size, - rx_buf_size, - _driver_factory, - _ep); - } - - public: - - Root(Genode::Rpc_entrypoint *session_ep, - Genode::Allocator *md_alloc, - Nic::Driver_factory &driver_factory) - : - Root_component(session_ep, md_alloc), - _driver_factory(driver_factory), - _ep(*session_ep) - { } + /** + * Return the MAC address of the device + */ + virtual Mac_address mac_address() = 0; }; + #endif /* _INCLUDE__NIC__COMPONENT_H_ */ diff --git a/repos/os/include/nic/driver.h b/repos/os/include/nic/driver.h deleted file mode 100644 index cdebf968aa..0000000000 --- a/repos/os/include/nic/driver.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * \brief Interfaces used internally in NIC drivers - * \author Norman Feske - * \date 2011-05-21 - */ - -/* - * Copyright (C) 2011-2013 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _INCLUDE__NIC__DRIVER_H_ -#define _INCLUDE__NIC__DRIVER_H_ - -#include /* for 'Genode::Irq_handler' type */ -#include /* for 'Nic::Mac_address' type */ - -namespace Nic { - - struct Rx_buffer_alloc; - struct Driver; - struct Driver_factory; - struct Driver_notification; -} - - -/** - * Interface for allocating the backing store for incoming packets - */ -struct Nic::Rx_buffer_alloc -{ - /** - * Allocate packet buffer - */ - virtual void *alloc(Genode::size_t) = 0; - - /** - * Submit packet to client - */ - virtual void submit() = 0; -}; - - -/** - * Interface for driver-to-component notifications - */ -struct Nic::Driver_notification { virtual void link_state_changed() = 0; }; - - -/** - * Interface to be implemented by the device-specific driver code - */ -struct Nic::Driver : Genode::Irq_handler -{ - /** - * Return MAC address of the network interface - */ - virtual Mac_address mac_address() = 0; - - /** - * Return link state (true if link detected) - */ - virtual bool link_state() = 0; - - /** - * Transmit packet - * - * \param packet start of packet - * \param size packet size - * - * If the packet size is not a multiple of 4 bytes, this method - * accesses the bytes after the packet buffer up to the next 4-byte - * length (in the worst case, 3 bytes after the packet end). - */ - virtual void tx(char const *packet, Genode::size_t size) = 0; -}; - - -/** - * Interface for constructing the driver object - * - * The driver object requires an rx-packet allocator at construction time. - * This allocator, however, exists not before the creation of a NIC session - * because the client pays for it. Therefore, the driver must be created at - * session-construction time. Because drivers may differ with regard to - * their constructor arguments, the 'Driver_factory' interface allows for - * unifying the session-creation among these drivers. - */ -struct Nic::Driver_factory -{ - /** - * Construct new driver - * - * \param rx_buffer_alloc buffer allocator used for storing incoming - * packets - * \param notifier callback for notifications - */ - virtual Driver *create(Rx_buffer_alloc &rx_buffer_alloc, - Driver_notification ¬ify) = 0; - - /** - * Destroy driver - */ - virtual void destroy(Driver *driver) = 0; -}; - -#endif /* _INCLUDE__NIC__DRIVER_H_ */ diff --git a/repos/os/include/nic/root.h b/repos/os/include/nic/root.h new file mode 100644 index 0000000000..7417170872 --- /dev/null +++ b/repos/os/include/nic/root.h @@ -0,0 +1,77 @@ +/** + * \brief Simple single client NIC Root + * \author Sebastian Sumpf + * \date 2015-06-23 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__NIC__ROOT_H_ +#define _INCLUDE__NIC__ROOT_H_ + +#include +#include + +namespace Nic { + + template class Root; +}; + + +template +class Nic::Root : public Genode::Root_component +{ + private: + + Server::Entrypoint &_ep; + + protected: + + SESSION_COMPONENT *_create_session(const char *args) + { + using namespace Genode; + + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); + + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (unsigned long)sizeof(SESSION_COMPONENT)); + if (ram_quota < session_size) + throw Genode::Root::Quota_exceeded(); + + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size + || rx_buf_size > ram_quota - session_size + || tx_buf_size + rx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + rx_buf_size + session_size); + throw Genode::Root::Quota_exceeded(); + } + + return new (Root::md_alloc()) + SESSION_COMPONENT(tx_buf_size, rx_buf_size, + *env()->heap(), + *env()->ram_session(), + _ep); + } + + public: + + Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc) + : Genode::Root_component(&ep.rpc_ep(), &md_alloc), + _ep(ep) + { } +}; + +#endif /* _INCLUDE__NIC__ROOT_H_ */ diff --git a/repos/os/src/drivers/nic/lan9118/lan9118.h b/repos/os/src/drivers/nic/lan9118/lan9118.h index 40abc3cc2f..92ac1f9f16 100644 --- a/repos/os/src/drivers/nic/lan9118/lan9118.h +++ b/repos/os/src/drivers/nic/lan9118/lan9118.h @@ -19,9 +19,10 @@ #include #include #include -#include +#include -class Lan9118 : public Nic::Driver +class Lan9118 : public Nic::Session_component, + public Genode::Irq_handler { private: @@ -70,9 +71,7 @@ class Lan9118 : public Nic::Driver Genode::Attached_io_mem_dataspace _mmio; volatile Genode::uint32_t *_reg_base; Timer::Connection _timer; - Nic::Rx_buffer_alloc &_rx_buffer_alloc; Nic::Mac_address _mac_addr; - Nic::Driver_notification &_notify; enum { IRQ_STACK_SIZE = 4096 }; Genode::Irq_activation _irq_activation; @@ -189,6 +188,67 @@ class Lan9118 : public Nic::Driver return _reg_read(RX_FIFO_INF) & 0xffff; } + protected: + + bool _send() + { + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Genode::Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; + } + + /* limit size to 11 bits, the maximum supported by lan9118 */ + enum { MAX_PACKET_SIZE_LOG2 = 11 }; + Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1; + if (packet.size() > max_size) { + PERR("packet size %zd too large, limit is %zd", packet.size(), max_size); + return true; + } + + enum { FIRST_SEG = (1 << 13), + LAST_SEG = (1 << 12) }; + + Genode::uint32_t const cmd_a = packet.size() | FIRST_SEG | LAST_SEG, + cmd_b = packet.size(); + + unsigned count = Genode::align_addr(packet.size(), 2) >> 2; + Genode::uint32_t *src = (Genode::uint32_t *)_tx.sink()->packet_content(packet); + + /* check space left in tx data fifo */ + Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff; + if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) { + PERR("tx fifo overrun, ignore packet"); + _tx.sink()->acknowledge_packet(packet); + return false; + } + + _reg_write(TX_DATA_FIFO, cmd_a); + _reg_write(TX_DATA_FIFO, cmd_b); + + /* supply payload to transmit fifo */ + for (; count--; src++) + _reg_write(TX_DATA_FIFO, *src); + + _tx.sink()->acknowledge_packet(packet); + return true; + } + + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + while (_send()) ; + } + + public: /** @@ -202,13 +262,14 @@ class Lan9118 : public Nic::Driver * \throw Device_not_supported */ Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq, - Nic::Rx_buffer_alloc &rx_buffer_alloc, - Nic::Driver_notification ¬ify) - : + Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) + : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep), _mmio(mmio_base, mmio_size), _reg_base(_mmio.local_addr()), - _rx_buffer_alloc(rx_buffer_alloc), - _notify(notify), _irq_activation(irq, *this, IRQ_STACK_SIZE) { unsigned long const id_rev = _reg_read(ID_REV), @@ -290,58 +351,21 @@ class Lan9118 : public Nic::Driver _mac_csr_write(MAC_CR, 0); } - void link_state_changed() { _notify.link_state_changed(); } + /************************************** + ** Nic::Session_component interface ** + **************************************/ - - /*************************** - ** Nic::Driver interface ** - ***************************/ - - Nic::Mac_address mac_address() + Nic::Mac_address mac_address() override { return _mac_addr; } - bool link_state() + bool link_state() override { /* XXX always return true for now */ return true; } - void tx(char const *packet, Genode::size_t size) - { - /* limit size to 11 bits, the maximum supported by lan9118 */ - enum { MAX_PACKET_SIZE_LOG2 = 11 }; - Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1; - if (size > max_size) { - PERR("packet size %zd too large, limit is %zd", size, max_size); - return; - } - - enum { FIRST_SEG = (1 << 13), - LAST_SEG = (1 << 12) }; - - Genode::uint32_t const cmd_a = size | FIRST_SEG | LAST_SEG, - cmd_b = size; - - unsigned count = Genode::align_addr(size, 2) >> 2; - Genode::uint32_t *src = (Genode::uint32_t *)packet; - - /* check space left in tx data fifo */ - Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff; - if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) { - PERR("tx fifo overrun, ignore packet"); - return; - } - - _reg_write(TX_DATA_FIFO, cmd_a); - _reg_write(TX_DATA_FIFO, cmd_b); - - /* supply payload to transmit fifo */ - for (; count--; src++) - _reg_write(TX_DATA_FIFO, *src); - } - /****************************** ** Irq_activation interface ** @@ -351,7 +375,9 @@ class Lan9118 : public Nic::Driver { using namespace Genode; - while (_rx_packet_avail()) { + _handle_packet_stream(); + + while (_rx_packet_avail() && _rx.source()->ready_to_submit()) { /* read packet from NIC, copy to client buffer */ Rx_packet_info packet = _rx_packet_info(); @@ -360,7 +386,12 @@ class Lan9118 : public Nic::Driver size_t const size = align_addr(packet.size, 2); /* allocate rx packet buffer */ - uint32_t *dst = (uint32_t *)_rx_buffer_alloc.alloc(size); + Nic::Packet_descriptor p; + try { + p = _rx.source()->alloc_packet(size); + } catch (Session::Rx::Source::Packet_alloc_failed) { return; } + + uint32_t *dst = (uint32_t *)_rx.source()->packet_content(p); /* calculate number of words to be read from rx fifo */ size_t count = min(size, _rx_data_pending()) >> 2; @@ -369,7 +400,7 @@ class Lan9118 : public Nic::Driver for (; count--; ) *dst++ = _reg_read(RX_DATA_FIFO); - _rx_buffer_alloc.submit(); + _rx.source()->submit_packet(p); } /* acknowledge all pending irqs */ diff --git a/repos/os/src/drivers/nic/lan9118/main.cc b/repos/os/src/drivers/nic/lan9118/main.cc index 1caa92c701..2099cbb081 100644 --- a/repos/os/src/drivers/nic/lan9118/main.cc +++ b/repos/os/src/drivers/nic/lan9118/main.cc @@ -18,6 +18,8 @@ #include #include #include +#include +#include /* device definitions */ #include @@ -25,39 +27,80 @@ /* driver code */ #include +namespace Server { struct Main; } -int main(int, char **) +class Root : public Genode::Root_component { - using namespace Genode; + private: - printf("--- LAN9118 NIC driver started ---\n"); + Server::Entrypoint &_ep; - /** - * Factory used by 'Nic::Root' at session creation/destruction time - */ - struct Lan9118_driver_factory : Nic::Driver_factory + protected: + + Lan9118 *_create_session(const char *args) + { + using namespace Genode; + + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); + + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (unsigned long)sizeof(Lan9118)); + if (ram_quota < session_size) + throw Genode::Root::Quota_exceeded(); + + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size + || rx_buf_size > ram_quota - session_size + || tx_buf_size + rx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + rx_buf_size + session_size); + throw Genode::Root::Quota_exceeded(); + } + + return new (Root::md_alloc()) + Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, + tx_buf_size, rx_buf_size, + *env()->heap(), + *env()->ram_session(), + _ep); + } + + public: + + Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc) + : Genode::Root_component(&ep.rpc_ep(), &md_alloc), + _ep(ep) + { } +}; + +struct Server::Main +{ + Entrypoint &ep; + ::Root nic_root{ ep, *Genode::env()->heap() }; + + Main(Entrypoint &ep) : ep(ep) { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - { - return new (env()->heap()) - Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc, notify); - } + printf("--- LAN9118 NIC driver started ---\n"); + Genode::env()->parent()->announce(ep.manage(nic_root)); + } +}; - void destroy(Nic::Driver *driver) - { - Genode::destroy(env()->heap(), static_cast(driver)); - } - } driver_factory; +namespace Server { - enum { STACK_SIZE = 4096 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep"); + char const *name() { return "nic_ep"; } - static Nic::Root nic_root(&ep, env()->heap(), driver_factory); - env()->parent()->announce(ep.manage(&nic_root)); + size_t stack_size() { return 2*1024*sizeof(long); } - Genode::sleep_forever(); - return 0; + void construct(Entrypoint &ep) + { + static Main main(ep); + } } + diff --git a/repos/os/src/drivers/nic/lan9118/target.mk b/repos/os/src/drivers/nic/lan9118/target.mk index 5e8635fe9c..34d51e6eab 100644 --- a/repos/os/src/drivers/nic/lan9118/target.mk +++ b/repos/os/src/drivers/nic/lan9118/target.mk @@ -1,5 +1,5 @@ REQUIRES = lan9118 TARGET = nic_drv SRC_CC = main.cc -LIBS = base +LIBS = base server INC_DIR += $(PRG_DIR) diff --git a/repos/os/src/drivers/nic/linux/main.cc b/repos/os/src/drivers/nic/linux/main.cc index b7213de2f6..1111c0b48d 100644 --- a/repos/os/src/drivers/nic/linux/main.cc +++ b/repos/os/src/drivers/nic/linux/main.cc @@ -2,6 +2,7 @@ * \brief NIC driver for Linux TUN/TAP device * \author Stefan Kalkowski * \author Christian Helmuth + * \author Sebastian Sumpf * \date 2011-08-08 * * Configuration options are: @@ -23,9 +24,8 @@ */ /* Genode */ -#include -#include -#include +#include +#include #include #include @@ -37,18 +37,20 @@ #include #include +namespace Server { struct Main; } -class Linux_driver : public Nic::Driver + +class Linux_session_component : public Nic::Session_component { private: - struct Rx_thread : Genode::Thread<0x2000> + struct Rx_signal_thread : Genode::Thread<0x1000> { - int fd; - Nic::Driver &driver; + int fd; + Genode::Signal_context_capability sigh; - Rx_thread(int fd, Nic::Driver &driver) - : Genode::Thread<0x2000>("rx"), fd(fd), driver(driver) { } + Rx_signal_thread(int fd, Genode::Signal_context_capability sigh) + : Genode::Thread<0x1000>("rx_signal"), fd(fd), sigh(sigh) { } void entry() { @@ -61,19 +63,15 @@ class Linux_driver : public Nic::Driver FD_SET(fd, &rfds); do { ret = select(fd + 1, &rfds, 0, 0, 0); } while (ret < 0); - /* inform driver about incoming packet */ - driver.handle_irq(fd); + /* signal incoming packet */ + Genode::Signal_transmitter(sigh).submit(); } } }; - Nic::Mac_address _mac_addr; - Nic::Rx_buffer_alloc &_alloc; - Nic::Driver_notification &_notify; - - char _packet_buffer[1514]; /* maximum ethernet packet length */ - int _tap_fd; - Rx_thread _rx_thread; + Nic::Mac_address _mac_addr; + int _tap_fd; + Rx_signal_thread _rx_thread; int _setup_tap_fd() { @@ -88,6 +86,12 @@ class Linux_driver : public Nic::Driver throw Genode::Exception(); } + /* set fd to non-blocking */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + PERR("could not set /dev/net/tun to non-blocking"); + throw Genode::Exception(); + } + Genode::memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; @@ -113,13 +117,85 @@ class Linux_driver : public Nic::Driver return fd; } + bool _send() + { + using namespace Genode; + + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; + } + + int ret; + + /* non-blocking-write packet to TAP */ + do { + ret = write(_tap_fd, _tx.sink()->packet_content(packet), packet.size()); + /* drop packet if write would block */ + if (ret < 0 && errno == EAGAIN) + continue; + + if (ret < 0) PERR("write: errno=%d", errno); + } while (ret < 0); + + _tx.sink()->acknowledge_packet(packet); + + return true; + } + + bool _receive() + { + unsigned const max_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE; + + if (!_rx.source()->ready_to_submit()) + return false; + + Nic::Packet_descriptor p; + try { + p = _rx.source()->alloc_packet(max_size); + } catch (Session::Rx::Source::Packet_alloc_failed) { return false; } + + int size = read(_tap_fd, _rx.source()->packet_content(p), max_size); + if (size <= 0) { + _rx.source()->release_packet(p); + return false; + } + + /* adjust packet size */ + Nic::Packet_descriptor p_adjust(p.offset(), size); + _rx.source()->submit_packet(p_adjust); + + return true; + } + + protected: + + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + while (_send()) ; + while (_receive()) ; + } + public: - Linux_driver(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) + Linux_session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) : - _alloc(alloc), _notify(notify), - _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this) + Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep), + _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, _packet_stream_dispatcher) { /* try using configured MAC address */ try { @@ -145,93 +221,23 @@ class Linux_driver : public Nic::Driver _rx_thread.start(); } - void link_state_changed() { _notify.link_state_changed(); } - - - /*************************** - ** Nic::Driver interface ** - ***************************/ - - Nic::Mac_address mac_address() { return _mac_addr; } - - bool link_state() - { - /* XXX return always true for now */ - return true; - } - - void tx(char const *packet, Genode::size_t size) - { - int ret; - - /* blocking-write packet to TAP */ - do { - ret = write(_tap_fd, packet, size); - if (ret < 0) PERR("write: errno=%d", errno); - } while (ret < 0); - } - - - /****************************** - ** Irq_activation interface ** - ******************************/ - - void handle_irq(int) - { - int ret; - - /* blocking read incoming packet */ - do { - ret = read(_tap_fd, _packet_buffer, sizeof(_packet_buffer)); - if (ret < 0) PERR("read: errno=%d", errno); - } while (ret < 0); - - void *buffer = _alloc.alloc(ret); - Genode::memcpy(buffer, _packet_buffer, ret); - _alloc.submit(); - } + bool link_state() override { return true; } + Nic::Mac_address mac_address() override { return _mac_addr; } }; -/* - * Manually initialize the 'lx_environ' pointer, needed because 'nic_drv' is not - * using the normal Genode startup code. - */ -extern char **environ; -char **lx_environ = environ; - - -int main(int, char **) +struct Server::Main { - using namespace Genode; + Entrypoint &ep; + Nic::Root nic_root{ ep, *Genode::env()->heap() }; - printf("--- Linux/tap NIC driver started ---\n"); - - /** - * Factory used by 'Nic::Root' at session creation/destruction time - */ - struct Linux_driver_factory : Nic::Driver_factory + Main(Entrypoint &ep) : ep(ep) { - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) - { - return new (env()->heap()) Linux_driver(alloc, notify); - } + Genode::env()->parent()->announce(ep.manage(nic_root)); + } +}; - void destroy(Nic::Driver *driver) - { - Genode::destroy(env()->heap(), static_cast(driver)); - } - } driver_factory; - - enum { STACK_SIZE = 2*4096 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep"); - - static Nic::Root nic_root(&ep, env()->heap(), driver_factory); - env()->parent()->announce(ep.manage(&nic_root)); - - sleep_forever(); - return 0; -} +char const * Server::name() { return "nic_ep"; } +size_t Server::stack_size() { return 2*1024*sizeof(long); } +void Server::construct(Entrypoint &ep) { static Main main(ep); } diff --git a/repos/os/src/drivers/nic/linux/target.mk b/repos/os/src/drivers/nic/linux/target.mk index 953ce5e00b..d76d0fc993 100644 --- a/repos/os/src/drivers/nic/linux/target.mk +++ b/repos/os/src/drivers/nic/linux/target.mk @@ -1,4 +1,4 @@ TARGET = nic_drv REQUIRES = linux -LIBS = lx_hybrid config +LIBS = lx_hybrid config server SRC_CC = main.cc diff --git a/repos/os/src/server/nic_loopback/main.cc b/repos/os/src/server/nic_loopback/main.cc index 14616d7778..0e1a377947 100644 --- a/repos/os/src/server/nic_loopback/main.cc +++ b/repos/os/src/server/nic_loopback/main.cc @@ -15,19 +15,16 @@ #include #include -#include #include -#include #include #include #include -#include -#include +#include +#include namespace Nic { - class Communication_buffers; - class Session_component; + class Loopback_component; class Root; } @@ -35,36 +32,8 @@ namespace Nic { namespace Server { struct Main; } -class Nic::Communication_buffers +class Nic::Loopback_component : public Nic::Session_component { - protected: - - Genode::Allocator_avl _rx_packet_alloc; - - Genode::Attached_ram_dataspace _tx_ds, _rx_ds; - - Communication_buffers(Genode::Allocator &rx_block_md_alloc, - Genode::Ram_session &ram_session, - Genode::size_t tx_size, Genode::size_t rx_size) - : - _rx_packet_alloc(&rx_block_md_alloc), - _tx_ds(&ram_session, tx_size), - _rx_ds(&ram_session, rx_size) - { } -}; - - -class Nic::Session_component : Communication_buffers, public Session_rpc_object -{ - private: - - Server::Entrypoint &_ep; - - void _handle_packet_stream(unsigned); - - Genode::Signal_rpc_member _packet_stream_dispatcher { - _ep, *this, &Session_component::_handle_packet_stream }; - public: /** @@ -78,46 +47,37 @@ class Nic::Session_component : Communication_buffers, public Session_rpc_object * \param ep entry point used for packet stream * channels */ - Session_component(Genode::size_t const tx_buf_size, - Genode::size_t const rx_buf_size, - Genode::Allocator &rx_block_md_alloc, - Genode::Ram_session &ram_session, - Server::Entrypoint &ep) - : - Communication_buffers(rx_block_md_alloc, ram_session, - tx_buf_size, rx_buf_size), - Session_rpc_object(this->_tx_ds.cap(), - this->_rx_ds.cap(), - &this->_rx_packet_alloc, ep.rpc_ep()), - _ep(ep) - { - /* install data-flow signal handlers for both packet streams */ - _tx.sigh_ready_to_ack(_packet_stream_dispatcher); - _tx.sigh_packet_avail(_packet_stream_dispatcher); - _rx.sigh_ready_to_submit(_packet_stream_dispatcher); - _rx.sigh_ack_avail(_packet_stream_dispatcher); - } + Loopback_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) + : Session_component(tx_buf_size, rx_buf_size, + rx_block_md_alloc, ram_session, ep) + { } - Mac_address mac_address() + Mac_address mac_address() override { Mac_address result = {{1,2,3,4,5,6}}; return result; } - bool link_state() + bool link_state() override { /* XXX always return true, for now */ return true; } - void link_state_sigh(Genode::Signal_context_capability sigh) { } + void _handle_packet_stream() override; }; -void Nic::Session_component::_handle_packet_stream(unsigned) +void Nic::Loopback_component::_handle_packet_stream() { using namespace Genode; + unsigned const alloc_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE; + /* loop unless we cannot make any progress */ for (;;) { @@ -154,35 +114,36 @@ void Nic::Session_component::_handle_packet_stream(unsigned) * We are safe to process one packet without blocking. */ + + Packet_descriptor packet_to_client; + try { + packet_to_client = _rx.source()->alloc_packet(alloc_size); + } catch (Session::Rx::Source::Packet_alloc_failed) { + continue; + } + /* obtain packet */ Packet_descriptor const packet_from_client = _tx.sink()->get_packet(); if (!packet_from_client.valid()) { PWRN("received invalid packet"); + _rx.source()->release_packet(packet_to_client); continue; } - try { - size_t const packet_size = packet_from_client.size(); - - Packet_descriptor const packet_to_client = - _rx.source()->alloc_packet(packet_size); - Genode::memcpy(_rx.source()->packet_content(packet_to_client), _tx.sink()->packet_content(packet_from_client), - packet_size); + packet_from_client.size()); + packet_to_client = Packet_descriptor(packet_to_client.offset(), packet_from_client.size()); _rx.source()->submit_packet(packet_to_client); - } catch (Session::Rx::Source::Packet_alloc_failed) { - PWRN("transmit packet allocation failed, drop packet"); - } _tx.sink()->acknowledge_packet(packet_from_client); } } -class Nic::Root : public Genode::Root_component +class Nic::Root : public Genode::Root_component { private: @@ -190,7 +151,7 @@ class Nic::Root : public Genode::Root_component protected: - Session_component *_create_session(const char *args) + Loopback_component*_create_session(const char *args) { using namespace Genode; @@ -216,7 +177,7 @@ class Nic::Root : public Genode::Root_component throw Root::Quota_exceeded(); } - return new (md_alloc()) Session_component(tx_buf_size, rx_buf_size, + return new (md_alloc()) Loopback_component(tx_buf_size, rx_buf_size, *env()->heap(), *env()->ram_session(), _ep); @@ -226,7 +187,7 @@ class Nic::Root : public Genode::Root_component Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc) : - Genode::Root_component(&ep.rpc_ep(), &md_alloc), + Genode::Root_component(&ep.rpc_ep(), &md_alloc), _ep(ep) { } }; diff --git a/repos/ports/src/app/openvpn/main.cc b/repos/ports/src/app/openvpn/main.cc index 2b14aca824..c7852918a0 100644 --- a/repos/ports/src/app/openvpn/main.cc +++ b/repos/ports/src/app/openvpn/main.cc @@ -82,14 +82,12 @@ Tuntap_device *tuntap_dev() ** Implementation of the Nic service ** ***************************************/ -class Nic_driver : public Tuntap_device, - public Nic::Driver +class Openvpn_component : public Tuntap_device, + public Nic::Session_component { private: Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }}; - Nic::Rx_buffer_alloc &_alloc; - Nic::Driver_notification &_notify; char const *_packet; @@ -99,12 +97,52 @@ class Nic_driver : public Tuntap_device, Genode::Semaphore _startup_lock; Genode::Semaphore _tx_lock; + protected: + + bool _send() + { + using namespace Genode; + + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + Packet_descriptor packet = _tx.sink()->get_packet(); + if (!packet.valid()) { + PWRN("Invalid tx packet"); + return true; + } + + _packet = _tx.sink()->packet_content(packet); + + /* notify openvpn */ + ::write(_pipefd[WRITE], "1", 1); + + /* block while openvpn handles the packet */ + _tx_lock.down(); + _tx.sink()->acknowledge_packet(packet); + + return true; + } + + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + while (_send()) ; + } public: - Nic_driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify) - : - _alloc(alloc), _notify(notify), _packet(0) + Openvpn_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator &rx_block_md_alloc, + Genode::Ram_session &ram_session, + Server::Entrypoint &ep) + : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep) { if (pipe(_pipefd)) { PERR("could not create pipe"); @@ -112,41 +150,18 @@ class Nic_driver : public Tuntap_device, } } - ~Nic_driver() { PDBG("should probably be implemented"); } + /************************************** + ** Nic::Session_component interface ** + **************************************/ - void link_state_changed() { _notify.link_state_changed(); } + Nic::Mac_address mac_address() override { return _mac_addr; } - /*************************** - ** Nic::Driver interface ** - ***************************/ - - Nic::Mac_address mac_address() { return _mac_addr; } - - bool link_state() + bool link_state() override { /* XXX always return true for now */ return true; } - void tx(char const *packet, Genode::size_t size) - { - PDBGV("packet:0x%p size:%zu", packet, size); - - _packet = packet; - - /* notify openvpn */ - ::write(_pipefd[WRITE], "1", 1); - - /* block while openvpn handles the packet */ - _tx_lock.down(); - } - - /****************************** - ** Irq_activation interface ** - ******************************/ - - void handle_irq(int) { } - /*********************** ** TUN/TAP interface ** ***********************/ @@ -171,10 +186,16 @@ class Nic_driver : public Tuntap_device, int write(char const *buf, Genode::size_t len) { PDBGV("buf:0x%p len:%zu", len); + _handle_packet_stream(); - void *buffer = _alloc.alloc(len); - Genode::memcpy(buffer, buf, len); - _alloc.submit(); + if (!_rx.source()->ready_to_submit()) + return 0; + + try { + Genode::Packet_descriptor packet = _rx.source()->alloc_packet(len); + Genode::memcpy(_rx.source()->packet_content(packet), buf, len); + _rx.source()->submit_packet(packet); + } catch (...) { return 0; } return len; } @@ -185,57 +206,86 @@ class Nic_driver : public Tuntap_device, }; -struct Main +class Root : public Genode::Root_component { - struct Nic_driver_factory : Nic::Driver_factory - { - Nic_driver *drv { 0 }; - Openvpn_thread *openvpn { 0 }; + private: - Nic::Driver *create(Nic::Rx_buffer_alloc &alloc, - Nic::Driver_notification ¬ify) + Server::Entrypoint &_ep; + Openvpn_thread *_thread = nullptr; + + protected: + + Openvpn_component *_create_session(const char *args) { - /* there can be only one */ - if (!drv) { - drv = new (Genode::env()->heap()) Nic_driver(alloc, notify); + using namespace Genode; - /** - * Setting the pointer in this manner is quite hackish but it has - * to be valid before OpenVPN calls open_tun(), which unfortunatly - * is early. - */ - _tuntap_dev = drv; + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); - PDBGV("start OpenVPN main thread"); - Openvpn_thread *openvpn = new (Genode::env()->heap()) Openvpn_thread(genode_argc, - genode_argv); + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (unsigned long)sizeof(Openvpn_component)); + if (ram_quota < session_size) + throw Genode::Root::Quota_exceeded(); - openvpn->start(); - - /* wait until OpenVPN configured the TUN/TAP device for the first time */ - _tuntap_dev->down(); - - return drv; + /* + * Check if donated ram quota suffices for both communication + * buffers. Also check both sizes separately to handle a + * possible overflow of the sum of both sizes. + */ + if (tx_buf_size > ram_quota - session_size + || rx_buf_size > ram_quota - session_size + || tx_buf_size + rx_buf_size > ram_quota - session_size) { + PERR("insufficient 'ram_quota', got %zd, need %zd", + ram_quota, tx_buf_size + rx_buf_size + session_size); + throw Genode::Root::Quota_exceeded(); } - return 0; + Openvpn_component *component = new (Root::md_alloc()) + Openvpn_component(tx_buf_size, rx_buf_size, + *env()->heap(), + *env()->ram_session(), + _ep); + /** + * Setting the pointer in this manner is quite hackish but it has + * to be valid before OpenVPN calls open_tun(), which unfortunatly + * is early. + */ + _tuntap_dev = component; + + PDBGV("start OpenVPN main thread"); + _thread = new (Genode::env()->heap()) Openvpn_thread(genode_argc, genode_argv); + _thread->start(); + + /* wait until OpenVPN configured the TUN/TAP device for the first time */ + _tuntap_dev->down(); + + return component; } - void destroy(Nic::Driver *driver) + void _destroy_session(Openvpn_component *session) { - Genode::destroy(Genode::env()->heap(), static_cast(driver)); - drv = 0; - Genode::destroy(Genode::env()->heap(), openvpn); - openvpn = 0; + Genode::destroy(Root::md_alloc(), session); + Genode::destroy(Root::md_alloc(), _thread); + _thread = nullptr; } - } driver_factory; + public: + + Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc) + : Genode::Root_component(&ep.rpc_ep(), &md_alloc), + _ep(ep) + { } +}; + + +struct Main +{ Server::Entrypoint &ep; + ::Root nic_root { ep, *Genode::env()->heap() }; Main(Server::Entrypoint &ep) : ep(ep) { - static Nic::Root nic_root(&ep.rpc_ep(), Genode::env()->heap(), driver_factory); - Genode::env()->parent()->announce(ep.manage(nic_root)); } };