data->header.rule_cnt, p->rx_accept_flags,
                         p->tx_accept_flags);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
 
        /* Send a ramrod */
                raw->clear_pending(raw);
                return 0;
        } else {
-               /* No need for an explicit memory barrier here as long we would
-                * need to ensure the ordering of writing to the SPQ element
+               /* No need for an explicit memory barrier here as long as we
+                * ensure the ordering of writing to the SPQ element
                 * and updating of the SPQ producer which involves a memory
-                * read and we will have to put a full memory barrier there
-                * (inside bnx2x_sp_post()).
+                * read. If the memory read is removed we will have to put a
+                * full memory barrier there (inside bnx2x_sp_post()).
                 */
 
                /* Send a ramrod */
                raw->clear_pending(raw);
                return 0;
        } else {
-               /* No need for an explicit memory barrier here as long we would
-                * need to ensure the ordering of writing to the SPQ element
+               /* No need for an explicit memory barrier here as long as we
+                * ensure the ordering of writing to the SPQ element
                 * and updating of the SPQ producer which involves a memory
-                * read and we will have to put a full memory barrier there
-                * (inside bnx2x_sp_post()).
+                * read. If the memory read is removed we will have to put a
+                * full memory barrier there (inside bnx2x_sp_post()).
                 */
 
                /* Send a ramrod */
                data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
        }
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
 
        /* Send a ramrod */
        /* Fill the ramrod data */
        bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
        bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
        bnx2x_q_fill_setup_data_e2(bp, params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
                         o->cids[cid_index], rdata->general.client_id,
                         rdata->general.sp_client_id, rdata->general.cos);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[cid_index],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
        /* Fill the ramrod data */
        bnx2x_q_fill_update_data(bp, o, update_params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE,
                             o->cids[cid_index], U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
        return bnx2x_q_send_update(bp, params);
 }
 
+static void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp,
+                               struct bnx2x_queue_sp_obj *obj,
+                               struct bnx2x_queue_update_tpa_params *params,
+                               struct tpa_update_ramrod_data *data)
+{
+       data->client_id = obj->cl_id;
+       data->complete_on_both_clients = params->complete_on_both_clients;
+       data->dont_verify_rings_pause_thr_flg =
+               params->dont_verify_thr;
+       data->max_agg_size = cpu_to_le16(params->max_agg_sz);
+       data->max_sges_for_packet = params->max_sges_pkt;
+       data->max_tpa_queues = params->max_tpa_queues;
+       data->sge_buff_size = cpu_to_le16(params->sge_buff_sz);
+       data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map));
+       data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map));
+       data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high);
+       data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low);
+       data->tpa_mode = params->tpa_mode;
+       data->update_ipv4 = params->update_ipv4;
+       data->update_ipv6 = params->update_ipv6;
+}
+
 static inline int bnx2x_q_send_update_tpa(struct bnx2x *bp,
                                        struct bnx2x_queue_state_params *params)
 {
-       /* TODO: Not implemented yet. */
-       return -1;
+       struct bnx2x_queue_sp_obj *o = params->q_obj;
+       struct tpa_update_ramrod_data *rdata =
+               (struct tpa_update_ramrod_data *)o->rdata;
+       dma_addr_t data_mapping = o->rdata_mapping;
+       struct bnx2x_queue_update_tpa_params *update_tpa_params =
+               ¶ms->params.update_tpa;
+       u16 type;
+
+       /* Clear the ramrod data */
+       memset(rdata, 0, sizeof(*rdata));
+
+       /* Fill the ramrod data */
+       bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata);
+
+       /* Add the function id inside the type, so that sp post function
+        * doesn't automatically add the PF func-id, this is required
+        * for operations done by PFs on behalf of their VFs
+        */
+       type = ETH_CONNECTION_TYPE |
+               ((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT);
+
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE,
+                            o->cids[BNX2X_PRIMARY_CID_INDEX],
+                            U64_HI(data_mapping),
+                            U64_LO(data_mapping), type);
 }
 
 static inline int bnx2x_q_send_halt(struct bnx2x *bp,
        rdata->tx_switch_suspend = switch_update_params->suspend;
        rdata->echo = SWITCH_UPDATE;
 
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0,
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
        rdata->allowed_priorities = afex_update_params->allowed_priorities;
        rdata->echo = AFEX_UPDATE;
 
-       /*  No need for an explicit memory barrier here as long we would
-        *  need to ensure the ordering of writing to the SPQ element
-        *  and updating of the SPQ producer which involves a memory
-        *  read and we will have to put a full memory barrier there
-        *  (inside bnx2x_sp_post()).
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
        DP(BNX2X_MSG_SP,
           "afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n",
                rdata->traffic_type_to_priority_cos[i] =
                        tx_start_params->traffic_type_to_priority_cos[i];
 
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0,
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
 
           BNX2X_VFOP_RSS_DONE
 };
 
+enum bnx2x_vfop_tpa_state {
+          BNX2X_VFOP_TPA_CONFIG,
+          BNX2X_VFOP_TPA_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,
        return -ENOMEM;
 }
 
+/* VFOP tpa update, send update on all queues */
+static void bnx2x_vfop_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+       struct bnx2x_vfop_args_tpa *tpa_args = &vfop->args.tpa;
+       enum bnx2x_vfop_tpa_state state = vfop->state;
+
+       bnx2x_vfop_reset_wq(vf);
+
+       if (vfop->rc < 0)
+               goto op_err;
+
+       DP(BNX2X_MSG_IOV, "vf[%d:%d] STATE: %d\n",
+          vf->abs_vfid, tpa_args->qid,
+          state);
+
+       switch (state) {
+       case BNX2X_VFOP_TPA_CONFIG:
+
+               if (tpa_args->qid < vf_rxq_count(vf)) {
+                       struct bnx2x_queue_state_params *qstate =
+                               &vf->op_params.qstate;
+
+                       qstate->q_obj = &bnx2x_vfq(vf, tpa_args->qid, sp_obj);
+
+                       /* The only thing that changes for the ramrod params
+                        * between calls is the sge_map
+                        */
+                       qstate->params.update_tpa.sge_map =
+                               tpa_args->sge_map[tpa_args->qid];
+
+                       DP(BNX2X_MSG_IOV, "sge_addr[%d] %08x:%08x\n",
+                          tpa_args->qid,
+                          U64_HI(qstate->params.update_tpa.sge_map),
+                          U64_LO(qstate->params.update_tpa.sge_map));
+                       qstate->cmd = BNX2X_Q_CMD_UPDATE_TPA;
+                       vfop->rc = bnx2x_queue_state_change(bp, qstate);
+
+                       tpa_args->qid++;
+                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+               }
+               vfop->state = BNX2X_VFOP_TPA_DONE;
+               vfop->rc = 0;
+               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+               BNX2X_ERR("TPA update error: rc %d\n", vfop->rc);
+op_done:
+       case BNX2X_VFOP_TPA_DONE:
+               bnx2x_vfop_end(bp, vf, vfop);
+               return;
+       default:
+               bnx2x_vfop_default(state);
+       }
+op_pending:
+       return;
+}
+
+int bnx2x_vfop_tpa_cmd(struct bnx2x *bp,
+                       struct bnx2x_virtf *vf,
+                       struct bnx2x_vfop_cmd *cmd,
+                       struct vfpf_tpa_tlv *tpa_tlv)
+{
+       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+       if (vfop) {
+               vfop->args.qx.qid = 0; /* loop */
+               memcpy(&vfop->args.tpa.sge_map,
+                      tpa_tlv->tpa_client_info.sge_addr,
+                      sizeof(vfop->args.tpa.sge_map));
+               bnx2x_vfop_opset(BNX2X_VFOP_TPA_CONFIG,
+                                bnx2x_vfop_tpa, cmd->done);
+               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_tpa,
+                                            cmd->block);
+       }
+       return -ENOMEM;
+}
+
 /* VF release ~ VF close + VF release-resources
  * Release is the ultimate SW shutdown and is called whenever an
  * irrecoverable error is encountered.
 
        resp->pfdev_info.db_size = bp->db_size;
        resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
        resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
-                                  /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+                                  PFVF_CAP_TPA |
+                                  PFVF_CAP_TPA_UPDATE);
        bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
                          sizeof(resp->pfdev_info.fw_ver));
 
                bnx2x_vf_mbx_resp(bp, vf);
 }
 
+static int bnx2x_validate_tpa_params(struct bnx2x *bp,
+                                      struct vfpf_tpa_tlv *tpa_tlv)
+{
+       int rc = 0;
+
+       if (tpa_tlv->tpa_client_info.max_sges_for_packet >
+           U_ETH_MAX_SGES_FOR_PACKET) {
+               rc = -EINVAL;
+               BNX2X_ERR("TPA update: max_sges received %d, max is %d\n",
+                         tpa_tlv->tpa_client_info.max_sges_for_packet,
+                         U_ETH_MAX_SGES_FOR_PACKET);
+       }
+
+       if (tpa_tlv->tpa_client_info.max_tpa_queues > MAX_AGG_QS(bp)) {
+               rc = -EINVAL;
+               BNX2X_ERR("TPA update: max_tpa_queues received %d, max is %d\n",
+                         tpa_tlv->tpa_client_info.max_tpa_queues,
+                         MAX_AGG_QS(bp));
+       }
+
+       return rc;
+}
+
+static void bnx2x_vf_mbx_update_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                   struct bnx2x_vf_mbx *mbx)
+{
+       struct bnx2x_vfop_cmd cmd = {
+               .done = bnx2x_vf_mbx_resp,
+               .block = false,
+       };
+       struct bnx2x_queue_update_tpa_params *vf_op_params =
+               &vf->op_params.qstate.params.update_tpa;
+       struct vfpf_tpa_tlv *tpa_tlv = &mbx->msg->req.update_tpa;
+
+       memset(vf_op_params, 0, sizeof(*vf_op_params));
+
+       if (bnx2x_validate_tpa_params(bp, tpa_tlv))
+               goto mbx_resp;
+
+       vf_op_params->complete_on_both_clients =
+               tpa_tlv->tpa_client_info.complete_on_both_clients;
+       vf_op_params->dont_verify_thr =
+               tpa_tlv->tpa_client_info.dont_verify_thr;
+       vf_op_params->max_agg_sz =
+               tpa_tlv->tpa_client_info.max_agg_size;
+       vf_op_params->max_sges_pkt =
+               tpa_tlv->tpa_client_info.max_sges_for_packet;
+       vf_op_params->max_tpa_queues =
+               tpa_tlv->tpa_client_info.max_tpa_queues;
+       vf_op_params->sge_buff_sz =
+               tpa_tlv->tpa_client_info.sge_buff_size;
+       vf_op_params->sge_pause_thr_high =
+               tpa_tlv->tpa_client_info.sge_pause_thr_high;
+       vf_op_params->sge_pause_thr_low =
+               tpa_tlv->tpa_client_info.sge_pause_thr_low;
+       vf_op_params->tpa_mode =
+               tpa_tlv->tpa_client_info.tpa_mode;
+       vf_op_params->update_ipv4 =
+               tpa_tlv->tpa_client_info.update_ipv4;
+       vf_op_params->update_ipv6 =
+               tpa_tlv->tpa_client_info.update_ipv6;
+
+       vf->op_rc = bnx2x_vfop_tpa_cmd(bp, vf, &cmd, tpa_tlv);
+
+mbx_resp:
+       if (vf->op_rc)
+               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)
                case CHANNEL_TLV_UPDATE_RSS:
                        bnx2x_vf_mbx_update_rss(bp, vf, mbx);
                        return;
+               case CHANNEL_TLV_UPDATE_TPA:
+                       bnx2x_vf_mbx_update_tpa(bp, vf, mbx);
+                       return;
                }
 
        } else {