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

Commit 05cc5a39 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller
Browse files

bnx2x: add vlan filtering offload



Current driver always uses vlan-promisc mode, i.e., it receives both
tagged and untagged traffic and lets the network stack drop packets
tagged with unrequested vlan tags.

This patch implements vlan-filtering offload in the driver -
Unless explicitly configured to promisc mode, only untagged packets or
packets tagged with requested vlans would reach the Rx flow.

Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarAriel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e82a08b0
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -1228,6 +1228,10 @@ struct bnx2x_slowpath {
		struct eth_classify_rules_ramrod_data	e2;
	} mac_rdata;

	union {
		struct eth_classify_rules_ramrod_data	e2;
	} vlan_rdata;

	union {
		struct tstorm_eth_mac_filter_config	e1x;
		struct eth_filter_rules_ramrod_data	e2;
@@ -1410,6 +1414,9 @@ struct bnx2x_sp_objs {

	/* Queue State object */
	struct bnx2x_queue_sp_obj q_obj;

	/* VLANs object */
	struct bnx2x_vlan_mac_obj vlan_obj;
};

struct bnx2x_fp_stats {
@@ -1427,6 +1434,12 @@ enum {
	SUB_MF_MODE_BD,
};

struct bnx2x_vlan_entry {
	struct list_head link;
	u16 vid;
	bool hw;
};

struct bnx2x {
	/* Fields used in the tx and intr/napi performance paths
	 * are grouped together in the beginning of the structure
@@ -1865,8 +1878,6 @@ struct bnx2x {
	int					dcb_version;

	/* CAM credit pools */

	/* used only in sriov */
	struct bnx2x_credit_pool_obj		vlans_pool;

	struct bnx2x_credit_pool_obj		macs_pool;
@@ -1929,6 +1940,11 @@ struct bnx2x {
	u16 rx_filter;

	struct bnx2x_link_report_data		vf_link_vars;
	struct list_head vlan_reg;
	u16 vlan_cnt;
	u16 vlan_credit;
	u16 vxlan_dst_port;
	bool accept_any_vlan;
};

/* Tx queues may be less or equal to Rx queues */
@@ -1956,23 +1972,14 @@ extern int num_queues;
#define RSS_IPV6_TCP_CAP_MASK						\
	TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY

/* func init flags */
#define FUNC_FLG_RSS		0x0001
#define FUNC_FLG_STATS		0x0002
/* removed  FUNC_FLG_UNMATCHED	0x0004 */
#define FUNC_FLG_TPA		0x0008
#define FUNC_FLG_SPQ		0x0010
#define FUNC_FLG_LEADING	0x0020	/* PF only */
#define FUNC_FLG_LEADING_STATS	0x0040
struct bnx2x_func_init_params {
	/* dma */
	dma_addr_t	fw_stat_map;	/* valid iff FUNC_FLG_STATS */
	dma_addr_t	spq_map;	/* valid iff FUNC_FLG_SPQ */
	bool		spq_active;
	dma_addr_t	spq_map;
	u16		spq_prod;

	u16		func_flgs;
	u16		func_id;	/* abs fid */
	u16		pf_id;
	u16		spq_prod;	/* valid iff FUNC_FLG_SPQ */
};

#define for_each_cnic_queue(bp, var) \
@@ -2082,6 +2089,11 @@ struct bnx2x_func_init_params {
int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac,
		      struct bnx2x_vlan_mac_obj *obj, bool set,
		      int mac_type, unsigned long *ramrod_flags);

int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
		       struct bnx2x_vlan_mac_obj *obj, bool set,
		       unsigned long *ramrod_flags);

/**
 * bnx2x_del_all_macs - delete all MACs configured for the specific MAC object
 *
@@ -2486,6 +2498,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define VF_ACQUIRE_THRESH		3
#define VF_ACQUIRE_MAC_FILTERS		1
#define VF_ACQUIRE_MC_FILTERS		10
#define VF_ACQUIRE_VLAN_FILTERS		2 /* VLAN0 + 'real' VLAN */

#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
			    (!((me_reg) & ME_REG_VF_ERR)))
@@ -2596,4 +2609,9 @@ void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb);
#define BNX2X_MAX_PHC_DRIFT 31000000
#define BNX2X_PTP_TX_TIMEOUT

/* Re-configure all previously configured vlan filters.
 * Meant for implicit re-load flows.
 */
int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp);

#endif /* bnx2x.h */
+5 −0
Original line number Diff line number Diff line
@@ -2848,6 +2848,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)

	/* Start fast path */

	/* Re-configure vlan filters */
	rc = bnx2x_vlan_reconfigure_vid(bp);
	if (rc)
		LOAD_ERROR_EXIT(bp, load_error3);

	/* Initialize Rx filter. */
	bnx2x_set_rx_mode_inner(bp);

+12 −1
Original line number Diff line number Diff line
@@ -1066,6 +1066,15 @@ static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp,
			   BNX2X_FILTER_MAC_PENDING,
			   &bp->sp_state, obj_type,
			   &bp->macs_pool);

	if (!CHIP_IS_E1x(bp))
		bnx2x_init_vlan_obj(bp, &bnx2x_sp_obj(bp, fp).vlan_obj,
				    fp->cl_id, fp->cid, BP_FUNC(bp),
				    bnx2x_sp(bp, vlan_rdata),
				    bnx2x_sp_mapping(bp, vlan_rdata),
				    BNX2X_FILTER_VLAN_PENDING,
				    &bp->sp_state, obj_type,
				    &bp->vlans_pool);
}

/**
@@ -1125,7 +1134,7 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp)
	bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp),
				   bnx2x_get_path_func_num(bp));

	bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_ABS_FUNC(bp)>>1,
	bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_FUNC(bp),
				    bnx2x_get_path_func_num(bp));

	/* RSS configuration object */
@@ -1135,6 +1144,8 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp)
				  bnx2x_sp_mapping(bp, rss_rdata),
				  BNX2X_FILTER_RSS_CONF_PENDING, &bp->sp_state,
				  BNX2X_OBJ_TYPE_RX);

	bp->vlan_credit = PF_VLAN_CREDIT_E2(bp, bnx2x_get_path_func_num(bp));
}

static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
+232 −18
Original line number Diff line number Diff line
@@ -3067,7 +3067,7 @@ void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p)
	storm_memset_func_en(bp, p->func_id, 1);

	/* spq */
	if (p->func_flgs & FUNC_FLG_SPQ) {
	if (p->spq_active) {
		storm_memset_spq_addr(bp, p->spq_map, p->func_id);
		REG_WR(bp, XSEM_REG_FAST_MEMORY +
		       XSTORM_SPQ_PROD_OFFSET(p->func_id), p->spq_prod);
@@ -3283,7 +3283,6 @@ static void bnx2x_pf_init(struct bnx2x *bp)
{
	struct bnx2x_func_init_params func_init = {0};
	struct event_ring_data eq_data = { {0} };
	u16 flags;

	if (!CHIP_IS_E1x(bp)) {
		/* reset IGU PF statistics: MSIX + ATTN */
@@ -3300,15 +3299,7 @@ static void bnx2x_pf_init(struct bnx2x *bp)
				BP_FUNC(bp) : BP_VN(bp))*4, 0);
	}

	/* function setup flags */
	flags = (FUNC_FLG_STATS | FUNC_FLG_LEADING | FUNC_FLG_SPQ);

	/* This flag is relevant for E1x only.
	 * E2 doesn't have a TPA configuration in a function level.
	 */
	flags |= (bp->dev->features & NETIF_F_LRO) ? FUNC_FLG_TPA : 0;

	func_init.func_flgs = flags;
	func_init.spq_active = true;
	func_init.pf_id = BP_FUNC(bp);
	func_init.func_id = BP_FUNC(bp);
	func_init.spq_map = bp->spq_mapping;
@@ -5303,6 +5294,10 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
		else
			vlan_mac_obj = &bp->sp_objs[cid].mac_obj;

		break;
	case BNX2X_FILTER_VLAN_PENDING:
		DP(BNX2X_MSG_SP, "Got SETUP_VLAN completions\n");
		vlan_mac_obj = &bp->sp_objs[cid].vlan_obj;
		break;
	case BNX2X_FILTER_MCAST_PENDING:
		DP(BNX2X_MSG_SP, "Got SETUP_MCAST completions\n");
@@ -5617,7 +5612,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
		      BNX2X_STATE_DIAG):
		case (EVENT_RING_OPCODE_CLASSIFICATION_RULES |
		      BNX2X_STATE_CLOSING_WAIT4_HALT):
			DP(BNX2X_MSG_SP, "got (un)set mac ramrod\n");
			DP(BNX2X_MSG_SP, "got (un)set vlan/mac ramrod\n");
			bnx2x_handle_classification_eqe(bp, elem);
			break;

