diff options
author | Jason Baron <jbaron@akamai.com> | 2016-09-22 17:12:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-26 09:43:06 -0400 |
commit | e8c6ae9fbf8ca70ef0c2de0d2f3995acb0dc8968 (patch) | |
tree | d1e1e5fbcee7979dc3dc58de4d41e732cd876c6d | |
parent | b47c62c5de2bc43a26bcaca8d7a93bf9dee66ffe (diff) |
bnx2x: allocate mac filtering 'mcast_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 'mcast_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>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 79 |
1 files changed, 51 insertions, 28 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index dab61a81a3ba..20fe6a8c35c1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -12563,43 +12563,64 @@ static int bnx2x_close(struct net_device *dev) | |||
12563 | return 0; | 12563 | return 0; |
12564 | } | 12564 | } |
12565 | 12565 | ||
12566 | static int bnx2x_init_mcast_macs_list(struct bnx2x *bp, | 12566 | struct bnx2x_mcast_list_elem_group |
12567 | struct bnx2x_mcast_ramrod_params *p) | ||
12568 | { | 12567 | { |
12569 | int mc_count = netdev_mc_count(bp->dev); | 12568 | struct list_head mcast_group_link; |
12570 | struct bnx2x_mcast_list_elem *mc_mac = | 12569 | struct bnx2x_mcast_list_elem mcast_elems[]; |
12571 | kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC); | 12570 | }; |
12572 | struct netdev_hw_addr *ha; | ||
12573 | 12571 | ||
12574 | if (!mc_mac) { | 12572 | #define MCAST_ELEMS_PER_PG \ |
12575 | BNX2X_ERR("Failed to allocate mc MAC list\n"); | 12573 | ((PAGE_SIZE - sizeof(struct bnx2x_mcast_list_elem_group)) / \ |
12576 | return -ENOMEM; | 12574 | sizeof(struct bnx2x_mcast_list_elem)) |
12575 | |||
12576 | static void bnx2x_free_mcast_macs_list(struct list_head *mcast_group_list) | ||
12577 | { | ||
12578 | struct bnx2x_mcast_list_elem_group *current_mcast_group; | ||
12579 | |||
12580 | while (!list_empty(mcast_group_list)) { | ||
12581 | current_mcast_group = list_first_entry(mcast_group_list, | ||
12582 | struct bnx2x_mcast_list_elem_group, | ||
12583 | mcast_group_link); | ||
12584 | list_del(¤t_mcast_group->mcast_group_link); | ||
12585 | free_page((unsigned long)current_mcast_group); | ||
12577 | } | 12586 | } |
12587 | } | ||
12578 | 12588 | ||
12579 | INIT_LIST_HEAD(&p->mcast_list); | 12589 | static int bnx2x_init_mcast_macs_list(struct bnx2x *bp, |
12590 | struct bnx2x_mcast_ramrod_params *p, | ||
12591 | struct list_head *mcast_group_list) | ||
12592 | { | ||
12593 | struct bnx2x_mcast_list_elem *mc_mac; | ||
12594 | struct netdev_hw_addr *ha; | ||
12595 | struct bnx2x_mcast_list_elem_group *current_mcast_group = NULL; | ||
12596 | int mc_count = netdev_mc_count(bp->dev); | ||
12597 | int offset = 0; | ||
12580 | 12598 | ||
12599 | INIT_LIST_HEAD(&p->mcast_list); | ||
12581 | netdev_for_each_mc_addr(ha, bp->dev) { | 12600 | netdev_for_each_mc_addr(ha, bp->dev) { |
12601 | if (!offset) { | ||
12602 | current_mcast_group = | ||
12603 | (struct bnx2x_mcast_list_elem_group *) | ||
12604 | __get_free_page(GFP_ATOMIC); | ||
12605 | if (!current_mcast_group) { | ||
12606 | bnx2x_free_mcast_macs_list(mcast_group_list); | ||
12607 | BNX2X_ERR("Failed to allocate mc MAC list\n"); | ||
12608 | return -ENOMEM; | ||
12609 | } | ||
12610 | list_add(¤t_mcast_group->mcast_group_link, | ||
12611 | mcast_group_list); | ||
12612 | } | ||
12613 | mc_mac = ¤t_mcast_group->mcast_elems[offset]; | ||
12582 | mc_mac->mac = bnx2x_mc_addr(ha); | 12614 | mc_mac->mac = bnx2x_mc_addr(ha); |
12583 | list_add_tail(&mc_mac->link, &p->mcast_list); | 12615 | list_add_tail(&mc_mac->link, &p->mcast_list); |
12584 | mc_mac++; | 12616 | offset++; |
12617 | if (offset == MCAST_ELEMS_PER_PG) | ||
12618 | offset = 0; | ||
12585 | } | 12619 | } |
12586 | |||
12587 | p->mcast_list_len = mc_count; | 12620 | p->mcast_list_len = mc_count; |
12588 | |||
12589 | return 0; | 12621 | return 0; |
12590 | } | 12622 | } |
12591 | 12623 | ||
12592 | static void bnx2x_free_mcast_macs_list( | ||
12593 | struct bnx2x_mcast_ramrod_params *p) | ||
12594 | { | ||
12595 | struct bnx2x_mcast_list_elem *mc_mac = | ||
12596 | list_first_entry(&p->mcast_list, struct bnx2x_mcast_list_elem, | ||
12597 | link); | ||
12598 | |||
12599 | WARN_ON(!mc_mac); | ||
12600 | kfree(mc_mac); | ||
12601 | } | ||
12602 | |||
12603 | /** | 12624 | /** |
12604 | * bnx2x_set_uc_list - configure a new unicast MACs list. | 12625 | * bnx2x_set_uc_list - configure a new unicast MACs list. |
12605 | * | 12626 | * |
@@ -12647,6 +12668,7 @@ static int bnx2x_set_uc_list(struct bnx2x *bp) | |||
12647 | 12668 | ||
12648 | static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) | 12669 | static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) |
12649 | { | 12670 | { |
12671 | LIST_HEAD(mcast_group_list); | ||
12650 | struct net_device *dev = bp->dev; | 12672 | struct net_device *dev = bp->dev; |
12651 | struct bnx2x_mcast_ramrod_params rparam = {NULL}; | 12673 | struct bnx2x_mcast_ramrod_params rparam = {NULL}; |
12652 | int rc = 0; | 12674 | int rc = 0; |
@@ -12662,7 +12684,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) | |||
12662 | 12684 | ||
12663 | /* then, configure a new MACs list */ | 12685 | /* then, configure a new MACs list */ |
12664 | if (netdev_mc_count(dev)) { | 12686 | if (netdev_mc_count(dev)) { |
12665 | rc = bnx2x_init_mcast_macs_list(bp, &rparam); | 12687 | rc = bnx2x_init_mcast_macs_list(bp, &rparam, &mcast_group_list); |
12666 | if (rc) | 12688 | if (rc) |
12667 | return rc; | 12689 | return rc; |
12668 | 12690 | ||
@@ -12673,7 +12695,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) | |||
12673 | BNX2X_ERR("Failed to set a new multicast configuration: %d\n", | 12695 | BNX2X_ERR("Failed to set a new multicast configuration: %d\n", |
12674 | rc); | 12696 | rc); |
12675 | 12697 | ||
12676 | bnx2x_free_mcast_macs_list(&rparam); | 12698 | bnx2x_free_mcast_macs_list(&mcast_group_list); |
12677 | } | 12699 | } |
12678 | 12700 | ||
12679 | return rc; | 12701 | return rc; |
@@ -12681,6 +12703,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) | |||
12681 | 12703 | ||
12682 | static int bnx2x_set_mc_list(struct bnx2x *bp) | 12704 | static int bnx2x_set_mc_list(struct bnx2x *bp) |
12683 | { | 12705 | { |
12706 | LIST_HEAD(mcast_group_list); | ||
12684 | struct bnx2x_mcast_ramrod_params rparam = {NULL}; | 12707 | struct bnx2x_mcast_ramrod_params rparam = {NULL}; |
12685 | struct net_device *dev = bp->dev; | 12708 | struct net_device *dev = bp->dev; |
12686 | int rc = 0; | 12709 | int rc = 0; |
@@ -12692,7 +12715,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) | |||
12692 | rparam.mcast_obj = &bp->mcast_obj; | 12715 | rparam.mcast_obj = &bp->mcast_obj; |
12693 | 12716 | ||
12694 | if (netdev_mc_count(dev)) { | 12717 | if (netdev_mc_count(dev)) { |
12695 | rc = bnx2x_init_mcast_macs_list(bp, &rparam); | 12718 | rc = bnx2x_init_mcast_macs_list(bp, &rparam, &mcast_group_list); |
12696 | if (rc) | 12719 | if (rc) |
12697 | return rc; | 12720 | return rc; |
12698 | 12721 | ||
@@ -12703,7 +12726,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) | |||
12703 | BNX2X_ERR("Failed to set a new multicast configuration: %d\n", | 12726 | BNX2X_ERR("Failed to set a new multicast configuration: %d\n", |
12704 | rc); | 12727 | rc); |
12705 | 12728 | ||
12706 | bnx2x_free_mcast_macs_list(&rparam); | 12729 | bnx2x_free_mcast_macs_list(&mcast_group_list); |
12707 | } else { | 12730 | } else { |
12708 | /* If no mc addresses are required, flush the configuration */ | 12731 | /* If no mc addresses are required, flush the configuration */ |
12709 | rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); | 12732 | rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); |