Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+51 −28
Original line number Diff line number Diff line
@@ -12563,43 +12563,64 @@ static int bnx2x_close(struct net_device *dev)
	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,
				      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 =
		kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC);
	struct bnx2x_mcast_list_elem *mc_mac;
	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");
				return -ENOMEM;
			}

	INIT_LIST_HEAD(&p->mcast_list);

	netdev_for_each_mc_addr(ha, bp->dev) {
			list_add(&current_mcast_group->mcast_group_link,
				 mcast_group_list);
		}
		mc_mac = &current_mcast_group->mcast_elems[offset];
		mc_mac->mac = bnx2x_mc_addr(ha);
		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;

	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.
 *
@@ -12647,6 +12668,7 @@ static int bnx2x_set_uc_list(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 bnx2x_mcast_ramrod_params rparam = {NULL};
	int rc = 0;
@@ -12662,7 +12684,7 @@ static int bnx2x_set_mc_list_e1x(struct bnx2x *bp)

	/* then, configure a new MACs list */
	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)
			return rc;

@@ -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",
				  rc);

		bnx2x_free_mcast_macs_list(&rparam);
		bnx2x_free_mcast_macs_list(&mcast_group_list);
	}

	return rc;
@@ -12681,6 +12703,7 @@ static int bnx2x_set_mc_list_e1x(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 net_device *dev = bp->dev;
	int rc = 0;
@@ -12692,7 +12715,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
	rparam.mcast_obj = &bp->mcast_obj;

	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)
			return rc;

@@ -12703,7 +12726,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
			BNX2X_ERR("Failed to set a new multicast configuration: %d\n",
				  rc);

		bnx2x_free_mcast_macs_list(&rparam);
		bnx2x_free_mcast_macs_list(&mcast_group_list);
	} else {
		/* If no mc addresses are required, flush the configuration */
		rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);