diff options
author | Jason Baron <jbaron@akamai.com> | 2016-09-22 17:12:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-26 09:43:06 -0400 |
commit | 3129e1599c6edfafc2a0a8be9f2eb344c7feb920 (patch) | |
tree | 48ea93455bc0ee13261a953028a0c1db473a25c6 | |
parent | e8c6ae9fbf8ca70ef0c2de0d2f3995acb0dc8968 (diff) |
bnx2x: allocate mac filtering pending list in PAGE_SIZE increments
Currently, we can have high order page allocations that specify
GFP_ATOMIC when configuring multicast MAC address filters.
For example, we have seen order 2 page allocation failures with
~500 multicast addresses configured.
Convert the allocation for the pending list to be done in PAGE_SIZE
increments.
Signed-off-by: Jason Baron <jbaron@akamai.com>
Cc: Yuval Mintz <Yuval.Mintz@qlogic.com>
Cc: Ariel Elior <Ariel.Elior@qlogic.com>
Acked-by: Yuval Mintz <Yuval.Mintz@caviumnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 123 |
1 files changed, 86 insertions, 37 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index d468380c2a23..4947a9cbf0c1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | |||
@@ -2606,8 +2606,23 @@ struct bnx2x_mcast_bin_elem { | |||
2606 | int type; /* BNX2X_MCAST_CMD_SET_{ADD, DEL} */ | 2606 | int type; /* BNX2X_MCAST_CMD_SET_{ADD, DEL} */ |
2607 | }; | 2607 | }; |
2608 | 2608 | ||
2609 | union bnx2x_mcast_elem { | ||
2610 | struct bnx2x_mcast_bin_elem bin_elem; | ||
2611 | struct bnx2x_mcast_mac_elem mac_elem; | ||
2612 | }; | ||
2613 | |||
2614 | struct bnx2x_mcast_elem_group { | ||
2615 | struct list_head mcast_group_link; | ||
2616 | union bnx2x_mcast_elem mcast_elems[]; | ||
2617 | }; | ||
2618 | |||
2619 | #define MCAST_MAC_ELEMS_PER_PG \ | ||
2620 | ((PAGE_SIZE - sizeof(struct bnx2x_mcast_elem_group)) / \ | ||
2621 | sizeof(union bnx2x_mcast_elem)) | ||
2622 | |||
2609 | struct bnx2x_pending_mcast_cmd { | 2623 | struct bnx2x_pending_mcast_cmd { |
2610 | struct list_head link; | 2624 | struct list_head link; |
2625 | struct list_head group_head; | ||
2611 | int type; /* BNX2X_MCAST_CMD_X */ | 2626 | int type; /* BNX2X_MCAST_CMD_X */ |
2612 | union { | 2627 | union { |
2613 | struct list_head macs_head; | 2628 | struct list_head macs_head; |
@@ -2638,16 +2653,29 @@ static int bnx2x_mcast_wait(struct bnx2x *bp, | |||
2638 | return 0; | 2653 | return 0; |
2639 | } | 2654 | } |
2640 | 2655 | ||
2656 | static void bnx2x_free_groups(struct list_head *mcast_group_list) | ||
2657 | { | ||
2658 | struct bnx2x_mcast_elem_group *current_mcast_group; | ||
2659 | |||
2660 | while (!list_empty(mcast_group_list)) { | ||
2661 | current_mcast_group = list_first_entry(mcast_group_list, | ||
2662 | struct bnx2x_mcast_elem_group, | ||
2663 | mcast_group_link); | ||
2664 | list_del(¤t_mcast_group->mcast_group_link); | ||
2665 | free_page((unsigned long)current_mcast_group); | ||
2666 | } | ||
2667 | } | ||
2668 | |||
2641 | static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp, | 2669 | static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp, |
2642 | struct bnx2x_mcast_obj *o, | 2670 | struct bnx2x_mcast_obj *o, |
2643 | struct bnx2x_mcast_ramrod_params *p, | 2671 | struct bnx2x_mcast_ramrod_params *p, |
2644 | enum bnx2x_mcast_cmd cmd) | 2672 | enum bnx2x_mcast_cmd cmd) |
2645 | { | 2673 | { |
2646 | int total_sz; | ||
2647 | struct bnx2x_pending_mcast_cmd *new_cmd; | 2674 | struct bnx2x_pending_mcast_cmd *new_cmd; |
2648 | struct bnx2x_mcast_mac_elem *cur_mac = NULL; | ||
2649 | struct bnx2x_mcast_list_elem *pos; | 2675 | struct bnx2x_mcast_list_elem *pos; |
2650 | int macs_list_len = 0, macs_list_len_size; | 2676 | struct bnx2x_mcast_elem_group *elem_group; |
2677 | struct bnx2x_mcast_mac_elem *mac_elem; | ||
2678 | int total_elems = 0, macs_list_len = 0, offset = 0; | ||
2651 | 2679 | ||
2652 | /* When adding MACs we'll need to store their values */ | 2680 | /* When adding MACs we'll need to store their values */ |
2653 | if (cmd == BNX2X_MCAST_CMD_ADD || cmd == BNX2X_MCAST_CMD_SET) | 2681 | if (cmd == BNX2X_MCAST_CMD_ADD || cmd == BNX2X_MCAST_CMD_SET) |
@@ -2657,50 +2685,61 @@ static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp, | |||
2657 | if (!p->mcast_list_len) | 2685 | if (!p->mcast_list_len) |
2658 | return 0; | 2686 | return 0; |
2659 | 2687 | ||
2660 | /* For a set command, we need to allocate sufficient memory for all | ||
2661 | * the bins, since we can't analyze at this point how much memory would | ||
2662 | * be required. | ||
2663 | */ | ||
2664 | macs_list_len_size = macs_list_len * | ||
2665 | sizeof(struct bnx2x_mcast_mac_elem); | ||
2666 | if (cmd == BNX2X_MCAST_CMD_SET) { | ||
2667 | int bin_size = BNX2X_MCAST_BINS_NUM * | ||
2668 | sizeof(struct bnx2x_mcast_bin_elem); | ||
2669 | |||
2670 | if (bin_size > macs_list_len_size) | ||
2671 | macs_list_len_size = bin_size; | ||
2672 | } | ||
2673 | total_sz = sizeof(*new_cmd) + macs_list_len_size; | ||
2674 | |||
2675 | /* Add mcast is called under spin_lock, thus calling with GFP_ATOMIC */ | 2688 | /* Add mcast is called under spin_lock, thus calling with GFP_ATOMIC */ |
2676 | new_cmd = kzalloc(total_sz, GFP_ATOMIC); | 2689 | new_cmd = kzalloc(sizeof(*new_cmd), GFP_ATOMIC); |
2677 | |||
2678 | if (!new_cmd) | 2690 | if (!new_cmd) |
2679 | return -ENOMEM; | 2691 | return -ENOMEM; |
2680 | 2692 | ||
2681 | DP(BNX2X_MSG_SP, "About to enqueue a new %d command. macs_list_len=%d\n", | ||
2682 | cmd, macs_list_len); | ||
2683 | |||
2684 | INIT_LIST_HEAD(&new_cmd->data.macs_head); | 2693 | INIT_LIST_HEAD(&new_cmd->data.macs_head); |
2685 | 2694 | INIT_LIST_HEAD(&new_cmd->group_head); | |
2686 | new_cmd->type = cmd; | 2695 | new_cmd->type = cmd; |
2687 | new_cmd->done = false; | 2696 | new_cmd->done = false; |
2688 | 2697 | ||
2698 | DP(BNX2X_MSG_SP, "About to enqueue a new %d command. macs_list_len=%d\n", | ||
2699 | cmd, macs_list_len); | ||
2700 | |||
2689 | switch (cmd) { | 2701 | switch (cmd) { |
2690 | case BNX2X_MCAST_CMD_ADD: | 2702 | case BNX2X_MCAST_CMD_ADD: |
2691 | case BNX2X_MCAST_CMD_SET: | 2703 | case BNX2X_MCAST_CMD_SET: |
2692 | cur_mac = (struct bnx2x_mcast_mac_elem *) | 2704 | /* For a set command, we need to allocate sufficient memory for |
2693 | ((u8 *)new_cmd + sizeof(*new_cmd)); | 2705 | * all the bins, since we can't analyze at this point how much |
2694 | 2706 | * memory would be required. | |
2695 | /* Push the MACs of the current command into the pending command | ||
2696 | * MACs list: FIFO | ||
2697 | */ | 2707 | */ |
2708 | total_elems = macs_list_len; | ||
2709 | if (cmd == BNX2X_MCAST_CMD_SET) { | ||
2710 | if (total_elems < BNX2X_MCAST_BINS_NUM) | ||
2711 | total_elems = BNX2X_MCAST_BINS_NUM; | ||
2712 | } | ||
2713 | while (total_elems > 0) { | ||
2714 | elem_group = (struct bnx2x_mcast_elem_group *) | ||
2715 | __get_free_page(GFP_ATOMIC | __GFP_ZERO); | ||
2716 | if (!elem_group) { | ||
2717 | kfree(new_cmd); | ||
2718 | bnx2x_free_groups(&new_cmd->group_head); | ||
2719 | return -ENOMEM; | ||
2720 | } | ||
2721 | total_elems -= MCAST_MAC_ELEMS_PER_PG; | ||
2722 | list_add_tail(&elem_group->mcast_group_link, | ||
2723 | &new_cmd->group_head); | ||
2724 | } | ||
2725 | elem_group = list_first_entry(&new_cmd->group_head, | ||
2726 | struct bnx2x_mcast_elem_group, | ||
2727 | mcast_group_link); | ||
2698 | list_for_each_entry(pos, &p->mcast_list, link) { | 2728 | list_for_each_entry(pos, &p->mcast_list, link) { |
2699 | memcpy(cur_mac->mac, pos->mac, ETH_ALEN); | 2729 | mac_elem = &elem_group->mcast_elems[offset].mac_elem; |
2700 | list_add_tail(&cur_mac->link, &new_cmd->data.macs_head); | 2730 | memcpy(mac_elem->mac, pos->mac, ETH_ALEN); |
2701 | cur_mac++; | 2731 | /* Push the MACs of the current command into the pending |
2732 | * command MACs list: FIFO | ||
2733 | */ | ||
2734 | list_add_tail(&mac_elem->link, | ||
2735 | &new_cmd->data.macs_head); | ||
2736 | offset++; | ||
2737 | if (offset == MCAST_MAC_ELEMS_PER_PG) { | ||
2738 | offset = 0; | ||
2739 | elem_group = list_next_entry(elem_group, | ||
2740 | mcast_group_link); | ||
2741 | } | ||
2702 | } | 2742 | } |
2703 | |||
2704 | break; | 2743 | break; |
2705 | 2744 | ||
2706 | case BNX2X_MCAST_CMD_DEL: | 2745 | case BNX2X_MCAST_CMD_DEL: |
@@ -2978,7 +3017,8 @@ bnx2x_mcast_hdl_pending_set_e2_convert(struct bnx2x *bp, | |||
2978 | u64 cur[BNX2X_MCAST_VEC_SZ], req[BNX2X_MCAST_VEC_SZ]; | 3017 | u64 cur[BNX2X_MCAST_VEC_SZ], req[BNX2X_MCAST_VEC_SZ]; |
2979 | struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n; | 3018 | struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n; |
2980 | struct bnx2x_mcast_bin_elem *p_item; | 3019 | struct bnx2x_mcast_bin_elem *p_item; |
2981 | int i, cnt = 0, mac_cnt = 0; | 3020 | struct bnx2x_mcast_elem_group *elem_group; |
3021 | int cnt = 0, mac_cnt = 0, offset = 0, i; | ||
2982 | 3022 | ||
2983 | memset(req, 0, sizeof(u64) * BNX2X_MCAST_VEC_SZ); | 3023 | memset(req, 0, sizeof(u64) * BNX2X_MCAST_VEC_SZ); |
2984 | memcpy(cur, o->registry.aprox_match.vec, | 3024 | memcpy(cur, o->registry.aprox_match.vec, |
@@ -3001,9 +3041,10 @@ bnx2x_mcast_hdl_pending_set_e2_convert(struct bnx2x *bp, | |||
3001 | * a list that will be used to configure bins. | 3041 | * a list that will be used to configure bins. |
3002 | */ | 3042 | */ |
3003 | cmd_pos->set_convert = true; | 3043 | cmd_pos->set_convert = true; |
3004 | p_item = (struct bnx2x_mcast_bin_elem *)(cmd_pos + 1); | ||
3005 | INIT_LIST_HEAD(&cmd_pos->data.macs_head); | 3044 | INIT_LIST_HEAD(&cmd_pos->data.macs_head); |
3006 | 3045 | elem_group = list_first_entry(&cmd_pos->group_head, | |
3046 | struct bnx2x_mcast_elem_group, | ||
3047 | mcast_group_link); | ||
3007 | for (i = 0; i < BNX2X_MCAST_BINS_NUM; i++) { | 3048 | for (i = 0; i < BNX2X_MCAST_BINS_NUM; i++) { |
3008 | bool b_current = !!BIT_VEC64_TEST_BIT(cur, i); | 3049 | bool b_current = !!BIT_VEC64_TEST_BIT(cur, i); |
3009 | bool b_required = !!BIT_VEC64_TEST_BIT(req, i); | 3050 | bool b_required = !!BIT_VEC64_TEST_BIT(req, i); |
@@ -3011,12 +3052,18 @@ bnx2x_mcast_hdl_pending_set_e2_convert(struct bnx2x *bp, | |||
3011 | if (b_current == b_required) | 3052 | if (b_current == b_required) |
3012 | continue; | 3053 | continue; |
3013 | 3054 | ||
3055 | p_item = &elem_group->mcast_elems[offset].bin_elem; | ||
3014 | p_item->bin = i; | 3056 | p_item->bin = i; |
3015 | p_item->type = b_required ? BNX2X_MCAST_CMD_SET_ADD | 3057 | p_item->type = b_required ? BNX2X_MCAST_CMD_SET_ADD |
3016 | : BNX2X_MCAST_CMD_SET_DEL; | 3058 | : BNX2X_MCAST_CMD_SET_DEL; |
3017 | list_add_tail(&p_item->link , &cmd_pos->data.macs_head); | 3059 | list_add_tail(&p_item->link , &cmd_pos->data.macs_head); |
3018 | p_item++; | ||
3019 | cnt++; | 3060 | cnt++; |
3061 | offset++; | ||
3062 | if (offset == MCAST_MAC_ELEMS_PER_PG) { | ||
3063 | offset = 0; | ||
3064 | elem_group = list_next_entry(elem_group, | ||
3065 | mcast_group_link); | ||
3066 | } | ||
3020 | } | 3067 | } |
3021 | 3068 | ||
3022 | /* We now definitely know how many commands are hiding here. | 3069 | /* We now definitely know how many commands are hiding here. |
@@ -3103,6 +3150,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e2(struct bnx2x *bp, | |||
3103 | */ | 3150 | */ |
3104 | if (cmd_pos->done) { | 3151 | if (cmd_pos->done) { |
3105 | list_del(&cmd_pos->link); | 3152 | list_del(&cmd_pos->link); |
3153 | bnx2x_free_groups(&cmd_pos->group_head); | ||
3106 | kfree(cmd_pos); | 3154 | kfree(cmd_pos); |
3107 | } | 3155 | } |
3108 | 3156 | ||
@@ -3741,6 +3789,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1( | |||
3741 | } | 3789 | } |
3742 | 3790 | ||
3743 | list_del(&cmd_pos->link); | 3791 | list_del(&cmd_pos->link); |
3792 | bnx2x_free_groups(&cmd_pos->group_head); | ||
3744 | kfree(cmd_pos); | 3793 | kfree(cmd_pos); |
3745 | 3794 | ||
3746 | return cnt; | 3795 | return cnt; |