diff options
author | Yevgeny Petrilin <yevgenyp@mellanox.co.il> | 2009-06-01 19:24:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-02 05:29:06 -0400 |
commit | f813cad836ab14b764cfe76f42a3b50bb9677b30 (patch) | |
tree | ccaafb7bcaa72e737fb8939e0c556f2466bb0d7d /drivers/net/mlx4 | |
parent | 3db36fb2c88d68ee28d20845d5bb805ea9a7f6d8 (diff) |
mlx4_en: multiqueue support
By default the driver opens 8 TX queues (defined by MLX4_EN_NUM_TX_RINGS).
If the driver is configured to support Per Priority Flow Control, we open
8 additional TX rings.
dev->real_num_tx_queues is always set to be MLX4_EN_NUM_TX_RINGS.
The mlx4_en_select_queue() function uses standard hashing (skb_tx_hash)
in case that PPFC is not supported or the skb contain a vlan tag,
otherwise the queue is selected according to vlan priority.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/mlx4')
-rw-r--r-- | drivers/net/mlx4/en_main.c | 9 | ||||
-rw-r--r-- | drivers/net/mlx4/en_netdev.c | 7 | ||||
-rw-r--r-- | drivers/net/mlx4/en_tx.c | 74 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4_en.h | 9 |
4 files changed, 28 insertions, 71 deletions
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index b510000d8391..9ed4a158f895 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c | |||
@@ -93,13 +93,8 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) | |||
93 | params->prof[i].tx_ppp = pfctx; | 93 | params->prof[i].tx_ppp = pfctx; |
94 | params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; | 94 | params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; |
95 | params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; | 95 | params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; |
96 | } | 96 | params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + |
97 | if (pfcrx || pfctx) { | 97 | (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; |
98 | params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; | ||
99 | params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; | ||
100 | } else { | ||
101 | params->prof[1].tx_ring_num = 1; | ||
102 | params->prof[2].tx_ring_num = 1; | ||
103 | } | 98 | } |
104 | 99 | ||
105 | return 0; | 100 | return 0; |
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 16a634ffbcdf..37e4d30cbf04 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c | |||
@@ -934,6 +934,7 @@ static const struct net_device_ops mlx4_netdev_ops = { | |||
934 | .ndo_open = mlx4_en_open, | 934 | .ndo_open = mlx4_en_open, |
935 | .ndo_stop = mlx4_en_close, | 935 | .ndo_stop = mlx4_en_close, |
936 | .ndo_start_xmit = mlx4_en_xmit, | 936 | .ndo_start_xmit = mlx4_en_xmit, |
937 | .ndo_select_queue = mlx4_en_select_queue, | ||
937 | .ndo_get_stats = mlx4_en_get_stats, | 938 | .ndo_get_stats = mlx4_en_get_stats, |
938 | .ndo_set_multicast_list = mlx4_en_set_multicast, | 939 | .ndo_set_multicast_list = mlx4_en_set_multicast, |
939 | .ndo_set_mac_address = mlx4_en_set_mac, | 940 | .ndo_set_mac_address = mlx4_en_set_mac, |
@@ -956,7 +957,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
956 | int i; | 957 | int i; |
957 | int err; | 958 | int err; |
958 | 959 | ||
959 | dev = alloc_etherdev(sizeof(struct mlx4_en_priv)); | 960 | dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num); |
960 | if (dev == NULL) { | 961 | if (dev == NULL) { |
961 | mlx4_err(mdev, "Net device allocation failed\n"); | 962 | mlx4_err(mdev, "Net device allocation failed\n"); |
962 | return -ENOMEM; | 963 | return -ENOMEM; |
@@ -1018,14 +1019,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1018 | } | 1019 | } |
1019 | priv->allocated = 1; | 1020 | priv->allocated = 1; |
1020 | 1021 | ||
1021 | /* Populate Tx priority mappings */ | ||
1022 | mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num); | ||
1023 | |||
1024 | /* | 1022 | /* |
1025 | * Initialize netdev entry points | 1023 | * Initialize netdev entry points |
1026 | */ | 1024 | */ |
1027 | dev->netdev_ops = &mlx4_netdev_ops; | 1025 | dev->netdev_ops = &mlx4_netdev_ops; |
1028 | dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; | 1026 | dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; |
1027 | dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS; | ||
1029 | 1028 | ||
1030 | SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); | 1029 | SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); |
1031 | 1030 | ||
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 95703f90c1b9..3719d1ac3950 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c | |||
@@ -297,34 +297,6 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) | |||
297 | return cnt; | 297 | return cnt; |
298 | } | 298 | } |
299 | 299 | ||
300 | void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num) | ||
301 | { | ||
302 | int block = 8 / ring_num; | ||
303 | int extra = 8 - (block * ring_num); | ||
304 | int num = 0; | ||
305 | u16 ring = 1; | ||
306 | int prio; | ||
307 | |||
308 | if (ring_num == 1) { | ||
309 | for (prio = 0; prio < 8; prio++) | ||
310 | prio_map[prio] = 0; | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | for (prio = 0; prio < 8; prio++) { | ||
315 | if (extra && (num == block + 1)) { | ||
316 | ring++; | ||
317 | num = 0; | ||
318 | extra--; | ||
319 | } else if (!extra && (num == block)) { | ||
320 | ring++; | ||
321 | num = 0; | ||
322 | } | ||
323 | prio_map[prio] = ring; | ||
324 | en_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); | ||
325 | num++; | ||
326 | } | ||
327 | } | ||
328 | 300 | ||
329 | static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) | 301 | static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) |
330 | { | 302 | { |
@@ -386,18 +358,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) | |||
386 | if (unlikely(ring->blocked)) { | 358 | if (unlikely(ring->blocked)) { |
387 | if ((u32) (ring->prod - ring->cons) <= | 359 | if ((u32) (ring->prod - ring->cons) <= |
388 | ring->size - HEADROOM - MAX_DESC_TXBBS) { | 360 | ring->size - HEADROOM - MAX_DESC_TXBBS) { |
389 | |||
390 | /* TODO: support multiqueue netdevs. Currently, we block | ||
391 | * when *any* ring is full. Note that: | ||
392 | * - 2 Tx rings can unblock at the same time and call | ||
393 | * netif_wake_queue(), which is OK since this | ||
394 | * operation is idempotent. | ||
395 | * - We might wake the queue just after another ring | ||
396 | * stopped it. This is no big deal because the next | ||
397 | * transmission on that ring would stop the queue. | ||
398 | */ | ||
399 | ring->blocked = 0; | 361 | ring->blocked = 0; |
400 | netif_wake_queue(dev); | 362 | netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring)); |
401 | priv->port_stats.wake_queue++; | 363 | priv->port_stats.wake_queue++; |
402 | } | 364 | } |
403 | } | 365 | } |
@@ -616,21 +578,20 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk | |||
616 | tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; | 578 | tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; |
617 | } | 579 | } |
618 | 580 | ||
619 | static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb, | 581 | u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) |
620 | u16 *vlan_tag) | ||
621 | { | 582 | { |
622 | int tx_ind; | 583 | struct mlx4_en_priv *priv = netdev_priv(dev); |
584 | u16 vlan_tag = 0; | ||
623 | 585 | ||
624 | /* Obtain VLAN information if present */ | 586 | /* If we support per priority flow control and the packet contains |
625 | if (priv->vlgrp && vlan_tx_tag_present(skb)) { | 587 | * a vlan tag, send the packet to the TX ring assigned to that priority |
626 | *vlan_tag = vlan_tx_tag_get(skb); | 588 | */ |
627 | /* Set the Tx ring to use according to vlan priority */ | 589 | if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) { |
628 | tx_ind = priv->tx_prio_map[*vlan_tag >> 13]; | 590 | vlan_tag = vlan_tx_tag_get(skb); |
629 | } else { | 591 | return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13); |
630 | *vlan_tag = 0; | ||
631 | tx_ind = 0; | ||
632 | } | 592 | } |
633 | return tx_ind; | 593 | |
594 | return skb_tx_hash(dev, skb); | ||
634 | } | 595 | } |
635 | 596 | ||
636 | int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | 597 | int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) |
@@ -650,7 +611,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
650 | dma_addr_t dma; | 611 | dma_addr_t dma; |
651 | u32 index; | 612 | u32 index; |
652 | __be32 op_own; | 613 | __be32 op_own; |
653 | u16 vlan_tag; | 614 | u16 vlan_tag = 0; |
654 | int i; | 615 | int i; |
655 | int lso_header_size; | 616 | int lso_header_size; |
656 | void *fragptr; | 617 | void *fragptr; |
@@ -673,15 +634,16 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
673 | return NETDEV_TX_OK; | 634 | return NETDEV_TX_OK; |
674 | } | 635 | } |
675 | 636 | ||
676 | tx_ind = get_vlan_info(priv, skb, &vlan_tag); | 637 | tx_ind = skb->queue_mapping; |
677 | ring = &priv->tx_ring[tx_ind]; | 638 | ring = &priv->tx_ring[tx_ind]; |
639 | if (priv->vlgrp && vlan_tx_tag_present(skb)) | ||
640 | vlan_tag = vlan_tx_tag_get(skb); | ||
678 | 641 | ||
679 | /* Check available TXBBs And 2K spare for prefetch */ | 642 | /* Check available TXBBs And 2K spare for prefetch */ |
680 | if (unlikely(((int)(ring->prod - ring->cons)) > | 643 | if (unlikely(((int)(ring->prod - ring->cons)) > |
681 | ring->size - HEADROOM - MAX_DESC_TXBBS)) { | 644 | ring->size - HEADROOM - MAX_DESC_TXBBS)) { |
682 | /* every full Tx ring stops queue. | 645 | /* every full Tx ring stops queue */ |
683 | * TODO: implement multi-queue support (per-queue stop) */ | 646 | netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind)); |
684 | netif_stop_queue(dev); | ||
685 | ring->blocked = 1; | 647 | ring->blocked = 1; |
686 | priv->port_stats.queue_stopped++; | 648 | priv->port_stats.queue_stopped++; |
687 | 649 | ||
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index fcbfcfc11568..4de8db00809d 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h | |||
@@ -139,8 +139,10 @@ enum { | |||
139 | #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) | 139 | #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) |
140 | #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) | 140 | #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) |
141 | 141 | ||
142 | #define MLX4_EN_TX_RING_NUM 9 | 142 | #define MLX4_EN_SMALL_PKT_SIZE 64 |
143 | #define MLX4_EN_DEF_TX_RING_SIZE 1024 | 143 | #define MLX4_EN_NUM_TX_RINGS 8 |
144 | #define MLX4_EN_NUM_PPP_RINGS 8 | ||
145 | #define MLX4_EN_DEF_TX_RING_SIZE 512 | ||
144 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 | 146 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 |
145 | 147 | ||
146 | /* Target number of packets to coalesce with interrupt moderation */ | 148 | /* Target number of packets to coalesce with interrupt moderation */ |
@@ -478,7 +480,6 @@ struct mlx4_en_priv { | |||
478 | int base_qpn; | 480 | int base_qpn; |
479 | 481 | ||
480 | struct mlx4_en_rss_map rss_map; | 482 | struct mlx4_en_rss_map rss_map; |
481 | u16 tx_prio_map[8]; | ||
482 | u32 flags; | 483 | u32 flags; |
483 | #define MLX4_EN_FLAG_PROMISC 0x1 | 484 | #define MLX4_EN_FLAG_PROMISC 0x1 |
484 | u32 tx_ring_num; | 485 | u32 tx_ring_num; |
@@ -526,6 +527,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); | |||
526 | 527 | ||
527 | void mlx4_en_poll_tx_cq(unsigned long data); | 528 | void mlx4_en_poll_tx_cq(unsigned long data); |
528 | void mlx4_en_tx_irq(struct mlx4_cq *mcq); | 529 | void mlx4_en_tx_irq(struct mlx4_cq *mcq); |
530 | u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); | ||
529 | int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); | 531 | int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); |
530 | 532 | ||
531 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, | 533 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, |
@@ -560,7 +562,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev); | |||
560 | void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, | 562 | void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, |
561 | struct mlx4_en_rss_map *rss_map, | 563 | struct mlx4_en_rss_map *rss_map, |
562 | int num_entries, int num_rings); | 564 | int num_entries, int num_rings); |
563 | void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num); | ||
564 | int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); | 565 | int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); |
565 | void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); | 566 | void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); |
566 | int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); | 567 | int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); |