Author: gherzan Date: Sun Mar 14 22:30:18 2010 New Revision: 2144 Log: kpisa: add TX workqueue stubs Also update the Makefile with a small ping in the run target. Modified: trunk/kernel/Makefile trunk/kernel/pisa.c Modified: trunk/kernel/Makefile ============================================================================== --- trunk/kernel/Makefile Sun Mar 14 21:47:27 2010 (r2143) +++ trunk/kernel/Makefile Sun Mar 14 22:30:18 2010 (r2144) @@ -21,8 +21,8 @@ clear sudo insmod pisa.ko /sbin/ifconfig -a | grep Link - sleep 1 - ps -ef | grep tx sudo ifconfig pisa0 192.168.10.1 netmask 255.255.0.0 + ps -ef | grep pisa + ping -c 1 -W 1 -I pisa0 192.168.10.2 || true sudo rmmod pisa dmesg | tail Modified: trunk/kernel/pisa.c ============================================================================== --- trunk/kernel/pisa.c Sun Mar 14 21:47:27 2010 (r2143) +++ trunk/kernel/pisa.c Sun Mar 14 22:30:18 2010 (r2144) @@ -15,6 +15,8 @@ #include <linux/netdevice.h> #include <linux/rtnetlink.h> #include <linux/if_arp.h> +#include <linux/spinlock.h> +#include <linux/compiler.h> #include <net/rtnetlink.h> @@ -45,17 +47,68 @@ struct pisa_priv { struct workqueue_struct *tx_wq; struct work_struct tx_work; + struct sk_buff_head tx_list; + int tx_connected; }; + +static int pisa_send(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct pisa_priv *priv __maybe_unused = netdev_priv(dev); + + /* TODO can a better decision be taken here? */ + if (!priv->tx_connected) { + dprintk("not connected, dropping skb %p", skb); + return -ENXIO; + } + + dprintk("sending skb %p via socket", skb); + /* TODO */ + + return 0; +} + +static void pisa_tx_wq_handler(struct work_struct *work) +{ + struct pisa_priv *priv = container_of(work, struct pisa_priv, tx_work); + struct sk_buff *skb = NULL; + struct net_device *dev __maybe_unused = NULL; + int err; + + spin_lock_bh(&priv->tx_list.lock); + while (!skb_queue_empty(&priv->tx_list)) { + + /* The "normal" dequeue function disables IRQs, but we only + * need serialization with bottom halves, so we use this. + */ + skb = __skb_dequeue(&priv->tx_list); + spin_unlock_bh(&priv->tx_list.lock); + + err = pisa_send(skb); + if (unlikely(err)) { + /* TODO update stats */ + } + + kfree_skb(skb); + + spin_lock_bh(&priv->tx_list.lock); + } + spin_unlock_bh(&priv->tx_list.lock); +} + static int pisa_init_netdev(struct net_device *dev) { struct pisa_priv *priv = netdev_priv(dev); char wq_name[PISA_NAME_LEN]; + skb_queue_head_init(&priv->tx_list); + INIT_WORK(&priv->tx_work, pisa_tx_wq_handler); + snprintf(wq_name, PISA_NAME_LEN, "%s_tx", dev->name); dprintk("creating own workqueue"); - priv->tx_wq = create_workqueue(dev->name); + priv->tx_wq = create_workqueue(wq_name); return (priv->tx_wq) ? 0 : -ENOMEM; } @@ -80,6 +133,15 @@ { struct pisa_priv *priv = netdev_priv(dev); + /* The _xmit calls are serialized, but we still need to sync + * with the working queues that run in process context. + * The "normal" call disables interrupts, but we don't need this + * and therefore we use the "unlocked" variant. + */ + spin_lock(&priv->tx_list.lock); + __skb_queue_tail(&priv->tx_list, skb); + spin_unlock(&priv->tx_list.lock); + schedule_work(&priv->tx_work); return NETDEV_TX_OK; @@ -96,7 +158,7 @@ { struct pisa_priv *priv = netdev_priv(dev); - dprintk("destroying %s", dev->name); + dprintk("destroying"); free_netdev(dev);