]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/vmxnet3/vmxnet3_ethtool.c
net-next: Add multiqueue support to vmxnet3 driver
[net-next-2.6.git] / drivers / net / vmxnet3 / vmxnet3_ethtool.c
index b79070bcc92efa592e9e8c1689d9e7061b8788c0..9ddaea636cfa4539ea055ad854f27ece7ca123be 100644 (file)
@@ -151,44 +151,42 @@ vmxnet3_get_stats(struct net_device *netdev)
        struct UPT1_TxStats *devTxStats;
        struct UPT1_RxStats *devRxStats;
        struct net_device_stats *net_stats = &netdev->stats;
+       int i;
 
        adapter = netdev_priv(netdev);
 
        /* Collect the dev stats into the shared area */
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
 
-       /* Assuming that we have a single queue device */
-       devTxStats = &adapter->tqd_start->stats;
-       devRxStats = &adapter->rqd_start->stats;
-
-       /* Get access to the driver stats per queue */
-       drvTxStats = &adapter->tx_queue.stats;
-       drvRxStats = &adapter->rx_queue.stats;
-
        memset(net_stats, 0, sizeof(*net_stats));
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               devTxStats = &adapter->tqd_start[i].stats;
+               drvTxStats = &adapter->tx_queue[i].stats;
+               net_stats->tx_packets += devTxStats->ucastPktsTxOK +
+                                       devTxStats->mcastPktsTxOK +
+                                       devTxStats->bcastPktsTxOK;
+               net_stats->tx_bytes += devTxStats->ucastBytesTxOK +
+                                     devTxStats->mcastBytesTxOK +
+                                     devTxStats->bcastBytesTxOK;
+               net_stats->tx_errors += devTxStats->pktsTxError;
+               net_stats->tx_dropped += drvTxStats->drop_total;
+       }
 
-       net_stats->rx_packets = devRxStats->ucastPktsRxOK +
-                               devRxStats->mcastPktsRxOK +
-                               devRxStats->bcastPktsRxOK;
-
-       net_stats->tx_packets = devTxStats->ucastPktsTxOK +
-                               devTxStats->mcastPktsTxOK +
-                               devTxStats->bcastPktsTxOK;
-
-       net_stats->rx_bytes = devRxStats->ucastBytesRxOK +
-                             devRxStats->mcastBytesRxOK +
-                             devRxStats->bcastBytesRxOK;
-
-       net_stats->tx_bytes = devTxStats->ucastBytesTxOK +
-                             devTxStats->mcastBytesTxOK +
-                             devTxStats->bcastBytesTxOK;
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               devRxStats = &adapter->rqd_start[i].stats;
+               drvRxStats = &adapter->rx_queue[i].stats;
+               net_stats->rx_packets += devRxStats->ucastPktsRxOK +
+                                       devRxStats->mcastPktsRxOK +
+                                       devRxStats->bcastPktsRxOK;
 
-       net_stats->rx_errors = devRxStats->pktsRxError;
-       net_stats->tx_errors = devTxStats->pktsTxError;
-       net_stats->rx_dropped = drvRxStats->drop_total;
-       net_stats->tx_dropped = drvTxStats->drop_total;
-       net_stats->multicast =  devRxStats->mcastPktsRxOK;
+               net_stats->rx_bytes += devRxStats->ucastBytesRxOK +
+                                     devRxStats->mcastBytesRxOK +
+                                     devRxStats->bcastBytesRxOK;
 
+               net_stats->rx_errors += devRxStats->pktsRxError;
+               net_stats->rx_dropped += drvRxStats->drop_total;
+               net_stats->multicast +=  devRxStats->mcastPktsRxOK;
+       }
        return net_stats;
 }
 
@@ -307,24 +305,26 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u8 *base;
        int i;
+       int j = 0;
 
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
 
        /* this does assume each counter is 64-bit wide */
+/* TODO change this for multiple queues */
 
-       base = (u8 *)&adapter->tqd_start->stats;
+       base = (u8 *)&adapter->tqd_start[j].stats;
        for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
                *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
 
-       base = (u8 *)&adapter->tx_queue.stats;
+       base = (u8 *)&adapter->tx_queue[j].stats;
        for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
                *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
 
-       base = (u8 *)&adapter->rqd_start->stats;
+       base = (u8 *)&adapter->rqd_start[j].stats;
        for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
                *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
 
-       base = (u8 *)&adapter->rx_queue.stats;
+       base = (u8 *)&adapter->rx_queue[j].stats;
        for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
                *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
 
@@ -339,6 +339,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        u32 *buf = p;
+       int i = 0;
 
        memset(p, 0, vmxnet3_get_regs_len(netdev));
 
@@ -347,28 +348,29 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
        /* Update vmxnet3_get_regs_len if we want to dump more registers */
 
        /* make each ring use multiple of 16 bytes */
-       buf[0] = adapter->tx_queue.tx_ring.next2fill;
-       buf[1] = adapter->tx_queue.tx_ring.next2comp;
-       buf[2] = adapter->tx_queue.tx_ring.gen;
+/* TODO change this for multiple queues */
+       buf[0] = adapter->tx_queue[i].tx_ring.next2fill;
+       buf[1] = adapter->tx_queue[i].tx_ring.next2comp;
+       buf[2] = adapter->tx_queue[i].tx_ring.gen;
        buf[3] = 0;
 
