|
@@ -60,6 +60,30 @@ void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv)
|
|
|
mutex_unlock(&bp->vf2pf_mutex);
|
|
|
}
|
|
|
|
|
|
+/* Finds a TLV by type in a TLV buffer; If found, returns pointer to the TLV */
|
|
|
+static void *bnx2x_search_tlv_list(struct bnx2x *bp, void *tlvs_list,
|
|
|
+ enum channel_tlvs req_tlv)
|
|
|
+{
|
|
|
+ struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
|
|
|
+
|
|
|
+ do {
|
|
|
+ if (tlv->type == req_tlv)
|
|
|
+ return tlv;
|
|
|
+
|
|
|
+ if (!tlv->length) {
|
|
|
+ BNX2X_ERR("Found TLV with length 0\n");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ tlvs_list += tlv->length;
|
|
|
+ tlv = (struct channel_tlv *)tlvs_list;
|
|
|
+ } while (tlv->type != CHANNEL_TLV_LIST_END);
|
|
|
+
|
|
|
+ DP(BNX2X_MSG_IOV, "TLV list does not contain %d TLV\n", req_tlv);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
/* list the types and lengths of the tlvs on the buffer */
|
|
|
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
|
|
|
{
|
|
@@ -196,6 +220,7 @@ 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;
|
|
|
+ struct vfpf_port_phys_id_resp_tlv *phys_port_resp;
|
|
|
u32 vf_id;
|
|
|
bool resources_acquired = false;
|
|
|
|
|
@@ -219,8 +244,14 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
|
|
|
/* pf 2 vf bulletin board address */
|
|
|
req->bulletin_addr = bp->pf2vf_bulletin_mapping;
|
|
|
|
|
|
+ /* Request physical port identifier */
|
|
|
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length,
|
|
|
+ CHANNEL_TLV_PHYS_PORT_ID, sizeof(struct channel_tlv));
|
|
|
+
|
|
|
/* add list termination tlv */
|
|
|
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
|
|
|
+ bnx2x_add_tlv(bp, req,
|
|
|
+ req->first_tlv.tl.length + sizeof(struct channel_tlv),
|
|
|
+ CHANNEL_TLV_LIST_END,
|
|
|
sizeof(struct channel_list_end_tlv));
|
|
|
|
|
|
/* output tlvs list */
|
|
@@ -287,6 +318,15 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* Retrieve physical port id (if possible) */
|
|
|
+ phys_port_resp = (struct vfpf_port_phys_id_resp_tlv *)
|
|
|
+ bnx2x_search_tlv_list(bp, resp,
|
|
|
+ CHANNEL_TLV_PHYS_PORT_ID);
|
|
|
+ if (phys_port_resp) {
|
|
|
+ memcpy(bp->phys_port_id, phys_port_resp->id, ETH_ALEN);
|
|
|
+ bp->flags |= HAS_PHYS_PORT_ID;
|
|
|
+ }
|
|
|
+
|
|
|
/* get HW info */
|
|
|
bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
|
|
|
bp->link_params.chip_id = bp->common.chip_id;
|
|
@@ -983,53 +1023,59 @@ static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
|
|
|
return bnx2x_issue_dmae_with_comp(bp, &dmae);
|
|
|
}
|
|
|
|
|
|
-static void bnx2x_vf_mbx_resp(struct bnx2x *bp, struct bnx2x_virtf *vf)
|
|
|
+static void bnx2x_vf_mbx_resp_single_tlv(struct bnx2x *bp,
|
|
|
+ struct bnx2x_virtf *vf)
|
|
|
{
|
|
|
struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
|
|
|
- u64 vf_addr;
|
|
|
- dma_addr_t pf_addr;
|
|
|
u16 length, type;
|
|
|
- int rc;
|
|
|
- struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
|
|
|
|
|
|
/* prepare response */
|
|
|
type = mbx->first_tlv.tl.type;
|
|
|
length = type == CHANNEL_TLV_ACQUIRE ?
|
|
|
sizeof(struct pfvf_acquire_resp_tlv) :
|
|
|
sizeof(struct pfvf_general_resp_tlv);
|
|
|
- bnx2x_add_tlv(bp, resp, 0, type, length);
|
|
|
- resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
|
|
|
- bnx2x_add_tlv(bp, resp, length, CHANNEL_TLV_LIST_END,
|
|
|
+ bnx2x_add_tlv(bp, &mbx->msg->resp, 0, type, length);
|
|
|
+ bnx2x_add_tlv(bp, &mbx->msg->resp, length, CHANNEL_TLV_LIST_END,
|
|
|
sizeof(struct channel_list_end_tlv));
|
|
|
+}
|
|
|
+
|
|
|
+static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
|
|
|
+ struct bnx2x_virtf *vf)
|
|
|
+{
|
|
|
+ struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
|
|
|
+ struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
|
|
|
+ dma_addr_t pf_addr;
|
|
|
+ u64 vf_addr;
|
|
|
+ int rc;
|
|
|
+
|
|
|
bnx2x_dp_tlv_list(bp, resp);
|
|
|
DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
|
|
|
mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
|
|
|
|
|
|
+ resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
|
|
|
+
|
|
|
/* send response */
|
|
|
vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
|
|
|
mbx->first_tlv.resp_msg_offset;
|
|
|
pf_addr = mbx->msg_mapping +
|
|
|
offsetof(struct bnx2x_vf_mbx_msg, resp);
|
|
|
|
|
|
- /* copy the response body, if there is one, before the header, as the vf
|
|
|
- * is sensitive to the header being written
|
|
|
+ /* Copy the response buffer. The first u64 is written afterwards, as
|
|
|
+ * the vf is sensitive to the header being written
|
|
|
*/
|
|
|
- if (resp->hdr.tl.length > sizeof(u64)) {
|
|
|
- length = resp->hdr.tl.length - sizeof(u64);
|
|
|
- vf_addr += sizeof(u64);
|
|
|
- pf_addr += sizeof(u64);
|
|
|
- rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
|
|
|
- U64_HI(vf_addr),
|
|
|
- U64_LO(vf_addr),
|
|
|
- length/4);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("Failed to copy response body to VF %d\n",
|
|
|
- vf->abs_vfid);
|
|
|
- goto mbx_error;
|
|
|
- }
|
|
|
- vf_addr -= sizeof(u64);
|
|
|
- pf_addr -= sizeof(u64);
|
|
|
+ vf_addr += sizeof(u64);
|
|
|
+ pf_addr += sizeof(u64);
|
|
|
+ rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
|
|
|
+ U64_HI(vf_addr),
|
|
|
+ U64_LO(vf_addr),
|
|
|
+ (sizeof(union pfvf_tlvs) - sizeof(u64))/4);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Failed to copy response body to VF %d\n",
|
|
|
+ vf->abs_vfid);
|
|
|
+ goto mbx_error;
|
|
|
}
|
|
|
+ vf_addr -= sizeof(u64);
|
|
|
+ pf_addr -= sizeof(u64);
|
|
|
|
|
|
/* ack the FW */
|
|
|
storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
|
|
@@ -1060,6 +1106,36 @@ mbx_error:
|
|
|
bnx2x_vf_release(bp, vf, false); /* non blocking */
|
|
|
}
|
|
|
|
|
|
+static void bnx2x_vf_mbx_resp(struct bnx2x *bp,
|
|
|
+ struct bnx2x_virtf *vf)
|
|
|
+{
|
|
|
+ bnx2x_vf_mbx_resp_single_tlv(bp, vf);
|
|
|
+ bnx2x_vf_mbx_resp_send_msg(bp, vf);
|
|
|
+}
|
|
|
+
|
|
|
+static void bnx2x_vf_mbx_resp_phys_port(struct bnx2x *bp,
|
|
|
+ struct bnx2x_virtf *vf,
|
|
|
+ void *buffer,
|
|
|
+ u16 *offset)
|
|
|
+{
|
|
|
+ struct vfpf_port_phys_id_resp_tlv *port_id;
|
|
|
+
|
|
|
+ if (!(bp->flags & HAS_PHYS_PORT_ID))
|
|
|
+ return;
|
|
|
+
|
|
|
+ bnx2x_add_tlv(bp, buffer, *offset, CHANNEL_TLV_PHYS_PORT_ID,
|
|
|
+ sizeof(struct vfpf_port_phys_id_resp_tlv));
|
|
|
+
|
|
|
+ port_id = (struct vfpf_port_phys_id_resp_tlv *)
|
|
|
+ (((u8 *)buffer) + *offset);
|
|
|
+ memcpy(port_id->id, bp->phys_port_id, ETH_ALEN);
|
|
|
+
|
|
|
+ /* Offset should continue representing the offset to the tail
|
|
|
+ * of TLV data (outside this function scope)
|
|
|
+ */
|
|
|
+ *offset += sizeof(struct vfpf_port_phys_id_resp_tlv);
|
|
|
+}
|
|
|
+
|
|
|
static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|
|
struct bnx2x_vf_mbx *mbx, int vfop_status)
|
|
|
{
|
|
@@ -1067,6 +1143,7 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|
|
struct pfvf_acquire_resp_tlv *resp = &mbx->msg->resp.acquire_resp;
|
|
|
struct pf_vf_resc *resc = &resp->resc;
|
|
|
u8 status = bnx2x_pfvf_status_codes(vfop_status);
|
|
|
+ u16 length;
|
|
|
|
|
|
memset(resp, 0, sizeof(*resp));
|
|
|
|
|
@@ -1140,9 +1217,24 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|
|
resc->hw_sbs[i].sb_qid);
|
|
|
DP_CONT(BNX2X_MSG_IOV, "]\n");
|
|
|
|
|
|
+ /* prepare response */
|
|
|
+ length = sizeof(struct pfvf_acquire_resp_tlv);
|
|
|
+ bnx2x_add_tlv(bp, &mbx->msg->resp, 0, CHANNEL_TLV_ACQUIRE, length);
|
|
|
+
|
|
|
+ /* Handle possible VF requests for physical port identifiers.
|
|
|
+ * 'length' should continue to indicate the offset of the first empty
|
|
|
+ * place in the buffer (i.e., where next TLV should be inserted)
|
|
|
+ */
|
|
|
+ if (bnx2x_search_tlv_list(bp, &mbx->msg->req,
|
|
|
+ CHANNEL_TLV_PHYS_PORT_ID))
|
|
|
+ bnx2x_vf_mbx_resp_phys_port(bp, vf, &mbx->msg->resp, &length);
|
|
|
+
|
|
|
+ bnx2x_add_tlv(bp, &mbx->msg->resp, length, CHANNEL_TLV_LIST_END,
|
|
|
+ sizeof(struct channel_list_end_tlv));
|
|
|
+
|
|
|
/* send the response */
|
|
|
vf->op_rc = vfop_status;
|
|
|
- bnx2x_vf_mbx_resp(bp, vf);
|
|
|
+ bnx2x_vf_mbx_resp_send_msg(bp, vf);
|
|
|
}
|
|
|
|
|
|
static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
|
|
@@ -1874,6 +1966,9 @@ void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
|
|
|
/* process the VF message header */
|
|
|
mbx->first_tlv = mbx->msg->req.first_tlv;
|
|
|
|
|
|
+ /* Clean response buffer to refrain from falsely seeing chains */
|
|
|
+ memset(&mbx->msg->resp, 0, sizeof(union pfvf_tlvs));
|
|
|
+
|
|
|
/* dispatch the request (will prepare the response) */
|
|
|
bnx2x_vf_mbx_request(bp, vf, mbx);
|
|
|
goto mbx_done;
|