diff --git a/repos/dde_linux/fec.list b/repos/dde_linux/fec.list index 90e72bd720..9f83f66c25 100644 --- a/repos/dde_linux/fec.list +++ b/repos/dde_linux/fec.list @@ -4,6 +4,7 @@ linux-x.x.x/drivers/net/ethernet/freescale/fec_ptp.c linux-x.x.x/drivers/net/phy/mdio_bus.c linux-x.x.x/drivers/net/phy/phy_device.c linux-x.x.x/drivers/net/phy/phy.c +linux-x.x.x/drivers/net/phy/at803x.c linux-x.x.x/net/core/skbuff.c linux-x.x.x/net/ethernet/eth.c linux-x.x.x/include/asm-generic/atomic64.h @@ -15,6 +16,7 @@ linux-x.x.x/include/asm-generic/bitops/fls.h linux-x.x.x/include/asm-generic/bitops/fls64.h linux-x.x.x/include/linux/errqueue.h linux-x.x.x/include/linux/fec.h +linux-x.x.x/include/linux/gpio/consumer.h linux-x.x.x/include/linux/if_ether.h linux-x.x.x/include/linux/list.h linux-x.x.x/include/linux/list_nulls.h diff --git a/repos/dde_linux/patches/fec_tx_bounce_dma.patch b/repos/dde_linux/patches/fec_tx_bounce_dma.patch new file mode 100644 index 0000000000..4b0b4ee778 --- /dev/null +++ b/repos/dde_linux/patches/fec_tx_bounce_dma.patch @@ -0,0 +1,13 @@ +diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c +index b2a3220..18629c6 100644 +--- a/drivers/net/ethernet/freescale/fec_main.c ++++ b/drivers/net/ethernet/freescale/fec_main.c +@@ -2825,7 +2825,7 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue) + txq = fep->tx_queue[queue]; + bdp = txq->tx_bd_base; + for (i = 0; i < txq->tx_ring_size; i++) { +- txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); ++ txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL | GFP_LX_DMA); + if (!txq->tx_bounce[i]) + goto err_alloc; + diff --git a/repos/dde_linux/ports/dde_linux.hash b/repos/dde_linux/ports/dde_linux.hash index f9231242fb..f9ab7d4ebe 100644 --- a/repos/dde_linux/ports/dde_linux.hash +++ b/repos/dde_linux/ports/dde_linux.hash @@ -1 +1 @@ -82b2f79a8ecbbfeb42de534b776c6b348573bd60 +7f9bd747fe1d1ca7e19a46100b0f4d125698a5d4 diff --git a/repos/dde_linux/ports/dde_linux.port b/repos/dde_linux/ports/dde_linux.port index 3f400addcc..23afd5dd31 100644 --- a/repos/dde_linux/ports/dde_linux.port +++ b/repos/dde_linux/ports/dde_linux.port @@ -225,5 +225,6 @@ PATCH_OPT(patches/intel_fb_backlight.patch) := -p1 -d$(SRC_DIR_INTEL_FB) # Freescale NIC PATCH_OPT(patches/fec_skbuff_cast.patch) := -p1 -d$(SRC_DIR_FEC) +PATCH_OPT(patches/fec_tx_bounce_dma.patch) := -p1 -d$(SRC_DIR_FEC) # vi: set ft=make : diff --git a/repos/dde_linux/src/drivers/nic/fec/component.cc b/repos/dde_linux/src/drivers/nic/fec/component.cc index 13e404e979..fdac2710e3 100644 --- a/repos/dde_linux/src/drivers/nic/fec/component.cc +++ b/repos/dde_linux/src/drivers/nic/fec/component.cc @@ -130,8 +130,7 @@ void Session_component::unblock_rx_task(napi_struct * n) Nic::Mac_address Session_component::mac_address() { - net_device * dev = fec_get_my_registered_net_device(); - return dev ? Nic::Mac_address(dev->dev_addr) : Nic::Mac_address(); + return _ndev ? Nic::Mac_address(_ndev->dev_addr) : Nic::Mac_address(); } @@ -170,11 +169,14 @@ void Session_component::link_state(bool link) } -Session_component::Session_component(Genode::size_t const tx_buf_size, - Genode::size_t const rx_buf_size, - Genode::Allocator & rx_block_md_alloc, - Genode::Env & env) +Session_component::Session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator & rx_block_md_alloc, + Genode::Env & env, + Genode::Session_label label) : Nic::Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env), - _ndev(fec_get_my_registered_net_device()), - _has_link(!(_ndev->state & (1UL << __LINK_STATE_NOCARRIER))) { - _register_session_component(*this); } + _ndev(_register_session_component(*this, label)), + _has_link(_ndev ? !(_ndev->state & (1UL << __LINK_STATE_NOCARRIER)) : false) +{ + if (!_ndev) throw Genode::Service_denied(); +} diff --git a/repos/dde_linux/src/drivers/nic/fec/component.h b/repos/dde_linux/src/drivers/nic/fec/component.h index cf1f0b7590..09ae289173 100644 --- a/repos/dde_linux/src/drivers/nic/fec/component.h +++ b/repos/dde_linux/src/drivers/nic/fec/component.h @@ -15,7 +15,8 @@ #define _SRC__DRIVERS__NIC__FEC__COMPONENT_H_ /* Genode includes */ -#include +#include +#include #include @@ -47,7 +48,8 @@ class Session_component : public Nic::Session_component static void _run_tx_task(void * args); static void _run_rx_task(void * args); - static void _register_session_component(Session_component &); + static net_device * _register_session_component(Session_component &, + Genode::Session_label); Lx::Task _tx_task { _run_tx_task, &_tx_data, "tx_task", Lx::Task::PRIORITY_1, Lx::scheduler() }; @@ -60,10 +62,11 @@ class Session_component : public Nic::Session_component public: - Session_component(Genode::size_t const tx_buf_size, - Genode::size_t const rx_buf_size, - Genode::Allocator & rx_block_md_alloc, - Genode::Env & env); + Session_component(Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size, + Genode::Allocator & rx_block_md_alloc, + Genode::Env & env, + Genode::Session_label label); Nic::Mac_address mac_address() override; bool link_state() override { return _has_link; } @@ -72,4 +75,53 @@ class Session_component : public Nic::Session_component void unblock_rx_task(napi_struct * n); }; + +class Root : public Genode::Root_component +{ + private: + + Genode::Env &_env; + Genode::Allocator &_md_alloc; + + protected: + + Session_component *_create_session(const char *args) + { + using namespace Genode; + + Session_label const label = label_from_args(args); + + 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::Insufficient_ram_quota(); + + /* + * Check if donated ram quota suffices for both communication + * buffers and check for overflow + */ + if (tx_buf_size + rx_buf_size < tx_buf_size || + tx_buf_size + rx_buf_size > ram_quota - session_size) { + Genode::error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", tx_buf_size + rx_buf_size + session_size); + throw Genode::Insufficient_ram_quota(); + } + + return new (Root::md_alloc()) + Session_component(tx_buf_size, rx_buf_size, + _md_alloc, _env, label); + } + + public: + + Root(Genode::Env &env, Genode::Allocator &md_alloc) + : Genode::Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _md_alloc(md_alloc) + { } +}; + #endif /* _SRC__DRIVERS__NIC__FEC__COMPONENT_H_ */ diff --git a/repos/dde_linux/src/drivers/nic/fec/dummy.c b/repos/dde_linux/src/drivers/nic/fec/dummy.c index b1e3239a15..05d3a03d1b 100644 --- a/repos/dde_linux/src/drivers/nic/fec/dummy.c +++ b/repos/dde_linux/src/drivers/nic/fec/dummy.c @@ -34,12 +34,6 @@ int disable_irq(unsigned int irq) return -1; } -int disable_irq_nosync(unsigned int irq) -{ - TRACE_AND_STOP; - return -1; -} - int disable_irq_wake(unsigned int irq) { TRACE_AND_STOP; @@ -62,12 +56,6 @@ int enable_irq_wake(unsigned int irq) return -1; } -int enable_irq(unsigned int irq) -{ - TRACE_AND_STOP; - return -1; -} - void eth_hw_addr_random(struct net_device *dev) { TRACE_AND_STOP; @@ -170,53 +158,18 @@ struct timespec64 ns_to_timespec64(const s64 nsec) return ret; } -bool of_device_is_available(const struct device_node *device) -{ - TRACE_AND_STOP; - return -1; -} - -const void *of_get_mac_address(struct device_node *np) -{ - TRACE_AND_STOP; - return NULL; -} - -int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) -{ - TRACE_AND_STOP; - return -1; -} - struct device_node *of_node_get(struct device_node *node) { TRACE_AND_STOP; return NULL; } -void of_node_put(struct device_node *node) -{ - TRACE_AND_STOP; -} - -struct phy_device *of_phy_connect(struct net_device *dev, struct device_node *phy_np, void (*hndlr)(struct net_device *), u32 flags, int iface) -{ - TRACE_AND_STOP; - return NULL; -} - int of_phy_register_fixed_link(struct device_node *np) { TRACE_AND_STOP; return -1; } -int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value) -{ - TRACE_AND_STOP; - return -1; -} - void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) { TRACE_AND_STOP; @@ -246,16 +199,6 @@ resource_size_t resource_size(const struct resource *res) return -1; } -void rtnl_lock(void) -{ - TRACE_AND_STOP; -} - -void rtnl_unlock(void) -{ - TRACE_AND_STOP; -} - bool page_is_pfmemalloc(struct page *page) { TRACE_AND_STOP; @@ -289,12 +232,6 @@ u64 timecounter_cyc2time(struct timecounter *tc, cycle_t cycle_tstamp) return -1; } -u64 timecounter_read(struct timecounter *tc) -{ - TRACE_AND_STOP; - return -1; -} - void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) { TRACE_AND_STOP; @@ -342,12 +279,6 @@ int strcmp(const char *s1, const char *s2) return -1; } -int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) -{ - TRACE_AND_STOP; - return -1; -} - void class_unregister(struct class *cls) { TRACE_AND_STOP; diff --git a/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc index 641f2e2eb6..8f8d6b9e94 100644 --- a/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc +++ b/repos/dde_linux/src/drivers/nic/fec/lx_emul.cc @@ -16,8 +16,11 @@ * prevent shenanigans with macro definitions. */ #include +#include #include #include +#include +#include #include #include @@ -40,7 +43,6 @@ class Addr_to_page_mapping : public Genode::List::Element { private: - unsigned long _addr { 0 }; struct page *_page { nullptr }; static Genode::List & _list() @@ -51,14 +53,13 @@ class Addr_to_page_mapping : public Genode::List::Element public: - Addr_to_page_mapping(unsigned long addr, struct page *page) - : _addr(addr), _page(page) { } + Addr_to_page_mapping(struct page *page) + : _page(page) { } static void insert(struct page * page) { Addr_to_page_mapping *m = (Addr_to_page_mapping*) Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping)); - m->_addr = (unsigned long)page->addr; m->_page = page; _list().insert(m); } @@ -66,7 +67,7 @@ class Addr_to_page_mapping : public Genode::List::Element static struct page * remove(unsigned long addr) { for (Addr_to_page_mapping *m = _list().first(); m; m = m->next()) - if (m->_addr == addr) { + if ((unsigned long)m->_page->addr == addr) { struct page * ret = m->_page; _list().remove(m); Lx::Malloc::mem().free(m); @@ -75,6 +76,15 @@ class Addr_to_page_mapping : public Genode::List::Element return nullptr; } + + static struct page * find_page(void* addr) + { + for (Addr_to_page_mapping *m = _list().first(); m; m = m->next()) + if ((unsigned long)m->_page->addr <= (unsigned long)addr && + ((unsigned long)m->_page->addr + m->_page->size) > (unsigned long)addr) + return m->_page; + return nullptr; + } }; @@ -145,10 +155,149 @@ class Driver : public Genode::List::Element } }; -static Session_component * session = nullptr; -void Session_component::_register_session_component(Session_component & s) { - session = &s; } +struct Gpio_irq : public Genode::List::Element +{ + unsigned irq_nr; + bool enabled = true; + bool pending = false; + Gpio::Connection gpio; + Genode::Irq_session_client irq; + Genode::Signal_handler sigh; + Lx::Task task; + irq_handler_t ihandler; + void * dev_id; + + /** + * List of all currently registered irqs + */ + static Genode::List *list() + { + static Genode::List _list; + return &_list; + } + + static void run_irq(void *args) + { + Gpio_irq * girq = static_cast(args); + while (1) { + Lx::scheduler().current()->block_and_schedule(); + girq->ihandler(girq->irq_nr, girq->dev_id); + girq->irq.ack_irq(); + } + } + + void unblock() + { + if (enabled) task.unblock(); + + pending = !enabled; + } + + void enable() + { + enabled = true; + if (pending) unblock(); + } + + void disable() + { + enabled = false; + } + + Gpio_irq(Genode::Env &env, unsigned nr, irq_handler_t handler, void * dev_id) + : irq_nr(nr), + gpio(env, nr), + irq(gpio.irq_session(Gpio::Session::LOW_LEVEL)), + sigh(env.ep(), *this, &Gpio_irq::unblock), + task(run_irq, this, "gpio_irq", Lx::Task::PRIORITY_3, Lx::scheduler()), + ihandler(handler), + dev_id(dev_id) + { + list()->insert(this); + + irq.sigh(sigh); + irq.ack_irq(); + } +}; + + +struct Fec +{ + using String = Genode::String<128>; + + struct Mdio + { + struct Phy + { + String name; + String phy_driver; + const unsigned phy_reg; + const unsigned gpio_irq; + struct phy_device * phy_dev { nullptr }; + + Phy(String name, String driver, const unsigned reg, const unsigned irq) + : name(name), phy_driver(driver), phy_reg(reg), gpio_irq(irq) {} + }; + + enum { MAX = 10 }; + Genode::Constructible phys[MAX]; + + template + void for_each(FUNC && f) + { + for (unsigned i = 0; i < MAX; i++) + if (phys[i].constructed()) f(*phys[i]); + } + }; + + String name; + String device; + const unsigned irq; + const size_t mmio; + String phy_mode; + const bool magic_packet; + const int tx_queues; + const int rx_queues; + struct net_device * net_dev { nullptr }; + Session_component * session { nullptr }; + Genode::Attached_io_mem_dataspace io_ds { Lx_kit::env().env(), mmio, 0x4000 }; + Genode::Constructible mdio; + Mdio::Phy * phy { nullptr }; + + Fec(String name, String device, const unsigned irq, + const size_t mmio, String mode, const bool magic = true, + const int tx_queues = 1, const int rx_queues = 1) + : name(name), device(device), irq(irq), mmio(mmio), phy_mode(mode), magic_packet(magic), + tx_queues(tx_queues), rx_queues(rx_queues) {}; +}; + + +static const unsigned FEC_MAX = 2; +static Genode::Constructible fec_devices[FEC_MAX]; + +net_device * Session_component::_register_session_component(Session_component & s, + Genode::Session_label policy) +{ + Genode::Session_label name = policy.last_element(); + + for (unsigned i = 0; i < FEC_MAX; i++) { + + /* No more cards available */ + if (!fec_devices[i].constructed()) return nullptr; + + /* Session does not match cards policy */ + if (fec_devices[i]->name.length() > 1 && + fec_devices[i]->name != name) continue; + + /* Session already in use */ + if (fec_devices[i]->session) return nullptr; + + fec_devices[i]->session = &s; + return fec_devices[i]->net_dev; + } + return nullptr; +} #include @@ -158,18 +307,78 @@ void Session_component::_register_session_component(Session_component & s) { extern "C" { -void lx_backtrace() -{ - Genode::backtrace(); -} - +void lx_backtrace() { Genode::backtrace(); } int platform_driver_register(struct platform_driver * drv) { - static platform_device pd_fec; - static const char * name = "2188000.ethernet"; - pd_fec.name = name; - return drv->probe(&pd_fec); + using String = Fec::String; + + try { + unsigned i = 0; + Genode::Attached_rom_dataspace config { Lx_kit::env().env(), "config" }; + config.xml().for_each_sub_node("card", [&] (Genode::Xml_node const node) { + if (i == FEC_MAX) { + Genode::error("More cards defined than available!"); + return; + } + + String name = node.attribute_value("name", String()); + String type = node.attribute_value("type", String()); + String mdio = node.attribute_value("mii", String()); + String phy = node.attribute_value("phy", String()); + unsigned irq = node.attribute_value("irq", 0UL); + Genode::addr_t mmio = node.attribute_value("mmio", 0UL); + bool magic = node.attribute_value("magic_packet", true); + unsigned txq = node.attribute_value("tx-queues", 1UL); + unsigned rxq = node.attribute_value("rx-queues", 1UL); + fec_devices[i].construct(name, type, irq, mmio, mdio, magic, txq, rxq); + + node.for_each_sub_node("mdio", [&] (Genode::Xml_node const node) { + fec_devices[i]->mdio.construct(); + unsigned j = 0; + node.for_each_sub_node("phy", [&] (Genode::Xml_node const node) { + String name = node.attribute_value("name", String()); + String type = node.attribute_value("type", String()); + unsigned irq = node.attribute_value("gpio_irq", 0UL); + unsigned reg = node.attribute_value("reg_num", 0UL); + fec_devices[i]->mdio->phys[j].construct(name, type, reg, irq); + j++; + }); + }); + + for (unsigned k = 0; k <= i; k++) + if (fec_devices[k]->mdio.constructed()) { + fec_devices[k]->mdio->for_each([&] (Fec::Mdio::Phy & p) { + if (p.name == phy) fec_devices[i]->phy = &p; }); + } + + i++; + }); + } catch(...) { } + + if (!fec_devices[0].constructed()) { + Genode::warning("No valid configuration provided, use default values"); + fec_devices[0].construct(String(), "fsl,imx6q-fec", 150, 0x2188000, "rgmii"); + } + + for (unsigned i = 0; i < FEC_MAX; i++) { + if (!fec_devices[i].constructed()) break; + + platform_device * pd = new (Lx::Malloc::dma()) platform_device(); + pd->name = fec_devices[i]->name.string(); + pd->dev.of_node = (device_node*) &fec_devices[i]; + pd->dev.plat_dev = pd; + drv->probe(pd); + { + net_device * dev = fec_devices[i]->net_dev; + int err = dev ? dev->netdev_ops->ndo_open(dev) : -1; + if (err) { + Genode::error("ndo_open() failed: ", err); + return err; + } + } + } + return 0; } @@ -191,6 +400,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->gso_max_segs = GSO_MAX_SEGS; + setup(dev); + static const struct ethtool_ops default_ethtool_ops { }; if (!dev->ethtool_ops) dev->ethtool_ops = &default_ethtool_ops; @@ -200,34 +411,45 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, } +bool of_device_is_available(const struct device_node *device) +{ + return device; +} + + const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev) { + Fec * fec = (Fec*) dev->plat_dev->dev.of_node; for (; matches && matches->compatible[0]; matches++) - if (Genode::strcmp(matches->compatible, "fsl,imx6q-fec") == 0) + if (Genode::strcmp(matches->compatible, fec->device.string()) == 0) return matches; - return NULL; + return nullptr; } void * devm_ioremap_resource(struct device *dev, struct resource *res) { - static Genode::Attached_io_mem_dataspace io_ds(Lx_kit::env().env(), - 0x2188000, 0x1000); + Fec * fec = (Fec*) dev->plat_dev->dev.of_node; - return io_ds.local_addr(); + return fec->io_ds.local_addr(); } void platform_set_drvdata(struct platform_device *pdev, void *data) { pdev->dev.driver_data = data; + struct net_device * ndev = (net_device*)data; + ndev->dev.of_node = pdev->dev.of_node; } int of_get_phy_mode(struct device_node *np) { + Fec * fec = (Fec*) np; + for (int i = 0; i < PHY_INTERFACE_MODE_MAX; i++) - if (!Genode::strcmp("rgmii", phy_modes((phy_interface_t)i))) + if (!Genode::strcmp(fec->phy_mode.string(), + phy_modes((phy_interface_t)i))) return i; return -ENODEV; @@ -255,11 +477,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *addr = Lx::Malloc::dma().alloc_large(size); + dma_addr_t dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(addr); - static unsigned waechter = 0; - ASSERT(!waechter++); - - *dma_handle = (dma_addr_t) addr; + *dma_handle = (dma_addr_t) dma_addr; return addr; } @@ -267,7 +487,12 @@ void *dma_alloc_coherent(struct device *dev, size_t size, void *dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) { dma_addr_t dma_addr; - void *addr = Lx::Malloc::dma().alloc(size, 12, &dma_addr); + void *addr; + if (size > 2048) { + addr = Lx::Malloc::dma().alloc_large(size); + dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(addr); + } else + addr = Lx::Malloc::dma().alloc(size, 12, &dma_addr); *dma_handle = dma_addr; return addr; @@ -279,9 +504,18 @@ dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, { dma_addr_t dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(cpu_addr); - if (dma_addr == ~0UL) - Genode::error(__func__, ": virtual address ", cpu_addr, - " not registered for DMA"); + if (dma_addr == ~0UL) { + + struct page * p = Addr_to_page_mapping::find_page(cpu_addr); + if (p) { + dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(p->addr); + dma_addr += (dma_addr_t)cpu_addr - (dma_addr_t)p->addr; + } + + if (dma_addr == ~0UL) + Genode::error(__func__, ": virtual address ", cpu_addr, + " not registered for DMA"); + } return dma_addr; } @@ -308,14 +542,18 @@ int netif_running(const struct net_device *dev) void netif_carrier_on(struct net_device *dev) { dev->state &= ~(1UL << __LINK_STATE_NOCARRIER); - if (session) session->link_state(true); + + Fec * fec = (Fec*) dev->dev.of_node; + if (fec->session) fec->session->link_state(true); } void netif_carrier_off(struct net_device *dev) { dev->state |= 1UL << __LINK_STATE_NOCARRIER; - if (session) session->link_state(false); + + Fec * fec = (Fec*) dev->dev.of_node; + if (fec->session) fec->session->link_state(false); } @@ -331,7 +569,9 @@ int platform_get_irq(struct platform_device * d, unsigned int i) { if (i > 1) return -1; - return 150 + i; + Fec * fec = (Fec*) d->dev.of_node; + + return fec->irq + i; } @@ -346,14 +586,17 @@ struct clk *devm_clk_get(struct device *dev, const char *id) { static struct clk clocks[] { { "ipg", 66*1000*1000 }, - { "ahb", 132*1000*1000 }, - { "enet_clk_ref", 500*1000*1000 } }; + { "ahb", 198*1000*1000 }, + { "ptp", 25*1000*1000 }, + { "enet_out", 25*1000*1000 }, + { "enet_clk_ref", 125*1000*1000 } }; for (unsigned i = 0; i < (sizeof(clocks) / sizeof(struct clk)); i++) if (Genode::strcmp(clocks[i].name, id) == 0) return &clocks[i]; - return NULL; + Genode::error("MISSING CLOCK: ", id); + return nullptr; } @@ -372,31 +615,17 @@ int is_valid_ether_addr(const u8 * a) } -static struct net_device * my_net_device = nullptr; - - int register_netdev(struct net_device * d) { - my_net_device = d; - d->state |= (1 << __LINK_STATE_START) | (1UL << __LINK_STATE_NOCARRIER); - int err = d->netdev_ops->ndo_open(d); - if (err) { - Genode::error("ndo_open() failed: ", err); - return err; - } + Fec * fec = (Fec*) d->dev.of_node; + fec->net_dev = d; return 0; } -struct net_device * fec_get_my_registered_net_device() -{ - return my_net_device; -} - - void *kmem_cache_alloc_node(struct kmem_cache *cache, gfp_t, int) { return (void*)cache->alloc(); @@ -413,7 +642,8 @@ static struct page *allocate_pages(gfp_t gfp_mask, size_t const size) { struct page *page = (struct page *)kzalloc(sizeof(struct page), 0); - page->addr = Lx::Malloc::dma().alloc(size, 12); + page->addr = Lx::Malloc::dma().alloc_large(size); + page->size = size; if (!page->addr) { Genode::error("alloc_pages: ", size, " failed"); @@ -451,7 +681,7 @@ void __free_page_frag(void *addr) if (!atomic_dec_and_test(&page->_count)) Genode::error("page reference count != 0"); - Lx::Malloc::dma().free(page->addr); + Lx::Malloc::dma().free_large(page->addr); kfree(page); } @@ -513,7 +743,7 @@ long __wait_completion(struct completion *work, unsigned long timeout) if (timeout) { setup_timer(&t, _completion_timeout, (unsigned long)Lx::scheduler().current()); - mod_timer(&t, timeout); + mod_timer(&t, j); } while (!work->done) { @@ -533,14 +763,7 @@ long __wait_completion(struct completion *work, unsigned long timeout) work->done = 0; - return j ? j - jiffies : 1; -} - - -int request_module(const char *format, ...) -{ - TRACE; - return 0; + return (j || j == jiffies) ? 1 : j - jiffies; } @@ -599,13 +822,6 @@ int dev_set_name(struct device *dev, const char *fmt, ...) } -int bus_register(struct bus_type *bus) -{ - TRACE; - return 0; -} - - struct device *bus_find_device_by_name(struct bus_type *bus, struct device *start, const char *name) { for (Device *dev = Device::list()->first(); dev; dev = dev->next()) { @@ -656,7 +872,8 @@ void napi_disable(struct napi_struct *n) void __napi_schedule(struct napi_struct *n) { - if (session) session->unblock_rx_task(n); + Fec * fec = (Fec*) n->dev->dev.of_node; + if (fec->session) fec->session->unblock_rx_task(n); } @@ -687,7 +904,8 @@ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsig gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { - if (session) session->receive(skb); + Fec * fec = (Fec*) napi->dev->dev.of_node; + if (fec->session) fec->session->receive(skb); dev_kfree_skb(skb); return GRO_NORMAL; @@ -709,6 +927,192 @@ bool netif_queue_stopped(const struct net_device *dev) } +struct device_node *of_parse_phandle(const struct device_node *np, const char *phandle_name, int index) +{ + Fec * fec = (Fec*) np; + return (device_node*) fec->phy; +} + + +struct phy_device *of_phy_connect(struct net_device *dev, + struct device_node *phy_np, + void (*hndlr)(struct net_device *), + u32 flags, int iface) +{ + Fec::Mdio::Phy * phy = (Fec::Mdio::Phy*) phy_np; + struct phy_device * phydev = phy ? phy->phy_dev : nullptr; + if (!phydev) return nullptr; + + phydev->dev_flags = flags; + int ret = phy_connect_direct(dev, phydev, hndlr, (phy_interface_t)iface); + return ret ? nullptr : phydev; +} + + +struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name) +{ + if (Genode::strcmp("mdio", name) != 0) return nullptr; + + Fec * fec = (Fec*) node; + return fec->mdio.constructed() ? (device_node*) &*fec->mdio : nullptr; +} + + +static int of_mdiobus_register_phy(Fec::Mdio::Phy & ph, struct mii_bus *mdio) +{ + struct phy_device * phy = get_phy_device(mdio, ph.phy_reg, false); + + if (!phy || IS_ERR(phy)) return 1; + + phy->irq = ph.gpio_irq; + phy->dev.of_node = (device_node*) &ph; + + /* All data is now stored in the phy struct; + * register it */ + int rc = phy_device_register(phy); + if (rc) { + phy_device_free(phy); + return 1; + } + + ph.phy_dev = phy; + + dev_dbg(&mdio->dev, "registered phy at address %i\n", ph.phy_reg); + + return 0; +} + +int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) +{ + Fec::Mdio * fec_m = (Fec::Mdio*) np; + + mdio->phy_mask = ~0; + + /* Clear all the IRQ properties */ + if (mdio->irq) + for (unsigned i = 0; iirq[i] = PHY_POLL; + + mdio->dev.of_node = np; + + /* Register the MDIO bus */ + int rc = mdiobus_register(mdio); + if (rc) return rc; + + fec_m->for_each([&] (Fec::Mdio::Phy & phy) { + of_mdiobus_register_phy(phy, mdio); }); + return 0; +} + + +int of_driver_match_device(struct device *dev, const struct device_driver *drv) +{ + Fec::Mdio::Phy * phy = (Fec::Mdio::Phy*) dev->of_node; + + return phy ? (Genode::strcmp(drv->name, + phy->phy_driver.string()) == 0) : 0; +} + + +const void *of_get_property(const struct device_node *node, const char *name, int *lenp) +{ + Fec * fec = (Fec*) node; + if (Genode::strcmp("fsl,magic-packet", name) == 0) return (void*)fec->magic_packet; + + TRACE_AND_STOP; + return nullptr; +} + + +int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value) +{ + Fec * fec = (Fec*) np; + + if (Genode::strcmp("max-speed", propname) == 0) return 1; + + if ((Genode::strcmp("fsl,num-tx-queues", propname) == 0) && fec->tx_queues) + *out_value = fec->tx_queues; + else if ((Genode::strcmp("fsl,num-rx-queues", propname) == 0) && fec->rx_queues) + *out_value = fec->rx_queues; + else + TRACE_AND_STOP; + + return 0; +} + + +void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) +{ + if (size > 2048) Genode::warning("devm_kzalloc ", size); + return Lx::Malloc::mem().alloc(size); +} + + +int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) +{ + new (Lx::Malloc::mem()) Gpio_irq(Lx_kit::env().env(), irq, handler, dev); + return 0; +} + + +int enable_irq(unsigned int irq) +{ + for (Gpio_irq *girq = Gpio_irq::list()->first(); girq; girq = girq->next()) + if (girq->irq_nr == irq) { + girq->enable(); + return 0; + } + return 1; +} + + +int disable_irq_nosync(unsigned int irq) +{ + for (Gpio_irq *girq = Gpio_irq::list()->first(); girq; girq = girq->next()) + if (girq->irq_nr == irq) { + girq->disable(); + return 0; + } + return 1; +} + + +struct device_node *of_get_next_available_child(const struct device_node *node, struct device_node *prev) +{ + TRACE_AND_STOP; + return nullptr; +} + + +u64 timecounter_read(struct timecounter *tc) +{ + u64 nsec; + + cycle_t cycle_now, cycle_delta; + + /* increment time by nanoseconds since last call */ + { + /* read cycle counter: */ + cycle_now = tc->cc->read(tc->cc); + + /* calculate the delta since the last timecounter_read_delta(): */ + cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; + + /* convert to nanoseconds: */ + nsec = cyclecounter_cyc2ns(tc->cc, cycle_delta, + tc->mask, &tc->frac); + + /* update time stamp of timecounter_read_delta() call: */ + tc->cycle_last = cycle_now; + } + + nsec += tc->nsec; + tc->nsec = nsec; + + return nsec; +} + /********************* ** DUMMY FUNCTIONS ** *********************/ @@ -738,31 +1142,13 @@ int device_init_wakeup(struct device *dev, bool val) struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id) { TRACE; - return NULL; -} - -struct device_node *of_get_child_by_name( const struct device_node *node, const char *name) -{ - TRACE; - return NULL; + return nullptr; } struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, unsigned int index) { TRACE; - return NULL; -} - -const void *of_get_property(const struct device_node *node, const char *name, int *lenp) -{ - TRACE; - return NULL; -} - -struct device_node *of_parse_phandle(const struct device_node *np, const char *phandle_name, int index) -{ - TRACE; - return NULL; + return nullptr; } bool of_phy_is_fixed_link(struct device_node *np) @@ -786,7 +1172,7 @@ int pinctrl_pm_select_sleep_state(struct device *dev) struct resource *platform_get_resource(struct platform_device * d, unsigned r1, unsigned r2) { TRACE; - return NULL; + return nullptr; } void pm_runtime_enable(struct device *dev) @@ -818,7 +1204,7 @@ void pm_runtime_use_autosuspend(struct device *dev) struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, struct device *parent) { TRACE; - return NULL; + return (ptp_clock*)0xdeadbeef; } int regulator_enable(struct regulator * d) @@ -827,12 +1213,6 @@ int regulator_enable(struct regulator * d) return 0; } -int of_driver_match_device(struct device *dev, const struct device_driver *drv) -{ - TRACE; - return 0; -} - int class_register(struct class_ *cls) { TRACE; @@ -848,7 +1228,7 @@ int try_module_get(struct module *mod) struct device *get_device(struct device *dev) { TRACE; - return NULL; + return dev; } int device_bind_driver(struct device *dev) @@ -911,4 +1291,37 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size, TRACE; } +void of_node_put(struct device_node *node) +{ + TRACE; +} + +const void *of_get_mac_address(struct device_node *np) +{ + TRACE; + return nullptr; +} + +void rtnl_lock(void) +{ + TRACE; +} + +void rtnl_unlock(void) +{ + TRACE; +} + +int request_module(const char *fmt, ...) +{ + TRACE; + return 0; +} + +int bus_register(struct bus_type *bus) +{ + TRACE; + return 0; +} + } diff --git a/repos/dde_linux/src/drivers/nic/fec/lx_emul.h b/repos/dde_linux/src/drivers/nic/fec/lx_emul.h index 12a01b3d48..23ab82de67 100644 --- a/repos/dde_linux/src/drivers/nic/fec/lx_emul.h +++ b/repos/dde_linux/src/drivers/nic/fec/lx_emul.h @@ -25,7 +25,7 @@ void lx_backtrace(void); -#define DEBUG_LINUX_PRINTK 1 +#define DEBUG_LINUX_PRINTK 0 #define DEBUG 0 #if DEBUG @@ -87,7 +87,7 @@ size_t iov_iter_count(struct iov_iter *i); #define dev_notice(dev, format, arg...) lx_printf("dev_notice: " format , ## arg) #define dev_crit( dev, format, arg...) lx_printf("dev_crit: " format , ## arg) #if DEBUG -#define dev_dbg( dev, format, arg...) lx_printf("dev_dbg: " format , ## arg) +#define dev_dbg( dev, format, arg...) printk("dev_dbg: " format , ## arg) #else #define dev_dbg( dev, format, arg...) #endif @@ -240,6 +240,8 @@ struct attribute_group struct attribute ** attrs; }; +struct platform_device; + struct device { char name[32]; struct device * parent; @@ -251,6 +253,7 @@ struct device { struct bus_type *bus; struct class *class; struct device_node *of_node; + struct platform_device * plat_dev; }; struct platform_device { @@ -340,8 +343,9 @@ enum netdev_state_t { struct net_device { - unsigned long state; - netdev_features_t features; + const char * name; + unsigned long state; + netdev_features_t features; struct net_device_stats stats; netdev_features_t hw_features; const struct net_device_ops *netdev_ops; @@ -358,10 +362,10 @@ struct net_device unsigned char broadcast[MAX_ADDR_LEN]; unsigned long tx_queue_len; int watchdog_timeo; + struct timer_list watchdog_timer; struct device dev; u16 gso_max_segs; struct phy_device *phydev; - char const *name; }; static inline void *netdev_priv(const struct net_device *dev) { @@ -479,6 +483,7 @@ struct page void *addr; dma_addr_t paddr; unsigned long private; + unsigned long size; } __attribute((packed)); static inline struct page *compound_head(struct page *page) { return page; } @@ -585,8 +590,10 @@ void netif_tx_stop_queue(struct netdev_queue *dev_queue); void netif_tx_wake_queue(struct netdev_queue *dev_queue); bool netif_queue_stopped(const struct net_device *dev); +#define CONFIG_ARM 1 #define CONFIG_ARCH_MXC 1 #define CONFIG_OF_MDIO 1 +#define CONFIG_PTP_1588_CLOCK 1 void rtnl_lock(void); void rtnl_unlock(void); @@ -1351,7 +1358,11 @@ void device_release_driver(struct device *dev); struct device *class_find_device(struct class *cls, struct device *start, const void *data, int (*match)(struct device *, const void *)); -#define for_each_available_child_of_node(parent, child) BUG(); while (0) +struct device_node *of_get_next_available_child(const struct device_node *node, struct device_node *prev); + +#define for_each_available_child_of_node(parent, child) \ + for (child = of_get_next_available_child(parent, NULL); child != NULL; \ + child = of_get_next_available_child(parent, child)) u32 mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap); u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv); @@ -1457,8 +1468,11 @@ struct packet_offload *gro_find_complete_by_type(__be16 type); void dev_add_offload(struct packet_offload *po); -struct net_device * fec_get_my_registered_net_device(void); +void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp); +struct pm_qos_request {}; + +#define dma_wmb() __asm__ __volatile__ ("dmb oshst" : : : "memory") #include #endif /* _SRC__DRIVERS__NIC__FEC__LX_EMUL_H_ */ diff --git a/repos/dde_linux/src/drivers/nic/fec/main.cc b/repos/dde_linux/src/drivers/nic/fec/main.cc index 12cd071014..122b00a277 100644 --- a/repos/dde_linux/src/drivers/nic/fec/main.cc +++ b/repos/dde_linux/src/drivers/nic/fec/main.cc @@ -15,7 +15,6 @@ #include #include #include -#include #include @@ -31,6 +30,7 @@ /* Linux module functions */ extern "C" int module_fec_driver_init(); +extern "C" int module_phy_module_init(); extern "C" int subsys_phy_init(); extern "C" void skb_init(); @@ -40,14 +40,12 @@ struct workqueue_struct *system_wq; struct workqueue_struct *system_power_efficient_wq; unsigned long jiffies; - struct Main { - Genode::Env &env; - Genode::Entrypoint &ep { env.ep() }; - Genode::Attached_rom_dataspace config { env, "config" }; - Genode::Heap heap { env.ram(), env.rm() }; - Nic::Root root { env, heap }; + Genode::Env &env; + Genode::Entrypoint &ep { env.ep() }; + Genode::Heap heap { env.ram(), env.rm() }; + Root root { env, heap }; /* Linux task that handles the initialization */ Genode::Constructible linux; @@ -61,7 +59,6 @@ struct Main /* init singleton Lx::Scheduler */ Lx::scheduler(&env); - //Lx::pci_init(env, env.ram(), heap); Lx::malloc_init(env, heap); /* init singleton Lx::Timer */ @@ -95,9 +92,10 @@ static void run_linux(void * m) skb_init(); subsys_phy_init(); + module_phy_module_init(); module_fec_driver_init(); - main.announce(); + main.announce(); while (1) Lx::scheduler().current()->block_and_schedule(); } diff --git a/repos/dde_linux/src/drivers/nic/fec/target.mk b/repos/dde_linux/src/drivers/nic/fec/target.mk index 1a1c2eb89b..66b9063fbc 100644 --- a/repos/dde_linux/src/drivers/nic/fec/target.mk +++ b/repos/dde_linux/src/drivers/nic/fec/target.mk @@ -38,6 +38,7 @@ CC_OPT_skbuff = -Wno-pointer-sign -Wno-int-conversion -Wno-uninitialized CC_OPT_mdio_bus = -Wno-implicit-int -Wno-unused-function -Wno-pointer-sign CC_OPT_eth = -Wno-pointer-sign -Wno-unused-function CC_OPT_phy = -Wno-unused-function -Wno-unused-but-set-variable +CC_OPT_at803x = -Wno-unused-variable vpath %.c $(LX_CONTRIB_DIR)/drivers/net/ethernet/freescale vpath %.c $(LX_CONTRIB_DIR)/drivers/net/phy