-       buf[4] = adapter->tx_queue.comp_ring.next2proc;
-       buf[5] = adapter->tx_queue.comp_ring.gen;
-       buf[6] = adapter->tx_queue.stopped;
+       buf[4] = adapter->tx_queue[i].comp_ring.next2proc;
+       buf[5] = adapter->tx_queue[i].comp_ring.gen;
+       buf[6] = adapter->tx_queue[i].stopped;
        buf[7] = 0;
 
-       buf[8] = adapter->rx_queue.rx_ring[0].next2fill;
-       buf[9] = adapter->rx_queue.rx_ring[0].next2comp;
-       buf[10] = adapter->rx_queue.rx_ring[0].gen;
+       buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
+       buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp;
+       buf[10] = adapter->rx_queue[i].rx_ring[0].gen;
        buf[11] = 0;
 
-       buf[12] = adapter->rx_queue.rx_ring[1].next2fill;
-       buf[13] = adapter->rx_queue.rx_ring[1].next2comp;
-       buf[14] = adapter->rx_queue.rx_ring[1].gen;
+       buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill;
+       buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
+       buf[14] = adapter->rx_queue[i].rx_ring[1].gen;
        buf[15] = 0;
 
-       buf[16] = adapter->rx_queue.comp_ring.next2proc;
-       buf[17] = adapter->rx_queue.comp_ring.gen;
+       buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
+       buf[17] = adapter->rx_queue[i].comp_ring.gen;
        buf[18] = 0;
        buf[19] = 0;
 }
@@ -435,8 +437,10 @@ vmxnet3_get_ringparam(struct net_device *netdev,
        param->rx_mini_max_pending = 0;
        param->rx_jumbo_max_pending = 0;
 
-       param->rx_pending = adapter->rx_queue.rx_ring[0].size;
-       param->tx_pending = adapter->tx_queue.tx_ring.size;
+       param->rx_pending = adapter->rx_queue[0].rx_ring[0].size *
+                           adapter->num_rx_queues;
+       param->tx_pending = adapter->tx_queue[0].tx_ring.size *
+                           adapter->num_tx_queues;
        param->rx_mini_pending = 0;
        param->rx_jumbo_pending = 0;
 }
@@ -480,8 +484,8 @@ vmxnet3_set_ringparam(struct net_device *netdev,
                                                           sz) != 0)
                return -EINVAL;
 
-       if (new_tx_ring_size == adapter->tx_queue.tx_ring.size &&
-                       new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) {
+       if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size &&
+           new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) {
                return 0;
        }
 
@@ -498,11 +502,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,
 
                /* recreate the rx queue and the tx queue based on the
                 * new sizes */
-               vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
-               vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+               vmxnet3_tq_destroy_all(adapter);
+               vmxnet3_rq_destroy_all(adapter);
 
                err = vmxnet3_create_queues(adapter, new_tx_ring_size,
                        new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
+
                if (err) {
                        /* failed, most likely because of OOM, try default
                         * size */
@@ -535,6 +540,65 @@ out:
 }
 
 
+static int
+vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
+                 void *rules)
+{
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       switch (info->cmd) {
+       case ETHTOOL_GRXRINGS:
+               info->data = adapter->num_rx_queues;
+               return 0;
+       }
+       return -EOPNOTSUPP;
+}
+
+
+static int
+vmxnet3_get_rss_indir(struct net_device *netdev,
+                     struct ethtool_rxfh_indir *p)
+{
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+       unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize);
+
+       p->size = rssConf->indTableSize;
+       while (n--)
+               p->ring_index[n] = rssConf->indTable[n];
+       return 0;
+
+}
+
+static int
+vmxnet3_set_rss_indir(struct net_device *netdev,
+                     const struct ethtool_rxfh_indir *p)
+{
+       unsigned int i;
+       struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+       struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+
+       if (p->size != rssConf->indTableSize)
+               return -EINVAL;
+       for (i = 0; i < rssConf->indTableSize; i++) {
+               /*
+                * Return with error code if any of the queue indices
+                * is out of range
+                */
+               if (p->ring_index[i] < 0 ||
+                   p->ring_index[i] >= adapter->num_rx_queues)
+                       return -EINVAL;
+       }
+
+       for (i = 0; i < rssConf->indTableSize; i++)
+               rssConf->indTable[i] = p->ring_index[i];
+
+       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+                              VMXNET3_CMD_UPDATE_RSSIDT);
+
+       return 0;
+
+}
+
 static struct ethtool_ops vmxnet3_ethtool_ops = {
        .get_settings      = vmxnet3_get_settings,
        .get_drvinfo       = vmxnet3_get_drvinfo,
@@ -558,6 +622,9 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
        .get_ethtool_stats = vmxnet3_get_ethtool_stats,
        .get_ringparam     = vmxnet3_get_ringparam,
        .set_ringparam     = vmxnet3_set_ringparam,
+       .get_rxnfc         = vmxnet3_get_rxnfc,
+       .get_rxfh_indir    = vmxnet3_get_rss_indir,
+       .set_rxfh_indir    = vmxnet3_set_rss_indir,
 };
 
 void vmxnet3_set_ethtool_ops(struct net_device *netdev)