@@ -6205,6 +6200,11 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
		__set_bit(BNX2X_ACCEPT_MULTICAST, tx_accept_flags);
		__set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);

		if (bp->accept_any_vlan) {
			__set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
			__set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
		}

		break;
	case BNX2X_RX_MODE_ALLMULTI:
		__set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
@@ -6216,6 +6216,11 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
		__set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);

		if (bp->accept_any_vlan) {
			__set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
			__set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
		}

		break;
	case BNX2X_RX_MODE_PROMISC:
		/* According to definition of SI mode, iface in promisc mode
@@ -6236,18 +6241,15 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
		else
			__set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);

		__set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
		__set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);

		break;
	default:
		BNX2X_ERR("Unknown rx_mode: %d\n", rx_mode);
		return -EINVAL;
	}

	/* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
	if (rx_mode != BNX2X_RX_MODE_NONE) {
		__set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
		__set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
	}

	return 0;
}

@@ -8441,6 +8443,42 @@ int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac,
	return rc;
}

int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan,
		       struct bnx2x_vlan_mac_obj *obj, bool set,
		       unsigned long *ramrod_flags)
{
	int rc;
	struct bnx2x_vlan_mac_ramrod_params ramrod_param;

	memset(&ramrod_param, 0, sizeof(ramrod_param));

	/* Fill general parameters */
	ramrod_param.vlan_mac_obj = obj;
	ramrod_param.ramrod_flags = *ramrod_flags;

	/* Fill a user request section if needed */
	if (!test_bit(RAMROD_CONT, ramrod_flags)) {
		ramrod_param.user_req.u.vlan.vlan = vlan;
		/* Set the command: ADD or DEL */
		if (set)
			ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
		else
			ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_DEL;
	}

	rc = bnx2x_config_vlan_mac(bp, &ramrod_param);

	if (rc == -EEXIST) {
		/* Do not treat adding same vlan as error. */
		DP(BNX2X_MSG_SP, "Failed to schedule ADD operations: %d\n", rc);
		rc = 0;
	} else if (rc < 0) {
		BNX2X_ERR("%s VLAN failed\n", (set ? "Set" : "Del"));
	}

	return rc;
}

int bnx2x_del_all_macs(struct bnx2x *bp,
		       struct bnx2x_vlan_mac_obj *mac_obj,
		       int mac_type, bool wait_for_comp)
@@ -12140,6 +12178,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
	mutex_init(&bp->drv_info_mutex);
	sema_init(&bp->stats_lock, 1);
	bp->drv_info_mng_owner = false;
	INIT_LIST_HEAD(&bp->vlan_reg);

	INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
	INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -12658,6 +12697,169 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
	return vxlan_features_check(skb, features);
}

static int __bnx2x_vlan_configure_vid(struct bnx2x *bp, u16 vid, bool add)
{
	int rc;

	if (IS_PF(bp)) {
		unsigned long ramrod_flags = 0;

		__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
		rc = bnx2x_set_vlan_one(bp, vid, &bp->sp_objs->vlan_obj,
					add, &ramrod_flags);
	} else {
		rc = bnx2x_vfpf_update_vlan(bp, vid, bp->fp->index, add);
	}

	return rc;
}

int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp)
{
	struct bnx2x_vlan_entry *vlan;
	int rc = 0;

	if (!bp->vlan_cnt) {
		DP(NETIF_MSG_IFUP, "No need to re-configure vlan filters\n");
		return 0;
	}

	list_for_each_entry(vlan, &bp->vlan_reg, link) {
		/* Prepare for cleanup in case of errors */
		if (rc) {
			vlan->hw = false;
			continue;
		}

		if (!vlan->hw)
			continue;

		DP(NETIF_MSG_IFUP, "Re-configuring vlan 0x%04x\n", vlan->vid);

		rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true);
		if (rc) {
			BNX2X_ERR("Unable to configure VLAN %d\n", vlan->vid);
			vlan->hw = false;
			rc = -EINVAL;
			continue;
		}
	}

	return rc;
}

static int bnx2x_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
	struct bnx2x *bp = netdev_priv(dev);
	struct bnx2x_vlan_entry *vlan;
	bool hw = false;
	int rc = 0;

	if (!netif_running(bp->dev)) {
		DP(NETIF_MSG_IFUP,
		   "Ignoring VLAN configuration the interface is down\n");
		return -EFAULT;
	}

	DP(NETIF_MSG_IFUP, "Adding VLAN %d\n", vid);

	vlan = kmalloc(sizeof(*vlan), GFP_KERNEL);
	if (!vlan)
		return -ENOMEM;

	bp->vlan_cnt++;
	if (bp->vlan_cnt > bp->vlan_credit && !bp->accept_any_vlan) {
		DP(NETIF_MSG_IFUP, "Accept all VLAN raised\n");
		bp->accept_any_vlan = true;
		if (IS_PF(bp))
			bnx2x_set_rx_mode_inner(bp);
		else
			bnx2x_vfpf_storm_rx_mode(bp);
	} else if (bp->vlan_cnt <= bp->vlan_credit) {
		rc = __bnx2x_vlan_configure_vid(bp, vid, true);
		hw = true;
	}

	vlan->vid = vid;
	vlan->hw = hw;

	if (!rc) {
		list_add(&vlan->link, &bp->vlan_reg);
	} else {
		bp->vlan_cnt--;
		kfree(vlan);
	}

	DP(NETIF_MSG_IFUP, "Adding VLAN result %d\n", rc);

	return rc;
}

static int bnx2x_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
	struct bnx2x *bp = netdev_priv(dev);
	struct bnx2x_vlan_entry *vlan;
	int rc = 0;

	if (!netif_running(bp->dev)) {
		DP(NETIF_MSG_IFUP,
		   "Ignoring VLAN configuration the interface is down\n");
		return -EFAULT;
	}

	DP(NETIF_MSG_IFUP, "Removing VLAN %d\n", vid);

	if (!bp->vlan_cnt) {
		BNX2X_ERR("Unable to kill VLAN %d\n", vid);
		return -EINVAL;
	}

	list_for_each_entry(vlan, &bp->vlan_reg, link)
		if (vlan->vid == vid)
			break;

	if (vlan->vid != vid) {
		BNX2X_ERR("Unable to kill VLAN %d - not found\n", vid);
		return -EINVAL;
	}

	if (vlan->hw)
		rc = __bnx2x_vlan_configure_vid(bp, vid, false);

	list_del(&vlan->link);
	kfree(vlan);

	bp->vlan_cnt--;

	if (bp->vlan_cnt <= bp->vlan_credit && bp->accept_any_vlan) {
		/* Configure all non-configured entries */
		list_for_each_entry(vlan, &bp->vlan_reg, link) {
			if (vlan->hw)
				continue;

			rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true);
			if (rc) {
				BNX2X_ERR("Unable to config VLAN %d\n",
					  vlan->vid);
				continue;
			}
			DP(NETIF_MSG_IFUP, "HW configured for VLAN %d\n",
			   vlan->vid);
			vlan->hw = true;
		}
		DP(NETIF_MSG_IFUP, "Accept all VLAN Removed\n");
		bp->accept_any_vlan = false;
		if (IS_PF(bp))
			bnx2x_set_rx_mode_inner(bp);
		else
			bnx2x_vfpf_storm_rx_mode(bp);
	}

	DP(NETIF_MSG_IFUP, "Removing VLAN result %d\n", rc);

	return rc;
}

