diff options
author | Yan Burman <yanb@mellanox.com> | 2013-02-06 21:25:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-07 23:26:13 -0500 |
commit | c07cb4b0ab78f279ea94c3b4661cad86eb02a5d9 (patch) | |
tree | 7c2eda4433a461a036410586a3ca31d27d46fb6a /drivers/net/ethernet/mellanox/mlx4 | |
parent | 90bbb74af68b3255bc298731f8b60d5668877306 (diff) |
net/mlx4_en: Manage hash of MAC addresses per port
As a preparation step for supporting multiple unicast addresses, store MAC addresses in hash table.
Remove the radix tree for MAC addresses per QP, as it's not in use.
Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 87 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_rx.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 7 |
3 files changed, 79 insertions, 38 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 72a3fe50d429..8eb24ee598e2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c | |||
@@ -545,13 +545,10 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv) | |||
545 | memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac)); | 545 | memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac)); |
546 | entry->reg_id = reg_id; | 546 | entry->reg_id = reg_id; |
547 | 547 | ||
548 | err = radix_tree_insert(&priv->mac_tree, *qpn, entry); | 548 | hlist_add_head_rcu(&entry->hlist, |
549 | if (err) | 549 | &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); |
550 | goto insert_err; | ||
551 | return 0; | ||
552 | 550 | ||
553 | insert_err: | 551 | return 0; |
554 | kfree(entry); | ||
555 | 552 | ||
556 | alloc_err: | 553 | alloc_err: |
557 | mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id); | 554 | mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id); |
@@ -568,7 +565,6 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv) | |||
568 | { | 565 | { |
569 | struct mlx4_en_dev *mdev = priv->mdev; | 566 | struct mlx4_en_dev *mdev = priv->mdev; |
570 | struct mlx4_dev *dev = mdev->dev; | 567 | struct mlx4_dev *dev = mdev->dev; |
571 | struct mlx4_mac_entry *entry; | ||
572 | int qpn = priv->base_qpn; | 568 | int qpn = priv->base_qpn; |
573 | u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); | 569 | u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); |
574 | 570 | ||
@@ -577,15 +573,26 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv) | |||
577 | mlx4_unregister_mac(dev, priv->port, mac); | 573 | mlx4_unregister_mac(dev, priv->port, mac); |
578 | 574 | ||
579 | if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { | 575 | if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { |
580 | entry = radix_tree_lookup(&priv->mac_tree, qpn); | 576 | struct mlx4_mac_entry *entry; |
581 | if (entry) { | 577 | struct hlist_node *n, *tmp; |
582 | en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n", | 578 | struct hlist_head *bucket; |
583 | priv->port, entry->mac, qpn); | 579 | unsigned int mac_hash; |
584 | mlx4_en_uc_steer_release(priv, entry->mac, | 580 | |
585 | qpn, entry->reg_id); | 581 | mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX]; |
586 | mlx4_qp_release_range(dev, qpn, 1); | 582 | bucket = &priv->mac_hash[mac_hash]; |
587 | radix_tree_delete(&priv->mac_tree, qpn); | 583 | hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) { |
588 | kfree(entry); | 584 | if (ether_addr_equal_64bits(entry->mac, |
585 | priv->dev->dev_addr)) { | ||
586 | en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n", | ||
587 | priv->port, priv->dev->dev_addr, qpn); | ||
588 | mlx4_en_uc_steer_release(priv, entry->mac, | ||
589 | qpn, entry->reg_id); | ||
590 | mlx4_qp_release_range(dev, qpn, 1); | ||
591 | |||
592 | hlist_del_rcu(&entry->hlist); | ||
593 | kfree_rcu(entry, rcu); | ||
594 | break; | ||
595 | } | ||
589 | } | 596 | } |
590 | } | 597 | } |
591 | } | 598 | } |
@@ -595,26 +602,38 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, | |||
595 | { | 602 | { |
596 | struct mlx4_en_dev *mdev = priv->mdev; | 603 | struct mlx4_en_dev *mdev = priv->mdev; |
597 | struct mlx4_dev *dev = mdev->dev; | 604 | struct mlx4_dev *dev = mdev->dev; |
598 | struct mlx4_mac_entry *entry; | ||
599 | int err = 0; | 605 | int err = 0; |
600 | u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac); | 606 | u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac); |
601 | 607 | ||
602 | if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { | 608 | if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { |
603 | u64 prev_mac_u64; | 609 | struct hlist_head *bucket; |
604 | 610 | unsigned int mac_hash; | |
605 | entry = radix_tree_lookup(&priv->mac_tree, qpn); | 611 | struct mlx4_mac_entry *entry; |
606 | if (!entry) | 612 | struct hlist_node *n, *tmp; |
607 | return -EINVAL; | 613 | u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac); |
608 | prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac); | 614 | |
609 | mlx4_en_uc_steer_release(priv, entry->mac, | 615 | bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]]; |
610 | qpn, entry->reg_id); | 616 | hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) { |
611 | mlx4_unregister_mac(dev, priv->port, prev_mac_u64); | 617 | if (ether_addr_equal_64bits(entry->mac, prev_mac)) { |
612 | memcpy(entry->mac, new_mac, ETH_ALEN); | 618 | mlx4_en_uc_steer_release(priv, entry->mac, |
613 | entry->reg_id = 0; | 619 | qpn, entry->reg_id); |
614 | mlx4_register_mac(dev, priv->port, new_mac_u64); | 620 | mlx4_unregister_mac(dev, priv->port, |
615 | err = mlx4_en_uc_steer_add(priv, new_mac, | 621 | prev_mac_u64); |
616 | &qpn, &entry->reg_id); | 622 | hlist_del_rcu(&entry->hlist); |
617 | return err; | 623 | synchronize_rcu(); |
624 | memcpy(entry->mac, new_mac, ETH_ALEN); | ||
625 | entry->reg_id = 0; | ||
626 | mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX]; | ||
627 | hlist_add_head_rcu(&entry->hlist, | ||
628 | &priv->mac_hash[mac_hash]); | ||
629 | mlx4_register_mac(dev, priv->port, new_mac_u64); | ||
630 | err = mlx4_en_uc_steer_add(priv, new_mac, | ||
631 | &qpn, | ||
632 | &entry->reg_id); | ||
633 | return err; | ||
634 | } | ||
635 | } | ||
636 | return -EINVAL; | ||
618 | } | 637 | } |
619 | 638 | ||
620 | return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); | 639 | return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); |
@@ -1816,6 +1835,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1816 | { | 1835 | { |
1817 | struct net_device *dev; | 1836 | struct net_device *dev; |
1818 | struct mlx4_en_priv *priv; | 1837 | struct mlx4_en_priv *priv; |
1838 | int i; | ||
1819 | int err; | 1839 | int err; |
1820 | 1840 | ||
1821 | dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), | 1841 | dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), |
@@ -1874,7 +1894,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1874 | dev->dcbnl_ops = &mlx4_en_dcbnl_ops; | 1894 | dev->dcbnl_ops = &mlx4_en_dcbnl_ops; |
1875 | #endif | 1895 | #endif |
1876 | 1896 | ||
1877 | INIT_RADIX_TREE(&priv->mac_tree, GFP_KERNEL); | 1897 | for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) |
1898 | INIT_HLIST_HEAD(&priv->mac_hash[i]); | ||
1878 | 1899 | ||
1879 | /* Query for default mac and max mtu */ | 1900 | /* Query for default mac and max mtu */ |
1880 | priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; | 1901 | priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 2e7f5bb94e1f..91bb8e157253 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c | |||
@@ -615,10 +615,25 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
615 | ethh = (struct ethhdr *)(page_address(frags[0].page) + | 615 | ethh = (struct ethhdr *)(page_address(frags[0].page) + |
616 | frags[0].offset); | 616 | frags[0].offset); |
617 | 617 | ||
618 | /* Drop the packet, since HW loopback-ed it */ | 618 | if (is_multicast_ether_addr(ethh->h_dest)) { |
619 | if (ether_addr_equal_64bits(dev->dev_addr, | 619 | struct mlx4_mac_entry *entry; |
620 | ethh->h_source)) | 620 | struct hlist_node *n; |
621 | goto next; | 621 | struct hlist_head *bucket; |
622 | unsigned int mac_hash; | ||
623 | |||
624 | /* Drop the packet, since HW loopback-ed it */ | ||
625 | mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX]; | ||
626 | bucket = &priv->mac_hash[mac_hash]; | ||
627 | rcu_read_lock(); | ||
628 | hlist_for_each_entry_rcu(entry, n, bucket, hlist) { | ||
629 | if (ether_addr_equal_64bits(entry->mac, | ||
630 | ethh->h_source)) { | ||
631 | rcu_read_unlock(); | ||
632 | goto next; | ||
633 | } | ||
634 | } | ||
635 | rcu_read_unlock(); | ||
636 | } | ||
622 | } | 637 | } |
623 | 638 | ||
624 | /* | 639 | /* |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 47c9876a2449..0ff99e0b2ea3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | |||
@@ -442,6 +442,9 @@ enum { | |||
442 | MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3) | 442 | MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3) |
443 | }; | 443 | }; |
444 | 444 | ||
445 | #define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) | ||
446 | #define MLX4_EN_MAC_HASH_IDX 5 | ||
447 | |||
445 | struct mlx4_en_priv { | 448 | struct mlx4_en_priv { |
446 | struct mlx4_en_dev *mdev; | 449 | struct mlx4_en_dev *mdev; |
447 | struct mlx4_en_port_profile *prof; | 450 | struct mlx4_en_port_profile *prof; |
@@ -521,7 +524,7 @@ struct mlx4_en_priv { | |||
521 | bool wol; | 524 | bool wol; |
522 | struct device *ddev; | 525 | struct device *ddev; |
523 | int base_tx_qpn; | 526 | int base_tx_qpn; |
524 | struct radix_tree_root mac_tree; | 527 | struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE]; |
525 | 528 | ||
526 | #ifdef CONFIG_MLX4_EN_DCB | 529 | #ifdef CONFIG_MLX4_EN_DCB |
527 | struct ieee_ets ets; | 530 | struct ieee_ets ets; |
@@ -542,8 +545,10 @@ enum mlx4_en_wol { | |||
542 | }; | 545 | }; |
543 | 546 | ||
544 | struct mlx4_mac_entry { | 547 | struct mlx4_mac_entry { |
548 | struct hlist_node hlist; | ||
545 | unsigned char mac[ETH_ALEN + 2]; | 549 | unsigned char mac[ETH_ALEN + 2]; |
546 | u64 reg_id; | 550 | u64 reg_id; |
551 | struct rcu_head rcu; | ||
547 | }; | 552 | }; |
548 | 553 | ||
549 | #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) | 554 | #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) |