Commit 954ea748 authored by Ariel Elior's avatar Ariel Elior Committed by David S. Miller
Browse files

bnx2x: Support of PF driver of a VF q_filters request



The VF driver uses the 'q_filters' message on the VF <-> PF channel
for configuring an open queue, for example when the rxmode changes.
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8db573ba
......@@ -102,6 +102,8 @@ static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
}
/* VFOP - VF slow-path operation support */
#define BNX2X_VFOP_FILTER_ADD_CNT_MAX 0x10000
/* VFOP operations states */
enum bnx2x_vfop_qctor_state {
BNX2X_VFOP_QCTOR_INIT,
......@@ -124,6 +126,17 @@ enum bnx2x_vfop_qsetup_state {
BNX2X_VFOP_QSETUP_DONE
};
enum bnx2x_vfop_mcast_state {
BNX2X_VFOP_MCAST_DEL,
BNX2X_VFOP_MCAST_ADD,
BNX2X_VFOP_MCAST_CHK_DONE
};
enum bnx2x_vfop_rxmode_state {
BNX2X_VFOP_RXMODE_CONFIG,
BNX2X_VFOP_RXMODE_DONE
};
#define bnx2x_vfop_reset_wq(vf) atomic_set(&vf->op_in_progress, 0)
void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
......@@ -572,6 +585,57 @@ bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
}
static inline void
bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
struct bnx2x_vfop_vlan_mac_flags *flags)
{
bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
}
int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
struct bnx2x_vfop_filters *macs,
int qid, bool drv_only)
{
struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
struct bnx2x_vfop_args_filters filters = {
.multi_filter = macs,
.credit = NULL, /* consume credit */
};
struct bnx2x_vfop_vlan_mac_flags flags = {
.drv_only = drv_only,
.dont_consume = (filters.credit != NULL),
.single_cmd = false,
.add = false, /* don't care since only the items in the
* filters list affect the sp operation,
* not the list itself
*/
};
struct bnx2x_vlan_mac_ramrod_params *ramrod =
&vf->op_params.vlan_mac;
/* set ramrod params */
bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
/* set object */
ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
/* set extra args */
filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
vfop->args.filters = filters;
bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
bnx2x_vfop_vlan_mac, cmd->done);
return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
cmd->block);
}
return -ENOMEM;
}
int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
......@@ -611,6 +675,48 @@ int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
return -ENOMEM;
}
int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
struct bnx2x_vfop_filters *vlans,
int qid, bool drv_only)
{
struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
struct bnx2x_vfop_args_filters filters = {
.multi_filter = vlans,
.credit = &bnx2x_vfq(vf, qid, vlan_count),
};
struct bnx2x_vfop_vlan_mac_flags flags = {
.drv_only = drv_only,
.dont_consume = (filters.credit != NULL),
.single_cmd = false,
.add = false, /* don't care */
};
struct bnx2x_vlan_mac_ramrod_params *ramrod =
&vf->op_params.vlan_mac;
/* set ramrod params */
bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
/* set object */
ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
/* set extra args */
filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
atomic_read(filters.credit);
vfop->args.filters = filters;
bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
bnx2x_vfop_vlan_mac, cmd->done);
return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
cmd->block);
}
return -ENOMEM;
}
/* VFOP queue setup (queue constructor + set vlan 0) */
static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
......@@ -676,6 +782,180 @@ int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
return -ENOMEM;
}
/* VFOP multi-casts */
static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
enum bnx2x_vfop_mcast_state state = vfop->state;
int i;
bnx2x_vfop_reset_wq(vf);
if (vfop->rc < 0)
goto op_err;
DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
switch (state) {
case BNX2X_VFOP_MCAST_DEL:
/* clear existing mcasts */
vfop->state = BNX2X_VFOP_MCAST_ADD;
vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
case BNX2X_VFOP_MCAST_ADD:
if (raw->check_pending(raw))
goto op_pending;
if (args->mc_num) {
/* update mcast list on the ramrod params */
INIT_LIST_HEAD(&mcast->mcast_list);
for (i = 0; i < args->mc_num; i++)
list_add_tail(&(args->mc[i].link),
&mcast->mcast_list);
/* add new mcasts */
vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
vfop->rc = bnx2x_config_mcast(bp, mcast,
BNX2X_MCAST_CMD_ADD);
}
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
case BNX2X_VFOP_MCAST_CHK_DONE:
vfop->rc = raw->check_pending(raw) ? 1 : 0;
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
default:
bnx2x_vfop_default(state);
}
op_err:
BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
op_done:
kfree(args->mc);
bnx2x_vfop_end(bp, vf, vfop);
op_pending:
return;
}
int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
bnx2x_mac_addr_t *mcasts,
int mcast_num, bool drv_only)
{
struct bnx2x_vfop *vfop = NULL;
size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
NULL;
if (!mc_sz || mc) {
vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
int i;
struct bnx2x_mcast_ramrod_params *ramrod =
&vf->op_params.mcast;
/* set ramrod params */
memset(ramrod, 0, sizeof(*ramrod));
ramrod->mcast_obj = &vf->mcast_obj;
if (drv_only)
set_bit(RAMROD_DRV_CLR_ONLY,
&ramrod->ramrod_flags);
/* copy mcasts pointers */
vfop->args.mc_list.mc_num = mcast_num;
vfop->args.mc_list.mc = mc;
for (i = 0; i < mcast_num; i++)
mc[i].mac = mcasts[i];
bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
bnx2x_vfop_mcast, cmd->done);
return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
cmd->block);
} else {
kfree(mc);
}
}
return -ENOMEM;
}
/* VFOP rx-mode */
static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
enum bnx2x_vfop_rxmode_state state = vfop->state;
bnx2x_vfop_reset_wq(vf);
if (vfop->rc < 0)
goto op_err;
DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
switch (state) {
case BNX2X_VFOP_RXMODE_CONFIG:
/* next state */
vfop->state = BNX2X_VFOP_RXMODE_DONE;
vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
op_err:
BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
op_done:
case BNX2X_VFOP_RXMODE_DONE:
bnx2x_vfop_end(bp, vf, vfop);
return;
default:
bnx2x_vfop_default(state);
}
op_pending:
return;
}
int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
int qid, unsigned long accept_flags)
{
struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
if (vfop) {
struct bnx2x_rx_mode_ramrod_params *ramrod =
&vf->op_params.rx_mode;
memset(ramrod, 0, sizeof(*ramrod));
/* Prepare ramrod parameters */
ramrod->cid = vfq->cid;
ramrod->cl_id = vfq_cl_id(vf, vfq);
ramrod->rx_mode_obj = &bp->rx_mode_obj;
ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
ramrod->rx_accept_flags = accept_flags;
ramrod->tx_accept_flags = accept_flags;
ramrod->pstate = &vf->filter_state;
ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
set_bit(RAMROD_RX, &ramrod->ramrod_flags);
set_bit(RAMROD_TX, &ramrod->ramrod_flags);
ramrod->rdata =
bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
ramrod->rdata_mapping =
bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
bnx2x_vfop_rxmode, cmd->done);
return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
cmd->block);
}
return -ENOMEM;
}
/* VF enable primitives
* when pretend is required the caller is responsible
* for calling pretend prior to calling these routines
......
......@@ -441,6 +441,10 @@ void bnx2x_iov_sp_task(struct bnx2x *bp);
/* global vf mailbox routines */
void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
/* CORE VF API */
typedef u8 bnx2x_mac_addr_t[ETH_ALEN];
/* acquire */
int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct vf_pf_resc_request *resc);
......@@ -615,11 +619,39 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
struct bnx2x_vf_queue *q,
struct bnx2x_vfop_qctor_params *p,
unsigned long q_type);
int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
struct bnx2x_vfop_filters *macs,
int qid, bool drv_only);
int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
int qid, u16 vid, bool add);
int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
struct bnx2x_vfop_filters *vlans,
int qid, bool drv_only);
int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
int qid);
int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
bnx2x_mac_addr_t *mcasts,
int mcast_num, bool drv_only);
int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct bnx2x_vfop_cmd *cmd,
int qid, unsigned long accept_flags);
int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
/* VF FLR helpers */
......
......@@ -513,6 +513,280 @@ response:
bnx2x_vf_mbx_resp(bp, vf);
}
enum bnx2x_vfop_filters_state {
BNX2X_VFOP_MBX_Q_FILTERS_MACS,
BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
BNX2X_VFOP_MBX_Q_FILTERS_DONE
};
static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
struct bnx2x_virtf *vf,
struct vfpf_set_q_filters_tlv *tlv,
struct bnx2x_vfop_filters **pfl,
u32 type_flag)
{
int i, j;
struct bnx2x_vfop_filters *fl = NULL;
size_t fsz;
fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
sizeof(struct bnx2x_vfop_filters);
fl = kzalloc(fsz, GFP_KERNEL);
if (!fl)
return -ENOMEM;
INIT_LIST_HEAD(&fl->head);
for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
if ((msg_filter->flags & type_flag) != type_flag)
continue;
if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
fl->filters[j].mac = msg_filter->mac;
fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
} else {
fl->filters[j].vid = msg_filter->vlan_tag;
fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
}
fl->filters[j].add =
(msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
true : false;
list_add_tail(&fl->filters[j++].link, &fl->head);
}
if (list_empty(&fl->head))
kfree(fl);
else
*pfl = fl;
return 0;
}
static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx,
struct vfpf_q_mac_vlan_filter *filter)
{
DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags);
if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag);
if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
DP_CONT(msglvl, ", MAC=%pM", filter->mac);
DP_CONT(msglvl, "\n");
}
static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
struct vfpf_set_q_filters_tlv *filters)
{
int i;
if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED)
for (i = 0; i < filters->n_mac_vlan_filters; i++)
bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
&filters->filters[i]);
if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED)
for (i = 0; i < filters->n_multicast; i++)
DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
}
#define VFPF_MAC_FILTER VFPF_Q_FILTER_DEST_MAC_VALID
#define VFPF_VLAN_FILTER VFPF_Q_FILTER_VLAN_TAG_VALID
static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
int rc;
struct vfpf_set_q_filters_tlv *msg =
&BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
enum bnx2x_vfop_filters_state state = vfop->state;
struct bnx2x_vfop_cmd cmd = {
.done = bnx2x_vfop_mbx_qfilters,
.block = false,
};
DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
if (vfop->rc < 0)
goto op_err;
switch (state) {
case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
/* next state */
vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
/* check for any vlan/mac changes */
if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
/* build mac list */
struct bnx2x_vfop_filters *fl = NULL;
vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
VFPF_MAC_FILTER);
if (vfop->rc)
goto op_err;
if (fl) {
/* set mac list */
rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
msg->vf_qid,
false);
if (rc) {
vfop->rc = rc;
goto op_err;
}
return;
}
}
/* fall through */
case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
/* next state */
vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
/* check for any vlan/mac changes */
if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
/* build vlan list */
struct bnx2x_vfop_filters *fl = NULL;
vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
VFPF_VLAN_FILTER);
if (vfop->rc)
goto op_err;
if (fl) {
/* set vlan list */
rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
msg->vf_qid,
false);
if (rc) {
vfop->rc = rc;
goto op_err;
}
return;
}
}
/* fall through */
case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
/* next state */
vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
unsigned long accept = 0;
/* covert VF-PF if mask to bnx2x accept flags */
if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
__set_bit(BNX2X_ACCEPT_UNICAST, &accept);
if (msg->rx_mask &
VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
__set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
__set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
__set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
/* A packet arriving the vf's mac should be accepted
* with any vlan
*/
__set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
/* set rx-mode */
rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
msg->vf_qid, accept);
if (rc) {
vfop->rc = rc;
goto op_err;
}
return;
}
/* fall through */
case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
/* next state */
vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
/* set mcasts */
rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
msg->n_multicast, false);
if (rc) {
vfop->rc = rc;
goto op_err;
}
return;
}
/* fall through */
op_done:
case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
bnx2x_vfop_end(bp, vf, vfop);
return;
op_err:
BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
vf->abs_vfid, msg->vf_qid, vfop->rc);
goto op_done;
default: