Multiqueue netwrok device support implementation.
- Added a loadable parameter "multiq" to enable/disable multiqueue support,
  by default it is disabled.
- skb->queue_mapping is not used for queue/fifo selection. FIFO iselection is
  based on IP-TOS value, 0x0-0xF TOS values are mapped to 8 FIFOs.
- Added per FIFO flags FIFO_QUEUE_START and FIFO_QUEUE_STOP. Check this flag
  for starting and stopping netif queue and update the flags accordingly.
- In tx_intr_handler added a check to ensure that we have free TXDs before wak-
  ing up the queue.
- Added helper functions for queue manipulation(start/stop/wakeup) to invoke
  appropriate netif_ functions.
- Calling netif_start/stop for link up/down case respectively.

Signed-off-by: Surjit Reang <[EMAIL PROTECTED]>
Signed-off-by: Sreenivasa Honnur <[EMAIL PROTECTED]>
---
diff -Nurp orig/drivers/net/s2io.c patch1/drivers/net/s2io.c
--- orig/drivers/net/s2io.c     2007-12-21 12:10:29.000000000 -0800
+++ patch1/drivers/net/s2io.c   2007-12-21 13:36:59.000000000 -0800
@@ -50,6 +50,8 @@
  *                 Possible values '1' for enable , '0' for disable.
  *                 Default is '2' - which means disable in promisc mode
  *                 and enable in non-promiscuous mode.
+ * multiq: This parameter used to enable/disable MULTIQUEUE support.          *
+ *      Possible values '1' for enable and '0' for disable. Default is '0'    *
  ************************************************************************/
 
 #include <linux/module.h>
@@ -84,7 +86,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.15-2"
+#define DRV_VERSION "2.0.26.16"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -93,6 +95,12 @@ static char s2io_driver_version[] = DRV_
 static int rxd_size[2] = {32,48};
 static int rxd_count[2] = {127,85};
 
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+/* mapping from tos value to fifo number
+ * 0x0-0xF TOS values are mapped to 8 FIFOs */
+static int tos_map[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
+#endif
+
 static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
 {
        int ret;
@@ -458,6 +466,7 @@ MODULE_VERSION(DRV_VERSION);
 /* Module Loadable parameters. */
 S2IO_PARM_INT(tx_fifo_num, 1);
 S2IO_PARM_INT(rx_ring_num, 1);
+S2IO_PARM_INT(multiq, 0);
 
 
 S2IO_PARM_INT(rx_ring_mode, 1);
@@ -533,6 +542,101 @@ static struct pci_driver s2io_driver = {
 /* A simplifier macro used both by init and free shared_mem Fns(). */
 #define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
 
+/* netqueue manipulation helper functions */
+static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp)
+{
+       int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (sp->config.multiq) {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       netif_stop_subqueue(sp->dev, i);
+       } else
+#endif
+       {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP;
+               netif_stop_queue(sp->dev);
+       }
+}
+
+static inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (sp->config.multiq)
+               netif_stop_subqueue(sp->dev, fifo_no);
+       else
+#endif
+       {
+               sp->mac_control.fifos[fifo_no].queue_state =
+                       FIFO_QUEUE_STOP;
+               netif_stop_queue(sp->dev);
+       }
+}
+
+static inline void s2io_start_all_tx_queue(struct s2io_nic *sp)
+{
+       int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (sp->config.multiq) {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       netif_start_subqueue(sp->dev, i);
+       } else
+#endif
+       {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+               netif_start_queue(sp->dev);
+       }
+}
+
+static inline void s2io_start_tx_queue(struct s2io_nic *sp, int fifo_no)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (multiq)
+               netif_start_subqueue(sp->dev, fifo_no);
+       else
+#endif
+       {
+               sp->mac_control.fifos[fifo_no].queue_state =
+                       FIFO_QUEUE_START;
+               netif_start_queue(sp->dev);
+       }
+}
+
+static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp)
+{
+       int i;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (sp->config.multiq) {
+                       for (i = 0; i < sp->config.tx_fifo_num; i++)
+                               netif_wake_subqueue(sp->dev, i);
+       } else
+#endif
+       {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
+               netif_wake_queue(sp->dev);
+       }
+}
+
+static inline void s2io_wake_tx_queue(
+       struct fifo_info *fifo, int cnt, u8 multiq)
+{
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (multiq) {
+               if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no))
+                       netif_wake_subqueue(fifo->dev, fifo->fifo_no);
+       } else
+#endif
+       if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) {
+               if (netif_queue_stopped(fifo->dev)) {
+                       fifo->queue_state = FIFO_QUEUE_START;
+                       netif_wake_queue(fifo->dev);
+               }
+       }
+}
+
 /**
  * init_shared_mem - Allocation and Initialization of Memory
  * @nic: Device private variable.
@@ -614,6 +718,7 @@ static int init_shared_mem(struct s2io_n
                mac_control->fifos[i].fifo_no = i;
                mac_control->fifos[i].nic = nic;
                mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 2;
+               mac_control->fifos[i].dev = dev;
 
                for (j = 0; j < page_num; j++) {
                        int k = 0;
@@ -2975,10 +3080,10 @@ static void rx_intr_handler(struct ring_
 static void tx_intr_handler(struct fifo_info *fifo_data)
 {
        struct s2io_nic *nic = fifo_data->nic;
-       struct net_device *dev = (struct net_device *) nic->dev;
        struct tx_curr_get_info get_info, put_info;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        struct TxD *txdlp;
+       int pkt_cnt = 0;
        unsigned long flags = 0;
        u8 err_mask;
 
@@ -3040,6 +3145,8 @@ static void tx_intr_handler(struct fifo_
                        return;
                }
 
+               pkt_cnt++;
+
                /* Updating the statistics block */
                nic->stats.tx_bytes += skb->len;
                nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