static const struct net_device_ops bnx2x_netdev_ops = {
	.ndo_open		= bnx2x_open,
	.ndo_stop		= bnx2x_close,
@@ -12671,6 +12873,8 @@ static const struct net_device_ops bnx2x_netdev_ops = {
	.ndo_fix_features	= bnx2x_fix_features,
	.ndo_set_features	= bnx2x_set_features,
	.ndo_tx_timeout		= bnx2x_tx_timeout,
	.ndo_vlan_rx_add_vid	= bnx2x_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= bnx2x_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= poll_bnx2x,
#endif
@@ -12881,6 +13085,16 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
		NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA;

	/* VF with OLD Hypervisor or old PF do not support filtering */
	if (IS_PF(bp)) {
		if (CHIP_IS_E1x(bp))
			bp->accept_any_vlan = true;
		else
			dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
	} else if (bp->acquire_resp.pfdev_info.pf_cap & PFVF_CAP_VLAN_FILTER) {
		dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
	}

	dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX;
	dev->features |= NETIF_F_HIGHDMA;

+252 −6
Original line number Diff line number Diff line
@@ -357,6 +357,23 @@ static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o)

	return vp->get(vp, 1);
}

static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
{
	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;

	if (!mp->get(mp, 1))
		return false;

	if (!vp->get(vp, 1)) {
		mp->put(mp, 1);
		return false;
	}

	return true;
}

static bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset)
{
	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
@@ -385,6 +402,22 @@ static bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o)
	return vp->put(vp, 1);
}

static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
{
	struct bnx2x_credit_pool_obj *mp = o->macs_pool;
	struct bnx2x_credit_pool_obj *vp = o->vlans_pool;

	if (!mp->put(mp, 1))
		return false;

	if (!vp->put(vp, 1)) {
		mp->get(mp, 1);
		return false;
	}

	return true;
}

/**
 * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock
 *
@@ -638,6 +671,26 @@ static int bnx2x_check_vlan_add(struct bnx2x *bp,
	return 0;
}

static int bnx2x_check_vlan_mac_add(struct bnx2x *bp,
				    struct bnx2x_vlan_mac_obj *o,
				   union bnx2x_classification_ramrod_data *data)
{
	struct bnx2x_vlan_mac_registry_elem *pos;

	DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n",
	   data->vlan_mac.mac, data->vlan_mac.vlan);

	list_for_each_entry(pos, &o->head, link)
		if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
		    (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
				  ETH_ALEN)) &&
		    (data->vlan_mac.is_inner_mac ==
		     pos->u.vlan_mac.is_inner_mac))
			return -EEXIST;

	return 0;
}

/* check_del() callbacks */
static struct bnx2x_vlan_mac_registry_elem *
	bnx2x_check_mac_del(struct bnx2x *bp,
@@ -672,6 +725,27 @@ static struct bnx2x_vlan_mac_registry_elem *
	return NULL;
}

static struct bnx2x_vlan_mac_registry_elem *
	bnx2x_check_vlan_mac_del(struct bnx2x *bp,
				 struct bnx2x_vlan_mac_obj *o,
				 union bnx2x_classification_ramrod_data *data)
{
	struct bnx2x_vlan_mac_registry_elem *pos;

	DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n",
	   data->vlan_mac.mac, data->vlan_mac.vlan);

	list_for_each_entry(pos, &o->head, link)
		if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
		    (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
			     ETH_ALEN)) &&
		    (data->vlan_mac.is_inner_mac ==
		     pos->u.vlan_mac.is_inner_mac))
			return pos;

	return NULL;
}

/* check_move() callback */
static bool bnx2x_check_move(struct bnx2x *bp,
			     struct bnx2x_vlan_mac_obj *src_o,
@@ -1038,6 +1112,96 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
					rule_cnt);
}

static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
				      struct bnx2x_vlan_mac_obj *o,
				      struct bnx2x_exeq_elem *elem,
				      int rule_idx, int cam_offset)
{
	struct bnx2x_raw_obj *raw = &o->raw;
	struct eth_classify_rules_ramrod_data *data =
		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
	int rule_cnt = rule_idx + 1;
	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
	bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
	u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
	u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
	u16 inner_mac;

	/* Reset the ramrod data buffer for the first rule */
	if (rule_idx == 0)
		memset(data, 0, sizeof(*data));

	/* Set a rule header */
	bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR,
				      &rule_entry->pair.header);

	/* Set VLAN and MAC themselves */
	rule_entry->pair.vlan = cpu_to_le16(vlan);
	bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
			      &rule_entry->pair.mac_mid,
			      &rule_entry->pair.mac_lsb, mac);
	inner_mac = elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac;
	rule_entry->pair.inner_mac = cpu_to_le16(inner_mac);
	/* MOVE: Add a rule that will add this MAC/VLAN to the target Queue */
	if (cmd == BNX2X_VLAN_MAC_MOVE) {
		struct bnx2x_vlan_mac_obj *target_obj;

		rule_entry++;
		rule_cnt++;

		/* Setup ramrod data */
		target_obj = elem->cmd_data.vlan_mac.target_obj;
		bnx2x_vlan_mac_set_cmd_hdr_e2(bp, target_obj,
					      true, CLASSIFY_RULE_OPCODE_PAIR,
					      &rule_entry->pair.header);

		/* Set a VLAN itself */
		rule_entry->pair.vlan = cpu_to_le16(vlan);
		bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
				      &rule_entry->pair.mac_mid,
				      &rule_entry->pair.mac_lsb, mac);
		rule_entry->pair.inner_mac = cpu_to_le16(inner_mac);
	}

	/* Set the ramrod data header */
	bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header,
					rule_cnt);
}

/**
 * bnx2x_set_one_vlan_mac_e1h -
 *
 * @bp:		device handle
 * @o:		bnx2x_vlan_mac_obj
 * @elem:	bnx2x_exeq_elem
 * @rule_idx:	rule_idx
 * @cam_offset:	cam_offset
 */
static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
				       struct bnx2x_vlan_mac_obj *o,
				       struct bnx2x_exeq_elem *elem,
				       int rule_idx, int cam_offset)
{
	struct bnx2x_raw_obj *raw = &o->raw;
	struct mac_configuration_cmd *config =
		(struct mac_configuration_cmd *)(raw->rdata);
	/* 57710 and 57711 do not support MOVE command,
	 * so it's either ADD or DEL
	 */
	bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
		true : false;

	/* Reset the ramrod data buffer */
	memset(config, 0, sizeof(*config));

	bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING,
				     cam_offset, add,
				     elem->cmd_data.vlan_mac.u.vlan_mac.mac,
				     elem->cmd_data.vlan_mac.u.vlan_mac.vlan,
				     ETH_VLAN_FILTER_CLASSIFY, config);
}

/**
 * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element
 *
@@ -1137,6 +1301,25 @@ static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan(
	return NULL;
}

static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac(
	struct bnx2x_exe_queue_obj *o,
	struct bnx2x_exeq_elem *elem)
{
	struct bnx2x_exeq_elem *pos;
	struct bnx2x_vlan_mac_ramrod_data *data =
		&elem->cmd_data.vlan_mac.u.vlan_mac;

	/* Check pending for execution commands */
	list_for_each_entry(pos, &o->exe_queue, link)
		if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data,
			    sizeof(*data)) &&
		    (pos->cmd_data.vlan_mac.cmd ==
		     elem->cmd_data.vlan_mac.cmd))
			return pos;

	return NULL;
}

