From 954ea7480b11e67266c760c8c67fc337a3a6d5b9 Mon Sep 17 00:00:00 2001 From: Ariel Elior Date: Tue, 1 Jan 2013 05:22:38 +0000 Subject: 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: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 277 +++++++++++++++++++++++ 1 file changed, 277 insertions(+) (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 6605567..ad92bf4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -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: + bnx2x_vfop_default(state); + } +} + +static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vfop_cmd *cmd) +{ + struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); + if (vfop) { + bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS, + bnx2x_vfop_mbx_qfilters, cmd->done); + return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters, + cmd->block); + } + return -ENOMEM; +} + +static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vf_mbx *mbx) +{ + struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters; + struct bnx2x_vfop_cmd cmd = { + .done = bnx2x_vf_mbx_resp, + .block = false, + }; + + /* verify vf_qid */ + if (filters->vf_qid > vf_rxq_count(vf)) + goto response; + + DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n", + vf->abs_vfid, + filters->vf_qid); + + /* print q_filter message */ + bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters); + + vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd); + if (vf->op_rc) + goto response; + return; + +response: + bnx2x_vf_mbx_resp(bp, vf); +} + /* dispatch request */ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vf_mbx *mbx) @@ -537,6 +811,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, case CHANNEL_TLV_SETUP_Q: bnx2x_vf_mbx_setup_q(bp, vf, mbx); break; + case CHANNEL_TLV_SET_Q_FILTERS: + bnx2x_vf_mbx_set_q_filters(bp, vf, mbx); + break; } } else { /* unknown TLV - this may belong to a VF driver from the future -- cgit v1.1