Commit e8c6ae9f authored by Jason Baron's avatar Jason Baron Committed by David S. Miller

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: default avatarJason Baron <jbaron@akamai.com>
Cc: Yuval Mintz <Yuval.Mintz@qlogic.com>
Cc: Ariel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b47c62c5
...@@ -12563,43 +12563,64 @@ static int bnx2x_close(struct net_device *dev) ...@@ -12563,43 +12563,64 @@ static int bnx2x_close(struct net_device *dev)
return 0; return 0;
} }
struct bnx2x_mcast_list_elem_group
{
struct list_head mcast_group_link;
struct bnx2x_mcast_list_elem mcast_elems[];
};
#define MCAST_ELEMS_PER_PG \
((PAGE_SIZE - sizeof(struct bnx2x_mcast_list_elem_group)) / \
sizeof(struct bnx2x_mcast_list_elem))
static void bnx2x_free_mcast_macs_list(struct list_head *mcast_group_list)
{
struct bnx2x_mcast_list_elem_group *current_mcast_group;
while (!list_empty(mcast_group_list)) {
current_mcast_group = list_first_entry(mcast_group_list,
struct bnx2x_mcast_list_elem_group,
mcast_group_link);
list_del(&current_mcast_group->mcast_group_link);
free_page((unsigned long)current_mcast_group);
}
}
static int bnx2x_init_mcast_macs_list(struct bnx2x *bp, static int bnx2x_init_mcast_macs_list(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p) struct bnx2x_mcast_ramrod_params *p,
struct list_head *mcast_group_list)
{ {
int mc_count = netdev_mc_count(bp->dev); struct bnx2x_mcast_list_elem *mc_mac;
struct bnx2x_mcast_list_elem *mc_mac =
kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC);
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
struct bnx2x_mcast_list_elem_group *current_mcast_group = NULL;
int mc_count = netdev_mc_count(bp->dev);
int offset = 0;
if (!mc_mac) { INIT_LIST_HEAD(&p->mcast_list);
netdev_for_each_mc_addr(ha, bp->dev) {
if (!offset) {
current_mcast_group =
(struct bnx2x_mcast_list_elem_group *)
__get_free_page(GFP_ATOMIC);
if (!current_mcast_group) {
bnx2x_free_mcast_macs_list(mcast_group_list);
BNX2X_ERR("Failed to allocate mc MAC list\n"); BNX2X_ERR("Failed to allocate mc MAC list\n");
return -ENOMEM; return -ENOMEM;
} }
list_add(&current_mcast_group->mcast_group_link,
INIT_LIST_HEAD(&p->mcast_list); mcast_group_list);
}
netdev_for_each_mc_addr(ha, bp->dev) { mc_mac = &current_mcast_group->mcast_elems[offset];
mc_mac->mac = bnx2x_mc_addr(ha); mc_mac->mac = bnx2x_mc_addr(ha);
list_add_tail(&mc_mac->link, &p->mcast_list); list_add_tail(&mc_mac->link, &p->mcast_list);
mc_mac++; offset++;
if (offset == MCAST_ELEMS_PER_PG)
offset = 0;
} }
p->mcast_list_len = mc_count; p->mcast_list_len = mc_count;
return 0; return 0;
} }
static void bnx2x_free_mcast_macs_list(
struct bnx2x_mcast_ramrod_params *p)
{
struct bnx2x_mcast_list_elem *mc_mac =
list_first_entry(&p->mcast_list, struct bnx2x_mcast_list_elem,
link);
WARN_ON(!mc_mac);
kfree(mc_mac);
}
/** /**
* bnx2x_set_uc_list - configure a new unicast MACs list. * bnx2x_set_uc_list - configure a new unicast MACs list.
* *
...@@ -12647,6 +12668,7 @@ static int bnx2x_set_uc_list(struct bnx2x *bp) ...@@ -12647,6 +12668,7 @@ static int bnx2x_set_uc_list(struct bnx2x *bp)
static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) static int bnx2x_set_mc_list_e1x(struct bnx2x *bp)
{ {
LIST_HEAD(mcast_group_list);
struct net_device *dev = bp->dev; struct net_device *dev = bp->dev;
struct bnx2x_mcast_ramrod_params rparam = {NULL}; struct bnx2x_mcast_ramrod_params rparam = {NULL};
int rc = 0; int rc = 0;
...@@ -12662,7 +12684,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) ...@@ -12662,7 +12684,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp)
/* then, configure a new MACs list */ /* then, configure a new MACs list */
if (netdev_mc_count(dev)) { if (netdev_mc_count(dev)) {
rc = bnx2x_init_mcast_macs_list(bp, &rparam); rc = bnx2x_init_mcast_macs_list(bp, &rparam, &mcast_group_list);
if (rc) if (rc)
return rc; return rc;
...@@ -12673,7 +12695,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) ...@@ -12673,7 +12695,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp)
BNX2X_ERR("Failed to set a new multicast configuration: %d\n", BNX2X_ERR("Failed to set a new multicast configuration: %d\n",
rc); rc);
bnx2x_free_mcast_macs_list(&rparam); bnx2x_free_mcast_macs_list(&mcast_group_list);
} }
return rc; return rc;
...@@ -12681,6 +12703,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp) ...@@ -12681,6 +12703,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp)
static int bnx2x_set_mc_list(struct bnx2x *bp) static int bnx2x_set_mc_list(struct bnx2x *bp)
{ {
LIST_HEAD(mcast_group_list);
struct bnx2x_mcast_ramrod_params rparam = {NULL}; struct bnx2x_mcast_ramrod_params rparam = {NULL};
struct net_device *dev = bp->dev; struct net_device *dev = bp->dev;
int rc = 0; int rc = 0;
...@@ -12692,7 +12715,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) ...@@ -12692,7 +12715,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
rparam.mcast_obj = &bp->mcast_obj; rparam.mcast_obj = &bp->mcast_obj;
if (netdev_mc_count(dev)) { if (netdev_mc_count(dev)) {
rc = bnx2x_init_mcast_macs_list(bp, &rparam); rc = bnx2x_init_mcast_macs_list(bp, &rparam, &mcast_group_list);
if (rc) if (rc)
return rc; return rc;
...@@ -12703,7 +12726,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) ...@@ -12703,7 +12726,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
BNX2X_ERR("Failed to set a new multicast configuration: %d\n", BNX2X_ERR("Failed to set a new multicast configuration: %d\n",
rc); rc);
bnx2x_free_mcast_macs_list(&rparam); bnx2x_free_mcast_macs_list(&mcast_group_list);
} else { } else {
/* If no mc addresses are required, flush the configuration */ /* If no mc addresses are required, flush the configuration */
rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment