bnx2x: Add ndo_get_phys_port_id support
authorYuval Mintz <yuvalmin@broadcom.com>
Wed, 9 Oct 2013 14:06:28 +0000 (16:06 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 9 Oct 2013 18:55:13 +0000 (14:55 -0400)
Each network interface (either PF or VF) is identified by its port's MAC id.

Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h

index 8fe4bcb2407d999d9693cbd63820ffe8ec0be607..5fb18cd99da20cd6a6dbe5798eaba8aa7357aa80 100644 (file)
@@ -1546,6 +1546,7 @@ struct bnx2x {
 #define IS_VF_FLAG                     (1 << 22)
 #define INTERRUPTS_ENABLED_FLAG                (1 << 23)
 #define BC_SUPPORTS_RMMOD_CMD          (1 << 24)
+#define HAS_PHYS_PORT_ID               (1 << 25)
 
 #define BP_NOMCP(bp)                   ((bp)->flags & NO_MCP_FLAG)
 
@@ -1876,6 +1877,8 @@ struct bnx2x {
        u32 dump_preset_idx;
        bool                                    stats_started;
        struct semaphore                        stats_sema;
+
+       u8                                      phys_port_id[ETH_ALEN];
 };
 
 /* Tx queues may be less or equal to Rx queues */
index 13a569460ef27fc55573f437c9197ecbf5fda1c6..e53ff1eb3a841aea27d8ea1fc38f6bb5f5a35059 100644 (file)
@@ -11149,6 +11149,14 @@ static void bnx2x_get_mac_hwinfo(struct bnx2x *bp)
                        bnx2x_get_cnic_mac_hwinfo(bp);
        }
 
+       if (!BP_NOMCP(bp)) {
+               /* Read physical port identifier from shmem */
+               val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
+               val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
+               bnx2x_set_mac_buf(bp->phys_port_id, val, val2);
+               bp->flags |= HAS_PHYS_PORT_ID;
+       }
+
        memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
 
        if (!bnx2x_is_valid_ether_addr(bp, bp->dev->dev_addr))
@@ -12044,6 +12052,20 @@ static int bnx2x_validate_addr(struct net_device *dev)
        return 0;
 }
 
+static int bnx2x_get_phys_port_id(struct net_device *netdev,
+                                 struct netdev_phys_port_id *ppid)
+{
+       struct bnx2x *bp = netdev_priv(netdev);
+
+       if (!(bp->flags & HAS_PHYS_PORT_ID))
+               return -EOPNOTSUPP;
+
+       ppid->id_len = sizeof(bp->phys_port_id);
+       memcpy(ppid->id, bp->phys_port_id, ppid->id_len);
+
+       return 0;
+}
+
 static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_open               = bnx2x_open,
        .ndo_stop               = bnx2x_close,
@@ -12073,6 +12095,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = bnx2x_low_latency_recv,
 #endif
+       .ndo_get_phys_port_id   = bnx2x_get_phys_port_id,
 };
 
 static int bnx2x_set_coherency_mask(struct bnx2x *bp)
index da16953eb2ec58012f059273abf153c7e81293b9..58dc89af7c6afb5d51333230efd59cf63b72ee4a 100644 (file)
@@ -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;
index 1179fe06d0c7ff010b7a06102a68b601c747bf9c..208568bc7a71d72d8e19aea70f02485e17c0e8ee 100644 (file)
@@ -188,6 +188,12 @@ struct pfvf_acquire_resp_tlv {
        } resc;
 };
 
+struct vfpf_port_phys_id_resp_tlv {
+       struct channel_tlv tl;
+       u8 id[ETH_ALEN];
+       u8 padding[2];
+};
+
 #define VFPF_INIT_FLG_STATS_COALESCE   (1 << 0) /* when set the VFs queues
                                                  * stats will be coalesced on
                                                  * the leading RSS queue
@@ -398,6 +404,7 @@ enum channel_tlvs {
        CHANNEL_TLV_PF_SET_MAC,
        CHANNEL_TLV_PF_SET_VLAN,
        CHANNEL_TLV_UPDATE_RSS,
+       CHANNEL_TLV_PHYS_PORT_ID,
        CHANNEL_TLV_MAX
 };