/**
 * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed
 *
@@ -2044,6 +2227,68 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp,
	}
}

void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
			     struct bnx2x_vlan_mac_obj *vlan_mac_obj,
			     u8 cl_id, u32 cid, u8 func_id, void *rdata,
			     dma_addr_t rdata_mapping, int state,
			     unsigned long *pstate, bnx2x_obj_type type,
			     struct bnx2x_credit_pool_obj *macs_pool,
			     struct bnx2x_credit_pool_obj *vlans_pool)
{
	union bnx2x_qable_obj *qable_obj =
		(union bnx2x_qable_obj *)vlan_mac_obj;

	bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata,
				   rdata_mapping, state, pstate, type,
				   macs_pool, vlans_pool);

	/* CAM pool handling */
	vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac;
	vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac;
	/* CAM offset is relevant for 57710 and 57711 chips only which have a
	 * single CAM for both MACs and VLAN-MAC pairs. So the offset
	 * will be taken from MACs' pool object only.
	 */
	vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac;
	vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac;

	if (CHIP_IS_E1(bp)) {
		BNX2X_ERR("Do not support chips others than E2\n");
		BUG();
	} else if (CHIP_IS_E1H(bp)) {
		vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e1h;
		vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
		vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
		vlan_mac_obj->check_move        = bnx2x_check_move_always_err;
		vlan_mac_obj->ramrod_cmd        = RAMROD_CMD_ID_ETH_SET_MAC;

		/* Exe Queue */
		bnx2x_exe_queue_init(bp,
				     &vlan_mac_obj->exe_queue, 1, qable_obj,
				     bnx2x_validate_vlan_mac,
				     bnx2x_remove_vlan_mac,
				     bnx2x_optimize_vlan_mac,
				     bnx2x_execute_vlan_mac,
				     bnx2x_exeq_get_vlan_mac);
	} else {
		vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e2;
		vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
		vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
		vlan_mac_obj->check_move        = bnx2x_check_move;
		vlan_mac_obj->ramrod_cmd        =
			RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;

		/* Exe Queue */
		bnx2x_exe_queue_init(bp,
				     &vlan_mac_obj->exe_queue,
				     CLASSIFY_RULES_COUNT,
				     qable_obj, bnx2x_validate_vlan_mac,
				     bnx2x_remove_vlan_mac,
				     bnx2x_optimize_vlan_mac,
				     bnx2x_execute_vlan_mac,
				     bnx2x_exeq_get_vlan_mac);
	}
}
/* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
static inline void __storm_memset_mac_filters(struct bnx2x *bp,
			struct tstorm_eth_mac_filter_config *mac_filters,
@@ -3856,7 +4101,7 @@ static bool bnx2x_credit_pool_get_entry_always_true(
 * If credit is negative pool operations will always succeed (unlimited pool).
 *
 */
static inline void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p,
void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p,
			    int base, int credit)
{
	/* Zero the object first */
@@ -3936,9 +4181,9 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
		/* CAM credit is equaly divided between all active functions
		 * on the PATH.
		 */
		if ((func_num > 0)) {
		if (func_num > 0) {
			if (!CHIP_REV_IS_SLOW(bp))
				cam_sz = (MAX_MAC_CREDIT_E2 / func_num);
				cam_sz = PF_MAC_CREDIT_E2(bp, func_num);
			else
				cam_sz = BNX2X_CAM_SIZE_EMUL;

@@ -3968,8 +4213,9 @@ void bnx2x_init_vlan_credit_pool(struct bnx2x *bp,
		 * on the PATH.
		 */
		if (func_num > 0) {
			int credit = MAX_VLAN_CREDIT_E2 / func_num;
			bnx2x_init_credit_pool(p, func_id * credit, credit);
			int credit = PF_VLAN_CREDIT_E2(bp, func_num);

			bnx2x_init_credit_pool(p, -1/*unused for E2*/, credit);
		} else
			/* this should never happen! Block VLAN operations. */
			bnx2x_init_credit_pool(p, 0, 0);
Loading