@@ -3054,8 +3161,7 @@ static void tx_intr_handler(struct fifo_
                    get_info.offset;
        }
 
-       if (netif_queue_stopped(dev))
-               netif_wake_queue(dev);
+       s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq);
 
        spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
 }
@@ -3939,7 +4045,7 @@ static int s2io_open(struct net_device *
                goto hw_init_failed;
        }
 
-       netif_start_queue(dev);
+       s2io_start_all_tx_queue(sp);
        return 0;
 
 hw_init_failed:
@@ -3985,7 +4091,7 @@ static int s2io_close(struct net_device 
        if (!is_s2io_card_up(sp))
                return 0;
 
-       netif_stop_queue(dev);
+       s2io_stop_all_tx_queue(sp);
 
        /* delete all populated mac entries */
        for (offset = 1; offset < config->max_mc_addr; offset++) {
@@ -4055,9 +4161,34 @@ static int s2io_xmit(struct sk_buff *skb
                vlan_priority = vlan_tag >> 13;
                queue = config->fifo_mapping[vlan_priority];
        }
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       else if (skb->protocol == htons(ETH_P_IP) && sp->config.multiq) {
+               struct iphdr *ip;
+               ip = ip_hdr(skb);
+
+               /* get fifo number based on TOS value */
+               queue = tos_map[IPTOS_TOS(ip->tos) >> 1];
+       }
+#endif
 
        fifo = &mac_control->fifos[queue];
        spin_lock_irqsave(&fifo->tx_lock, flags);
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (sp->config.multiq) {
+               if (__netif_subqueue_stopped(dev, fifo->fifo_no)) {
+                       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+                       return NETDEV_TX_BUSY;
+               }
+       } else
+#endif
+       if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) {
+               if (netif_queue_stopped(dev)) {
+                       spin_unlock_irqrestore(&fifo->tx_lock, flags);
+                       return NETDEV_TX_BUSY;
+               }
+       }
+
        put_off = (u16) fifo->tx_curr_put_info.offset;
        get_off = (u16) fifo->tx_curr_get_info.offset;
        txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr;
@@ -4067,7 +4198,7 @@ static int s2io_xmit(struct sk_buff *skb
        if (txdp->Host_Control ||
                   ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
                DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
-               netif_stop_queue(dev);
+               s2io_stop_tx_queue(sp, fifo->fifo_no);
                dev_kfree_skb(skb);
                spin_unlock_irqrestore(&fifo->tx_lock, flags);
                return 0;
@@ -4173,7 +4304,7 @@ static int s2io_xmit(struct sk_buff *skb
                DBG_PRINT(TX_DBG,
                          "No free TxDs for xmit, Put: 0x%x Get:0x%x\n",
                          put_off, get_off);
-               netif_stop_queue(dev);
+               s2io_stop_tx_queue(sp, fifo->fifo_no);
        }
        mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
        dev->trans_start = jiffies;
@@ -4182,7 +4313,7 @@ static int s2io_xmit(struct sk_buff *skb
        return 0;
 pci_map_failed:
        stats->pci_map_fail_cnt++;
-       netif_stop_queue(dev);
+       s2io_stop_tx_queue(sp, fifo->fifo_no);
        stats->mem_freed += skb->truesize;
        dev_kfree_skb(skb);
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
@@ -4594,7 +4725,7 @@ static void s2io_handle_errors(void * de
        return;
 
 reset:
-       netif_stop_queue(dev);
+       s2io_stop_all_tx_queue(sp);
        schedule_work(&sp->rst_timer_task);
        sw_stat->soft_reset_cnt++;
        return;
@@ -6581,16 +6712,16 @@ static int s2io_change_mtu(struct net_de
 
        dev->mtu = new_mtu;
        if (netif_running(dev)) {
+               s2io_stop_all_tx_queue(sp);
                s2io_card_down(sp);
-               netif_stop_queue(dev);
+
                ret = s2io_card_up(sp);
                if (ret) {
                        DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
                                  __FUNCTION__);
                        return ret;
                }
-               if (netif_queue_stopped(dev))
-                       netif_wake_queue(dev);
+               s2io_wake_all_tx_queue(sp);
        } else { /* Device is down */
                struct XENA_dev_config __iomem *bar0 = sp->bar0;
                u64 val64 = new_mtu;
@@ -6698,7 +6829,7 @@ static void s2io_set_link(struct work_st
                        } else {
                                DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
                                DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
-                               netif_stop_queue(dev);
+                               s2io_stop_all_tx_queue(nic);
                        }
                }
                val64 = readq(&bar0->adapter_control);
@@ -7177,7 +7308,8 @@ static void s2io_restart_nic(struct work
                DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
                          dev->name);
        }
-       netif_wake_queue(dev);
+       s2io_wake_all_tx_queue(sp);
+
        DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
                  dev->name);
 out_unlock:
@@ -7456,6 +7588,7 @@ static void s2io_link(struct s2io_nic * 
                init_tti(sp, link);
                if (link == LINK_DOWN) {
                        DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
+                       s2io_stop_all_tx_queue(sp);
                        netif_carrier_off(dev);
                        if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
                        sp->mac_control.stats_info->sw_stat.link_up_time =
@@ -7468,6 +7601,7 @@ static void s2io_link(struct s2io_nic * 
                                jiffies - sp->start_time;
                        sp->mac_control.stats_info->sw_stat.link_up_cnt++;
                        netif_carrier_on(dev);
+                       s2io_wake_all_tx_queue(sp);
                }
        }
        sp->last_link_state = link;
@@ -7504,7 +7638,8 @@ static void s2io_init_pci(struct s2io_ni
        pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
 }
 
-static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
+static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
+       u8 *dev_multiq)
 {
        if ((tx_fifo_num > MAX_TX_FIFOS) ||
                (tx_fifo_num < FIFO_DEFAULT_NUM)) {
@@ -7518,6 +7653,19 @@ static int s2io_verify_parm(struct pci_d
                DBG_PRINT(ERR_DBG, "tx fifos\n");
        }
 
+#ifndef CONFIG_NETDEVICES_MULTIQUEUE
+       if (multiq) {
+               DBG_PRINT(ERR_DBG, "s2io: Multiqueue support not enabled\n");
+               multiq = 0;
+       }
+#endif
+
+       /* if multiqueue is enabled configure all fifos */
+       if (multiq) {
+               tx_fifo_num = MAX_TX_FIFOS;
+               *dev_multiq = multiq;
+       }
+
        if ( rx_ring_num > 8) {
                DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
                         "supported\n");
@@ -7609,9 +7757,11 @@ s2io_init_nic(struct pci_dev *pdev, cons
        struct config_param *config;
        int mode;
        u8 dev_intr_type = intr_type;
+       u8 dev_multiq = 0;
        DECLARE_MAC_BUF(mac);
 
-       if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
+       ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq);
+       if (ret)
                return ret;
 
        if ((ret = pci_enable_device(pdev))) {
@@ -7643,7 +7793,13 @@ s2io_init_nic(struct pci_dev *pdev, cons
                return -ENODEV;
        }
 
-       dev = alloc_etherdev(sizeof(struct s2io_nic));
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (dev_multiq)
+               dev = alloc_etherdev_mq(sizeof(struct s2io_nic), MAX_TX_FIFOS);
+       else
+#endif
+               dev = alloc_etherdev(sizeof(struct s2io_nic));
+
        if (dev == NULL) {
                DBG_PRINT(ERR_DBG, "Device allocation failed\n");
                pci_disable_device(pdev);
@@ -7694,6 +7850,7 @@ s2io_init_nic(struct pci_dev *pdev, cons
 
        /* Tx side parameters. */
        config->tx_fifo_num = tx_fifo_num;
+       config->multiq = dev_multiq;
        for (i = 0; i < MAX_TX_FIFOS; i++) {
                config->tx_cfg[i].fifo_len = tx_fifo_len[i];
                config->tx_cfg[i].fifo_priority = i;
@@ -7807,6 +7964,11 @@ s2io_init_nic(struct pci_dev *pdev, cons
                dev->features |= NETIF_F_HW_CSUM;
        }
 
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       if (config->multiq)
+               dev->features |= NETIF_F_MULTI_QUEUE;
+#endif
+
        dev->tx_timeout = &s2io_tx_watchdog;
        dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
        INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
@@ -7963,6 +8125,16 @@ s2io_init_nic(struct pci_dev *pdev, cons
                    DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
                    break;
        }
+
+       if (sp->config.multiq) {
+               for (i = 0; i < sp->config.tx_fifo_num; i++)
+                       mac_control->fifos[i].multiq = config->multiq;
+               DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
+                       dev->name);
+       } else
+               DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
+                       dev->name);
+
        if (sp->lro)
                DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
                          dev->name);
diff -Nurp orig/drivers/net/s2io.h patch1/drivers/net/s2io.h
--- orig/drivers/net/s2io.h     2007-12-21 12:10:29.000000000 -0800
+++ patch1/drivers/net/s2io.h   2007-12-21 13:36:28.000000000 -0800
@@ -464,6 +464,7 @@ struct config_param {
        int max_mc_addr;        /* xena=64 herc=256 */
        int max_mac_addr;       /* xena=16 herc=64 */
        int mc_start_offset;    /* xena=16 herc=64 */
+       u8 multiq;
 };
 
 /* Structure representing MAC Addrs */
@@ -721,6 +722,17 @@ struct fifo_info {
         */
        struct tx_curr_get_info tx_curr_get_info;
 
+
+#define FIFO_QUEUE_START 0
+#define FIFO_QUEUE_STOP 1
+       int queue_state;
+
+       /* copy of sp->dev pointer */
+       struct net_device *dev;
+
+       /* copy of multiq status */
+       u8 multiq;
+
        /* Per fifo lock */
        spinlock_t tx_lock;
 
@@ -756,7 +768,7 @@ struct mac_info {
        dma_addr_t stats_mem_phy;       /* Physical address of the stat block */
        u32 stats_mem_sz;
        struct stat_block *stats_info;  /* Logical address of the stat block */
-};
+} ____cacheline_aligned;
 
 /* structure representing the user defined MAC addresses */
 struct usr_addr {

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to