/* CLOSE VF - opposite to INIT_VF */ void bnx2x_vfpf_close_vf(struct bnx2x *bp) { struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int i, rc; u32 vf_id; /* If we haven't got a valid VF id, there is no sense to * continue with sending messages */ if (bnx2x_get_vf_id(bp, &vf_id)) goto free_irq; /* Close the queues */ for_each_queue(bp, i) bnx2x_vfpf_teardown_queue(bp, i); /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req)); req->vf_id = vf_id; /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc); else if (resp->hdr.status != PFVF_STATUS_SUCCESS) BNX2X_ERR("Sending CLOSE failed: pf response was %d\n", resp->hdr.status); bnx2x_vfpf_finalize(bp, &req->first_tlv); free_irq: /* Disable HW interrupts, NAPI */ bnx2x_netif_stop(bp, 0); /* Delete all NAPI objects */ bnx2x_del_all_napi(bp); /* Release IRQs */ bnx2x_free_irq(bp); }
/* Clear the mailbox and init the header of the first tlv */ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, u16 type, u16 length) { DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n", type); /* Clear mailbox */ memset(bp->vf2pf_mbox, 0, sizeof(struct bnx2x_vf_mbx_msg)); /* init type and length */ bnx2x_add_tlv(bp, &first_tlv->tl, 0, type, length); /* init first tlv header */ first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req); }
int bnx2x_vfpf_release(struct bnx2x *bp) { struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; u32 rc, vf_id; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req)); if (bnx2x_get_vf_id(bp, &vf_id)) { rc = -EAGAIN; goto out; } req->vf_id = vf_id; /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); /* send release request */ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) /* PF timeout */ goto out; if (resp->hdr.status == PFVF_STATUS_SUCCESS) { /* PF released us */ DP(BNX2X_MSG_SP, "vf released\n"); } else { /* PF reports error */ BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n", resp->hdr.status); rc = -EAGAIN; goto out; } out: bnx2x_vfpf_finalize(bp, &req->first_tlv); return rc; }
/* Tell PF about SB addresses */ int bnx2x_vfpf_init(struct bnx2x *bp) { struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int rc, i; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req)); /* status blocks */ for_each_eth_queue(bp, i) req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i, status_blk_mapping); /* statistics - requests only supports single queue for now */ req->stats_addr = bp->fw_stats_data_mapping + offsetof(struct bnx2x_fw_stats_data, queue_stats); /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) goto out; if (resp->hdr.status != PFVF_STATUS_SUCCESS) { BNX2X_ERR("INIT VF failed: %d. Breaking...\n", resp->hdr.status); rc = -EAGAIN; goto out; } DP(BNX2X_MSG_SP, "INIT VF Succeeded\n"); out: bnx2x_vfpf_finalize(bp, &req->first_tlv); return rc; }
int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) { struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int rc; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q, sizeof(*req)); req->vf_qid = qidx; /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) { BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx, rc); goto out; } /* PF failed the transaction */ if (resp->hdr.status != PFVF_STATUS_SUCCESS) { BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx, resp->hdr.status); rc = -EINVAL; } out: bnx2x_vfpf_finalize(bp, &req->first_tlv); return rc; }
/* request pf to add a mac for the vf */ int bnx2x_vfpf_set_mac(struct bnx2x *bp) { struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; int rc = 0; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS, sizeof(*req)); req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED; req->vf_qid = 0; req->n_mac_vlan_filters = 1; req->filters[0].flags = VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC; /* sample bulletin board for new mac */ bnx2x_sample_bulletin(bp); /* copy mac from device to request */ memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN); /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); /* send message to pf */ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) { BNX2X_ERR("failed to send message to pf. rc was %d\n", rc); goto out; } /* failure may mean PF was configured with a new mac for us */ while (resp->hdr.status == PFVF_STATUS_FAILURE) { DP(BNX2X_MSG_IOV, "vfpf SET MAC failed. Check bulletin board for new posts\n"); /* check if bulletin board was updated */ if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) { /* copy mac from device to request */ memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN); /* send message to pf */ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); } else { /* no new info in bulletin */ break; } } if (resp->hdr.status != PFVF_STATUS_SUCCESS) { BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status); rc = -EINVAL; } out: bnx2x_vfpf_finalize(bp, &req->first_tlv); return 0; }
/* ask the pf to open a queue for the vf */ int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) { struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; struct bnx2x_fastpath *fp = &bp->fp[fp_idx]; u16 tpa_agg_size = 0, flags = 0; int rc; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req)); /* select tpa mode to request */ if (!fp->disable_tpa) { flags |= VFPF_QUEUE_FLG_TPA; flags |= VFPF_QUEUE_FLG_TPA_IPV6; if (fp->mode == TPA_MODE_GRO) flags |= VFPF_QUEUE_FLG_TPA_GRO; tpa_agg_size = TPA_AGG_SIZE; } /* calculate queue flags */ flags |= VFPF_QUEUE_FLG_STATS; flags |= VFPF_QUEUE_FLG_CACHE_ALIGN; flags |= VFPF_QUEUE_FLG_VLAN; DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); /* Common */ req->vf_qid = fp_idx; req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID; /* Rx */ req->rxq.rcq_addr = fp->rx_comp_mapping; req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE; req->rxq.rxq_addr = fp->rx_desc_mapping; req->rxq.sge_addr = fp->rx_sge_mapping; req->rxq.vf_sb = fp_idx; req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS; req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0; req->rxq.mtu = bp->dev->mtu; req->rxq.buf_sz = fp->rx_buf_size; req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE; req->rxq.tpa_agg_sz = tpa_agg_size; req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT; req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT; req->rxq.flags = flags; req->rxq.drop_flags = 0; req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT; req->rxq.stat_id = -1; /* No stats at the moment */ /* Tx */ req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping; req->txq.vf_sb = fp_idx; req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0; req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0; req->txq.flags = flags; req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW; /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); if (rc) BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n", fp_idx); if (resp->hdr.status != PFVF_STATUS_SUCCESS) { BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n", fp_idx, resp->hdr.status); rc = -EINVAL; } bnx2x_vfpf_finalize(bp, &req->first_tlv); return rc; }
int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) { int rc = 0, attempts = 0; struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire; struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp; u32 vf_id; bool resources_acquired = false; /* clear mailbox and prep first tlv */ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req)); if (bnx2x_get_vf_id(bp, &vf_id)) { rc = -EAGAIN; goto out; } req->vfdev_info.vf_id = vf_id; req->vfdev_info.vf_os = 0; req->resc_request.num_rxqs = rx_count; req->resc_request.num_txqs = tx_count; req->resc_request.num_sbs = bp->igu_sb_cnt; req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS; req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS; /* pf 2 vf bulletin board address */ req->bulletin_addr = bp->pf2vf_bulletin_mapping; /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); /* output tlvs list */ bnx2x_dp_tlv_list(bp, req); while (!resources_acquired) { DP(BNX2X_MSG_SP, "attempting to acquire resources\n"); /* send acquire request */ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); /* PF timeout */ if (rc) goto out; /* copy acquire response from buffer to bp */ memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp)); attempts++; /* test whether the PF accepted our request. If not, humble the * the request and try again. */ if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) { DP(BNX2X_MSG_SP, "resources acquired\n"); resources_acquired = true; } else if (bp->acquire_resp.hdr.status == PFVF_STATUS_NO_RESOURCE && attempts < VF_ACQUIRE_THRESH) { DP(BNX2X_MSG_SP, "PF unwilling to fulfill resource request. Try PF recommended amount\n"); /* humble our request */ req->resc_request.num_txqs = bp->acquire_resp.resc.num_txqs; req->resc_request.num_rxqs = bp->acquire_resp.resc.num_rxqs; req->resc_request.num_sbs = bp->acquire_resp.resc.num_sbs; req->resc_request.num_mac_filters = bp->acquire_resp.resc.num_mac_filters; req->resc_request.num_vlan_filters = bp->acquire_resp.resc.num_vlan_filters; req->resc_request.num_mc_filters = bp->acquire_resp.resc.num_mc_filters; /* Clear response buffer */ memset(&bp->vf2pf_mbox->resp, 0, sizeof(union pfvf_tlvs)); } else { /* PF reports error */ BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n", bp->acquire_resp.hdr.status); rc = -EAGAIN; goto out; } } /* get HW info */ bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff); bp->link_params.chip_id = bp->common.chip_id; bp->db_size = bp->acquire_resp.pfdev_info.db_size; bp->common.int_block = INT_BLOCK_IGU; bp->common.chip_port_mode = CHIP_2_PORT_MODE; bp->igu_dsb_id = -1; bp->mf_ov = 0; bp->mf_mode = 0; bp->common.flash_size = 0; bp->flags |= NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG; bp->igu_sb_cnt = 1; bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id; strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver, sizeof(bp->fw_ver)); if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr)) memcpy(bp->dev->dev_addr, bp->acquire_resp.resc.current_mac_addr, ETH_ALEN); out: bnx2x_vfpf_finalize(bp, &req->first_tlv); return rc; }