11408cc1fSYuval Mintz /* QLogic qed NIC Driver
21408cc1fSYuval Mintz  * Copyright (c) 2015 QLogic Corporation
31408cc1fSYuval Mintz  *
41408cc1fSYuval Mintz  * This software is available under the terms of the GNU General Public License
51408cc1fSYuval Mintz  * (GPL) Version 2, available from the file COPYING in the main directory of
61408cc1fSYuval Mintz  * this source tree.
71408cc1fSYuval Mintz  */
81408cc1fSYuval Mintz 
936558c3dSYuval Mintz #include <linux/crc32.h>
10eff16960SYuval Mintz #include <linux/etherdevice.h>
111408cc1fSYuval Mintz #include "qed.h"
121408cc1fSYuval Mintz #include "qed_sriov.h"
131408cc1fSYuval Mintz #include "qed_vf.h"
141408cc1fSYuval Mintz 
151408cc1fSYuval Mintz static void *qed_vf_pf_prep(struct qed_hwfn *p_hwfn, u16 type, u16 length)
161408cc1fSYuval Mintz {
171408cc1fSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
181408cc1fSYuval Mintz 	void *p_tlv;
191408cc1fSYuval Mintz 
201408cc1fSYuval Mintz 	/* This lock is released when we receive PF's response
211408cc1fSYuval Mintz 	 * in qed_send_msg2pf().
221408cc1fSYuval Mintz 	 * So, qed_vf_pf_prep() and qed_send_msg2pf()
231408cc1fSYuval Mintz 	 * must come in sequence.
241408cc1fSYuval Mintz 	 */
251408cc1fSYuval Mintz 	mutex_lock(&(p_iov->mutex));
261408cc1fSYuval Mintz 
271408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn,
281408cc1fSYuval Mintz 		   QED_MSG_IOV,
291408cc1fSYuval Mintz 		   "preparing to send 0x%04x tlv over vf pf channel\n",
301408cc1fSYuval Mintz 		   type);
311408cc1fSYuval Mintz 
321408cc1fSYuval Mintz 	/* Reset Requst offset */
331408cc1fSYuval Mintz 	p_iov->offset = (u8 *)p_iov->vf2pf_request;
341408cc1fSYuval Mintz 
351408cc1fSYuval Mintz 	/* Clear mailbox - both request and reply */
361408cc1fSYuval Mintz 	memset(p_iov->vf2pf_request, 0, sizeof(union vfpf_tlvs));
371408cc1fSYuval Mintz 	memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs));
381408cc1fSYuval Mintz 
391408cc1fSYuval Mintz 	/* Init type and length */
401408cc1fSYuval Mintz 	p_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, type, length);
411408cc1fSYuval Mintz 
421408cc1fSYuval Mintz 	/* Init first tlv header */
431408cc1fSYuval Mintz 	((struct vfpf_first_tlv *)p_tlv)->reply_address =
441408cc1fSYuval Mintz 	    (u64)p_iov->pf2vf_reply_phys;
451408cc1fSYuval Mintz 
461408cc1fSYuval Mintz 	return p_tlv;
471408cc1fSYuval Mintz }
481408cc1fSYuval Mintz 
491408cc1fSYuval Mintz static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size)
501408cc1fSYuval Mintz {
511408cc1fSYuval Mintz 	union vfpf_tlvs *p_req = p_hwfn->vf_iov_info->vf2pf_request;
521408cc1fSYuval Mintz 	struct ustorm_trigger_vf_zone trigger;
531408cc1fSYuval Mintz 	struct ustorm_vf_zone *zone_data;
541408cc1fSYuval Mintz 	int rc = 0, time = 100;
551408cc1fSYuval Mintz 
561408cc1fSYuval Mintz 	zone_data = (struct ustorm_vf_zone *)PXP_VF_BAR0_START_USDM_ZONE_B;
571408cc1fSYuval Mintz 
581408cc1fSYuval Mintz 	/* output tlvs list */
591408cc1fSYuval Mintz 	qed_dp_tlv_list(p_hwfn, p_req);
601408cc1fSYuval Mintz 
611408cc1fSYuval Mintz 	/* need to add the END TLV to the message size */
621408cc1fSYuval Mintz 	resp_size += sizeof(struct channel_list_end_tlv);
631408cc1fSYuval Mintz 
641408cc1fSYuval Mintz 	/* Send TLVs over HW channel */
651408cc1fSYuval Mintz 	memset(&trigger, 0, sizeof(struct ustorm_trigger_vf_zone));
661408cc1fSYuval Mintz 	trigger.vf_pf_msg_valid = 1;
671408cc1fSYuval Mintz 
681408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn,
691408cc1fSYuval Mintz 		   QED_MSG_IOV,
701408cc1fSYuval Mintz 		   "VF -> PF [%02x] message: [%08x, %08x] --> %p, %08x --> %p\n",
711408cc1fSYuval Mintz 		   GET_FIELD(p_hwfn->hw_info.concrete_fid,
721408cc1fSYuval Mintz 			     PXP_CONCRETE_FID_PFID),
731408cc1fSYuval Mintz 		   upper_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys),
741408cc1fSYuval Mintz 		   lower_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys),
751408cc1fSYuval Mintz 		   &zone_data->non_trigger.vf_pf_msg_addr,
761408cc1fSYuval Mintz 		   *((u32 *)&trigger), &zone_data->trigger);
771408cc1fSYuval Mintz 
781408cc1fSYuval Mintz 	REG_WR(p_hwfn,
791408cc1fSYuval Mintz 	       (uintptr_t)&zone_data->non_trigger.vf_pf_msg_addr.lo,
801408cc1fSYuval Mintz 	       lower_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys));
811408cc1fSYuval Mintz 
821408cc1fSYuval Mintz 	REG_WR(p_hwfn,
831408cc1fSYuval Mintz 	       (uintptr_t)&zone_data->non_trigger.vf_pf_msg_addr.hi,
841408cc1fSYuval Mintz 	       upper_32_bits(p_hwfn->vf_iov_info->vf2pf_request_phys));
851408cc1fSYuval Mintz 
861408cc1fSYuval Mintz 	/* The message data must be written first, to prevent trigger before
871408cc1fSYuval Mintz 	 * data is written.
881408cc1fSYuval Mintz 	 */
891408cc1fSYuval Mintz 	wmb();
901408cc1fSYuval Mintz 
911408cc1fSYuval Mintz 	REG_WR(p_hwfn, (uintptr_t)&zone_data->trigger, *((u32 *)&trigger));
921408cc1fSYuval Mintz 
931408cc1fSYuval Mintz 	/* When PF would be done with the response, it would write back to the
941408cc1fSYuval Mintz 	 * `done' address. Poll until then.
951408cc1fSYuval Mintz 	 */
961408cc1fSYuval Mintz 	while ((!*done) && time) {
971408cc1fSYuval Mintz 		msleep(25);
981408cc1fSYuval Mintz 		time--;
991408cc1fSYuval Mintz 	}
1001408cc1fSYuval Mintz 
1011408cc1fSYuval Mintz 	if (!*done) {
1021408cc1fSYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_IOV,
1031408cc1fSYuval Mintz 			   "VF <-- PF Timeout [Type %d]\n",
1041408cc1fSYuval Mintz 			   p_req->first_tlv.tl.type);
1051408cc1fSYuval Mintz 		rc = -EBUSY;
1061408cc1fSYuval Mintz 		goto exit;
1071408cc1fSYuval Mintz 	} else {
1081408cc1fSYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_IOV,
1091408cc1fSYuval Mintz 			   "PF response: %d [Type %d]\n",
1101408cc1fSYuval Mintz 			   *done, p_req->first_tlv.tl.type);
1111408cc1fSYuval Mintz 	}
1121408cc1fSYuval Mintz 
1131408cc1fSYuval Mintz exit:
1141408cc1fSYuval Mintz 	mutex_unlock(&(p_hwfn->vf_iov_info->mutex));
1151408cc1fSYuval Mintz 
1161408cc1fSYuval Mintz 	return rc;
1171408cc1fSYuval Mintz }
1181408cc1fSYuval Mintz 
1191408cc1fSYuval Mintz #define VF_ACQUIRE_THRESH 3
1201cf2b1a9SYuval Mintz static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn,
1211cf2b1a9SYuval Mintz 					  struct vf_pf_resc_request *p_req,
1221cf2b1a9SYuval Mintz 					  struct pf_vf_resc *p_resp)
1231cf2b1a9SYuval Mintz {
1241cf2b1a9SYuval Mintz 	DP_VERBOSE(p_hwfn,
1251cf2b1a9SYuval Mintz 		   QED_MSG_IOV,
1261cf2b1a9SYuval Mintz 		   "PF unwilling to fullill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]. Try PF recommended amount\n",
1271cf2b1a9SYuval Mintz 		   p_req->num_rxqs,
1281cf2b1a9SYuval Mintz 		   p_resp->num_rxqs,
1291cf2b1a9SYuval Mintz 		   p_req->num_rxqs,
1301cf2b1a9SYuval Mintz 		   p_resp->num_txqs,
1311cf2b1a9SYuval Mintz 		   p_req->num_sbs,
1321cf2b1a9SYuval Mintz 		   p_resp->num_sbs,
1331cf2b1a9SYuval Mintz 		   p_req->num_mac_filters,
1341cf2b1a9SYuval Mintz 		   p_resp->num_mac_filters,
1351cf2b1a9SYuval Mintz 		   p_req->num_vlan_filters,
1361cf2b1a9SYuval Mintz 		   p_resp->num_vlan_filters,
1371cf2b1a9SYuval Mintz 		   p_req->num_mc_filters, p_resp->num_mc_filters);
1381cf2b1a9SYuval Mintz 
1391cf2b1a9SYuval Mintz 	/* humble our request */
1401cf2b1a9SYuval Mintz 	p_req->num_txqs = p_resp->num_txqs;
1411cf2b1a9SYuval Mintz 	p_req->num_rxqs = p_resp->num_rxqs;
1421cf2b1a9SYuval Mintz 	p_req->num_sbs = p_resp->num_sbs;
1431cf2b1a9SYuval Mintz 	p_req->num_mac_filters = p_resp->num_mac_filters;
1441cf2b1a9SYuval Mintz 	p_req->num_vlan_filters = p_resp->num_vlan_filters;
1451cf2b1a9SYuval Mintz 	p_req->num_mc_filters = p_resp->num_mc_filters;
1461cf2b1a9SYuval Mintz }
1471408cc1fSYuval Mintz 
1481408cc1fSYuval Mintz static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn)
1491408cc1fSYuval Mintz {
1501408cc1fSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
1511408cc1fSYuval Mintz 	struct pfvf_acquire_resp_tlv *resp = &p_iov->pf2vf_reply->acquire_resp;
1521408cc1fSYuval Mintz 	struct pf_vf_pfdev_info *pfdev_info = &resp->pfdev_info;
1531cf2b1a9SYuval Mintz 	struct vf_pf_resc_request *p_resc;
1541408cc1fSYuval Mintz 	bool resources_acquired = false;
1551408cc1fSYuval Mintz 	struct vfpf_acquire_tlv *req;
1561408cc1fSYuval Mintz 	int rc = 0, attempts = 0;
1571408cc1fSYuval Mintz 
1581408cc1fSYuval Mintz 	/* clear mailbox and prep first tlv */
1591408cc1fSYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_ACQUIRE, sizeof(*req));
1601cf2b1a9SYuval Mintz 	p_resc = &req->resc_request;
1611408cc1fSYuval Mintz 
1621408cc1fSYuval Mintz 	/* starting filling the request */
1631408cc1fSYuval Mintz 	req->vfdev_info.opaque_fid = p_hwfn->hw_info.opaque_fid;
1641408cc1fSYuval Mintz 
1651cf2b1a9SYuval Mintz 	p_resc->num_rxqs = QED_MAX_VF_CHAINS_PER_PF;
1661cf2b1a9SYuval Mintz 	p_resc->num_txqs = QED_MAX_VF_CHAINS_PER_PF;
1671cf2b1a9SYuval Mintz 	p_resc->num_sbs = QED_MAX_VF_CHAINS_PER_PF;
1681cf2b1a9SYuval Mintz 	p_resc->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS;
1691cf2b1a9SYuval Mintz 	p_resc->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS;
1701408cc1fSYuval Mintz 
1711408cc1fSYuval Mintz 	req->vfdev_info.os_type = VFPF_ACQUIRE_OS_LINUX;
1721408cc1fSYuval Mintz 	req->vfdev_info.fw_major = FW_MAJOR_VERSION;
1731408cc1fSYuval Mintz 	req->vfdev_info.fw_minor = FW_MINOR_VERSION;
1741408cc1fSYuval Mintz 	req->vfdev_info.fw_revision = FW_REVISION_VERSION;
1751408cc1fSYuval Mintz 	req->vfdev_info.fw_engineering = FW_ENGINEERING_VERSION;
1761fe614d1SYuval Mintz 	req->vfdev_info.eth_fp_hsi_major = ETH_HSI_VER_MAJOR;
1771fe614d1SYuval Mintz 	req->vfdev_info.eth_fp_hsi_minor = ETH_HSI_VER_MINOR;
1781408cc1fSYuval Mintz 
1791408cc1fSYuval Mintz 	/* Fill capability field with any non-deprecated config we support */
1801408cc1fSYuval Mintz 	req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_100G;
1811408cc1fSYuval Mintz 
1821408cc1fSYuval Mintz 	/* pf 2 vf bulletin board address */
1831408cc1fSYuval Mintz 	req->bulletin_addr = p_iov->bulletin.phys;
1841408cc1fSYuval Mintz 	req->bulletin_size = p_iov->bulletin.size;
1851408cc1fSYuval Mintz 
1861408cc1fSYuval Mintz 	/* add list termination tlv */
1871408cc1fSYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
1881408cc1fSYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
1891408cc1fSYuval Mintz 
1901408cc1fSYuval Mintz 	while (!resources_acquired) {
1911408cc1fSYuval Mintz 		DP_VERBOSE(p_hwfn,
1921408cc1fSYuval Mintz 			   QED_MSG_IOV, "attempting to acquire resources\n");
1931408cc1fSYuval Mintz 
194d8c2c7e3SYuval Mintz 		/* Clear response buffer, as this might be a re-send */
195d8c2c7e3SYuval Mintz 		memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs));
196d8c2c7e3SYuval Mintz 
1971408cc1fSYuval Mintz 		/* send acquire request */
1981408cc1fSYuval Mintz 		rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
1991408cc1fSYuval Mintz 		if (rc)
2001408cc1fSYuval Mintz 			return rc;
2011408cc1fSYuval Mintz 
2021408cc1fSYuval Mintz 		/* copy acquire response from buffer to p_hwfn */
2031408cc1fSYuval Mintz 		memcpy(&p_iov->acquire_resp, resp, sizeof(p_iov->acquire_resp));
2041408cc1fSYuval Mintz 
2051408cc1fSYuval Mintz 		attempts++;
2061408cc1fSYuval Mintz 
2071408cc1fSYuval Mintz 		if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
2081408cc1fSYuval Mintz 			/* PF agrees to allocate our resources */
2091408cc1fSYuval Mintz 			if (!(resp->pfdev_info.capabilities &
2101408cc1fSYuval Mintz 			      PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE)) {
211d8c2c7e3SYuval Mintz 				/* It's possible legacy PF mistakenly accepted;
212d8c2c7e3SYuval Mintz 				 * but we don't care - simply mark it as
213d8c2c7e3SYuval Mintz 				 * legacy and continue.
214d8c2c7e3SYuval Mintz 				 */
215d8c2c7e3SYuval Mintz 				req->vfdev_info.capabilities |=
216d8c2c7e3SYuval Mintz 				    VFPF_ACQUIRE_CAP_PRE_FP_HSI;
2171408cc1fSYuval Mintz 			}
2181408cc1fSYuval Mintz 			DP_VERBOSE(p_hwfn, QED_MSG_IOV, "resources acquired\n");
2191408cc1fSYuval Mintz 			resources_acquired = true;
2201408cc1fSYuval Mintz 		} else if (resp->hdr.status == PFVF_STATUS_NO_RESOURCE &&
2211408cc1fSYuval Mintz 			   attempts < VF_ACQUIRE_THRESH) {
2221cf2b1a9SYuval Mintz 			qed_vf_pf_acquire_reduce_resc(p_hwfn, p_resc,
2231cf2b1a9SYuval Mintz 						      &resp->resc);
224d8c2c7e3SYuval Mintz 		} else if (resp->hdr.status == PFVF_STATUS_NOT_SUPPORTED) {
225d8c2c7e3SYuval Mintz 			if (pfdev_info->major_fp_hsi &&
2261fe614d1SYuval Mintz 			    (pfdev_info->major_fp_hsi != ETH_HSI_VER_MAJOR)) {
2271fe614d1SYuval Mintz 				DP_NOTICE(p_hwfn,
2281fe614d1SYuval Mintz 					  "PF uses an incompatible fastpath HSI %02x.%02x [VF requires %02x.%02x]. Please change to a VF driver using %02x.xx.\n",
2291fe614d1SYuval Mintz 					  pfdev_info->major_fp_hsi,
2301fe614d1SYuval Mintz 					  pfdev_info->minor_fp_hsi,
2311fe614d1SYuval Mintz 					  ETH_HSI_VER_MAJOR,
232d8c2c7e3SYuval Mintz 					  ETH_HSI_VER_MINOR,
233d8c2c7e3SYuval Mintz 					  pfdev_info->major_fp_hsi);
234d8c2c7e3SYuval Mintz 				rc = -EINVAL;
235d8c2c7e3SYuval Mintz 				goto exit;
236d8c2c7e3SYuval Mintz 			}
237d8c2c7e3SYuval Mintz 
238d8c2c7e3SYuval Mintz 			if (!pfdev_info->major_fp_hsi) {
239d8c2c7e3SYuval Mintz 				if (req->vfdev_info.capabilities &
240d8c2c7e3SYuval Mintz 				    VFPF_ACQUIRE_CAP_PRE_FP_HSI) {
241d8c2c7e3SYuval Mintz 					DP_NOTICE(p_hwfn,
242d8c2c7e3SYuval Mintz 						  "PF uses very old drivers. Please change to a VF driver using no later than 8.8.x.x.\n");
243d8c2c7e3SYuval Mintz 					rc = -EINVAL;
244d8c2c7e3SYuval Mintz 					goto exit;
245d8c2c7e3SYuval Mintz 				} else {
246d8c2c7e3SYuval Mintz 					DP_INFO(p_hwfn,
247d8c2c7e3SYuval Mintz 						"PF is old - try re-acquire to see if it supports FW-version override\n");
248d8c2c7e3SYuval Mintz 					req->vfdev_info.capabilities |=
249d8c2c7e3SYuval Mintz 					    VFPF_ACQUIRE_CAP_PRE_FP_HSI;
250d8c2c7e3SYuval Mintz 					continue;
251d8c2c7e3SYuval Mintz 				}
252d8c2c7e3SYuval Mintz 			}
253d8c2c7e3SYuval Mintz 
254d8c2c7e3SYuval Mintz 			/* If PF/VF are using same Major, PF must have had
255d8c2c7e3SYuval Mintz 			 * it's reasons. Simply fail.
256d8c2c7e3SYuval Mintz 			 */
257d8c2c7e3SYuval Mintz 			DP_NOTICE(p_hwfn, "PF rejected acquisition by VF\n");
258d8c2c7e3SYuval Mintz 			rc = -EINVAL;
259d8c2c7e3SYuval Mintz 			goto exit;
2601408cc1fSYuval Mintz 		} else {
2611408cc1fSYuval Mintz 			DP_ERR(p_hwfn,
2621408cc1fSYuval Mintz 			       "PF returned error %d to VF acquisition request\n",
2631408cc1fSYuval Mintz 			       resp->hdr.status);
264d8c2c7e3SYuval Mintz 			rc = -EAGAIN;
265d8c2c7e3SYuval Mintz 			goto exit;
2661408cc1fSYuval Mintz 		}
2671408cc1fSYuval Mintz 	}
2681408cc1fSYuval Mintz 
269d8c2c7e3SYuval Mintz 	/* Mark the PF as legacy, if needed */
270d8c2c7e3SYuval Mintz 	if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_PRE_FP_HSI)
271d8c2c7e3SYuval Mintz 		p_iov->b_pre_fp_hsi = true;
272d8c2c7e3SYuval Mintz 
2731408cc1fSYuval Mintz 	/* Update bulletin board size with response from PF */
2741408cc1fSYuval Mintz 	p_iov->bulletin.size = resp->bulletin_size;
2751408cc1fSYuval Mintz 
2761408cc1fSYuval Mintz 	/* get HW info */
2771408cc1fSYuval Mintz 	p_hwfn->cdev->type = resp->pfdev_info.dev_type;
2781408cc1fSYuval Mintz 	p_hwfn->cdev->chip_rev = resp->pfdev_info.chip_rev;
2791408cc1fSYuval Mintz 
2801408cc1fSYuval Mintz 	p_hwfn->cdev->chip_num = pfdev_info->chip_num & 0xffff;
2811408cc1fSYuval Mintz 
2821408cc1fSYuval Mintz 	/* Learn of the possibility of CMT */
2831408cc1fSYuval Mintz 	if (IS_LEAD_HWFN(p_hwfn)) {
2841408cc1fSYuval Mintz 		if (resp->pfdev_info.capabilities & PFVF_ACQUIRE_CAP_100G) {
2851408cc1fSYuval Mintz 			DP_NOTICE(p_hwfn, "100g VF\n");
2861408cc1fSYuval Mintz 			p_hwfn->cdev->num_hwfns = 2;
2871408cc1fSYuval Mintz 		}
2881408cc1fSYuval Mintz 	}
2891408cc1fSYuval Mintz 
290d8c2c7e3SYuval Mintz 	if (!p_iov->b_pre_fp_hsi &&
291d8c2c7e3SYuval Mintz 	    ETH_HSI_VER_MINOR &&
2921fe614d1SYuval Mintz 	    (resp->pfdev_info.minor_fp_hsi < ETH_HSI_VER_MINOR)) {
2931fe614d1SYuval Mintz 		DP_INFO(p_hwfn,
2941fe614d1SYuval Mintz 			"PF is using older fastpath HSI; %02x.%02x is configured\n",
2951fe614d1SYuval Mintz 			ETH_HSI_VER_MAJOR, resp->pfdev_info.minor_fp_hsi);
2961fe614d1SYuval Mintz 	}
2971fe614d1SYuval Mintz 
298d8c2c7e3SYuval Mintz exit:
299d8c2c7e3SYuval Mintz 	return rc;
3001408cc1fSYuval Mintz }
3011408cc1fSYuval Mintz 
3021408cc1fSYuval Mintz int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn)
3031408cc1fSYuval Mintz {
3041408cc1fSYuval Mintz 	struct qed_vf_iov *p_iov;
3051408cc1fSYuval Mintz 	u32 reg;
3061408cc1fSYuval Mintz 
3071408cc1fSYuval Mintz 	/* Set number of hwfns - might be overriden once leading hwfn learns
3081408cc1fSYuval Mintz 	 * actual configuration from PF.
3091408cc1fSYuval Mintz 	 */
3101408cc1fSYuval Mintz 	if (IS_LEAD_HWFN(p_hwfn))
3111408cc1fSYuval Mintz 		p_hwfn->cdev->num_hwfns = 1;
3121408cc1fSYuval Mintz 
3131408cc1fSYuval Mintz 	/* Set the doorbell bar. Assumption: regview is set */
3141408cc1fSYuval Mintz 	p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview +
3151408cc1fSYuval Mintz 					  PXP_VF_BAR0_START_DQ;
3161408cc1fSYuval Mintz 
3171408cc1fSYuval Mintz 	reg = PXP_VF_BAR0_ME_OPAQUE_ADDRESS;
3181408cc1fSYuval Mintz 	p_hwfn->hw_info.opaque_fid = (u16)REG_RD(p_hwfn, reg);
3191408cc1fSYuval Mintz 
3201408cc1fSYuval Mintz 	reg = PXP_VF_BAR0_ME_CONCRETE_ADDRESS;
3211408cc1fSYuval Mintz 	p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, reg);
3221408cc1fSYuval Mintz 
3231408cc1fSYuval Mintz 	/* Allocate vf sriov info */
3241408cc1fSYuval Mintz 	p_iov = kzalloc(sizeof(*p_iov), GFP_KERNEL);
3251408cc1fSYuval Mintz 	if (!p_iov) {
3261408cc1fSYuval Mintz 		DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sriov'\n");
3271408cc1fSYuval Mintz 		return -ENOMEM;
3281408cc1fSYuval Mintz 	}
3291408cc1fSYuval Mintz 
3301408cc1fSYuval Mintz 	/* Allocate vf2pf msg */
3311408cc1fSYuval Mintz 	p_iov->vf2pf_request = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
3321408cc1fSYuval Mintz 						  sizeof(union vfpf_tlvs),
3331408cc1fSYuval Mintz 						  &p_iov->vf2pf_request_phys,
3341408cc1fSYuval Mintz 						  GFP_KERNEL);
3351408cc1fSYuval Mintz 	if (!p_iov->vf2pf_request) {
3361408cc1fSYuval Mintz 		DP_NOTICE(p_hwfn,
3371408cc1fSYuval Mintz 			  "Failed to allocate `vf2pf_request' DMA memory\n");
3381408cc1fSYuval Mintz 		goto free_p_iov;
3391408cc1fSYuval Mintz 	}
3401408cc1fSYuval Mintz 
3411408cc1fSYuval Mintz 	p_iov->pf2vf_reply = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
3421408cc1fSYuval Mintz 						sizeof(union pfvf_tlvs),
3431408cc1fSYuval Mintz 						&p_iov->pf2vf_reply_phys,
3441408cc1fSYuval Mintz 						GFP_KERNEL);
3451408cc1fSYuval Mintz 	if (!p_iov->pf2vf_reply) {
3461408cc1fSYuval Mintz 		DP_NOTICE(p_hwfn,
3471408cc1fSYuval Mintz 			  "Failed to allocate `pf2vf_reply' DMA memory\n");
3481408cc1fSYuval Mintz 		goto free_vf2pf_request;
3491408cc1fSYuval Mintz 	}
3501408cc1fSYuval Mintz 
3511408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn,
3521408cc1fSYuval Mintz 		   QED_MSG_IOV,
3531408cc1fSYuval Mintz 		   "VF's Request mailbox [%p virt 0x%llx phys], Response mailbox [%p virt 0x%llx phys]\n",
3541408cc1fSYuval Mintz 		   p_iov->vf2pf_request,
3551408cc1fSYuval Mintz 		   (u64) p_iov->vf2pf_request_phys,
3561408cc1fSYuval Mintz 		   p_iov->pf2vf_reply, (u64)p_iov->pf2vf_reply_phys);
3571408cc1fSYuval Mintz 
3581408cc1fSYuval Mintz 	/* Allocate Bulletin board */
3591408cc1fSYuval Mintz 	p_iov->bulletin.size = sizeof(struct qed_bulletin_content);
3601408cc1fSYuval Mintz 	p_iov->bulletin.p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
3611408cc1fSYuval Mintz 						    p_iov->bulletin.size,
3621408cc1fSYuval Mintz 						    &p_iov->bulletin.phys,
3631408cc1fSYuval Mintz 						    GFP_KERNEL);
3641408cc1fSYuval Mintz 	DP_VERBOSE(p_hwfn, QED_MSG_IOV,
3651408cc1fSYuval Mintz 		   "VF's bulletin Board [%p virt 0x%llx phys 0x%08x bytes]\n",
3661408cc1fSYuval Mintz 		   p_iov->bulletin.p_virt,
3671408cc1fSYuval Mintz 		   (u64)p_iov->bulletin.phys, p_iov->bulletin.size);
3681408cc1fSYuval Mintz 
3691408cc1fSYuval Mintz 	mutex_init(&p_iov->mutex);
3701408cc1fSYuval Mintz 
3711408cc1fSYuval Mintz 	p_hwfn->vf_iov_info = p_iov;
3721408cc1fSYuval Mintz 
3731408cc1fSYuval Mintz 	p_hwfn->hw_info.personality = QED_PCI_ETH;
3741408cc1fSYuval Mintz 
3751408cc1fSYuval Mintz 	return qed_vf_pf_acquire(p_hwfn);
3761408cc1fSYuval Mintz 
3771408cc1fSYuval Mintz free_vf2pf_request:
3781408cc1fSYuval Mintz 	dma_free_coherent(&p_hwfn->cdev->pdev->dev,
3791408cc1fSYuval Mintz 			  sizeof(union vfpf_tlvs),
3801408cc1fSYuval Mintz 			  p_iov->vf2pf_request, p_iov->vf2pf_request_phys);
3811408cc1fSYuval Mintz free_p_iov:
3821408cc1fSYuval Mintz 	kfree(p_iov);
3831408cc1fSYuval Mintz 
3841408cc1fSYuval Mintz 	return -ENOMEM;
3851408cc1fSYuval Mintz }
386d8c2c7e3SYuval Mintz #define TSTORM_QZONE_START   PXP_VF_BAR0_START_SDM_ZONE_A
387d8c2c7e3SYuval Mintz #define MSTORM_QZONE_START(dev)   (TSTORM_QZONE_START +	\
388d8c2c7e3SYuval Mintz 				   (TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev)))
3891408cc1fSYuval Mintz 
390dacd88d6SYuval Mintz int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn,
391dacd88d6SYuval Mintz 			u8 rx_qid,
392dacd88d6SYuval Mintz 			u16 sb,
393dacd88d6SYuval Mintz 			u8 sb_index,
394dacd88d6SYuval Mintz 			u16 bd_max_bytes,
395dacd88d6SYuval Mintz 			dma_addr_t bd_chain_phys_addr,
396dacd88d6SYuval Mintz 			dma_addr_t cqe_pbl_addr,
397dacd88d6SYuval Mintz 			u16 cqe_pbl_size, void __iomem **pp_prod)
398dacd88d6SYuval Mintz {
399dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
400dacd88d6SYuval Mintz 	struct pfvf_start_queue_resp_tlv *resp;
401dacd88d6SYuval Mintz 	struct vfpf_start_rxq_tlv *req;
402dacd88d6SYuval Mintz 	int rc;
403dacd88d6SYuval Mintz 
404dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
405dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_START_RXQ, sizeof(*req));
406dacd88d6SYuval Mintz 
407dacd88d6SYuval Mintz 	req->rx_qid = rx_qid;
408dacd88d6SYuval Mintz 	req->cqe_pbl_addr = cqe_pbl_addr;
409dacd88d6SYuval Mintz 	req->cqe_pbl_size = cqe_pbl_size;
410dacd88d6SYuval Mintz 	req->rxq_addr = bd_chain_phys_addr;
411dacd88d6SYuval Mintz 	req->hw_sb = sb;
412dacd88d6SYuval Mintz 	req->sb_index = sb_index;
413dacd88d6SYuval Mintz 	req->bd_max_bytes = bd_max_bytes;
414dacd88d6SYuval Mintz 	req->stat_id = -1;
415dacd88d6SYuval Mintz 
416d8c2c7e3SYuval Mintz 	/* If PF is legacy, we'll need to calculate producers ourselves
417d8c2c7e3SYuval Mintz 	 * as well as clean them.
418d8c2c7e3SYuval Mintz 	 */
419d8c2c7e3SYuval Mintz 	if (pp_prod && p_iov->b_pre_fp_hsi) {
420d8c2c7e3SYuval Mintz 		u8 hw_qid = p_iov->acquire_resp.resc.hw_qid[rx_qid];
421d8c2c7e3SYuval Mintz 		u32 init_prod_val = 0;
422d8c2c7e3SYuval Mintz 
423d8c2c7e3SYuval Mintz 		*pp_prod = (u8 __iomem *)p_hwfn->regview +
424d8c2c7e3SYuval Mintz 					 MSTORM_QZONE_START(p_hwfn->cdev) +
425d8c2c7e3SYuval Mintz 					 hw_qid * MSTORM_QZONE_SIZE;
426d8c2c7e3SYuval Mintz 
427d8c2c7e3SYuval Mintz 		/* Init the rcq, rx bd and rx sge (if valid) producers to 0 */
428d8c2c7e3SYuval Mintz 		__internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32),
429d8c2c7e3SYuval Mintz 				  (u32 *)(&init_prod_val));
430d8c2c7e3SYuval Mintz 	}
431dacd88d6SYuval Mintz 	/* add list termination tlv */
432dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
433dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
434dacd88d6SYuval Mintz 
435dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->queue_start;
436dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
437dacd88d6SYuval Mintz 	if (rc)
438dacd88d6SYuval Mintz 		return rc;
439dacd88d6SYuval Mintz 
440dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
441dacd88d6SYuval Mintz 		return -EINVAL;
442dacd88d6SYuval Mintz 
443dacd88d6SYuval Mintz 	/* Learn the address of the producer from the response */
444d8c2c7e3SYuval Mintz 	if (pp_prod && !p_iov->b_pre_fp_hsi) {
445b21290b7SYuval Mintz 		u32 init_prod_val = 0;
446dacd88d6SYuval Mintz 
447dacd88d6SYuval Mintz 		*pp_prod = (u8 __iomem *)p_hwfn->regview + resp->offset;
448dacd88d6SYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_IOV,
449dacd88d6SYuval Mintz 			   "Rxq[0x%02x]: producer at %p [offset 0x%08x]\n",
450dacd88d6SYuval Mintz 			   rx_qid, *pp_prod, resp->offset);
451dacd88d6SYuval Mintz 
452dacd88d6SYuval Mintz 		/* Init the rcq, rx bd and rx sge (if valid) producers to 0 */
453b21290b7SYuval Mintz 		__internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32),
454dacd88d6SYuval Mintz 				  (u32 *)&init_prod_val);
455dacd88d6SYuval Mintz 	}
456dacd88d6SYuval Mintz 
457dacd88d6SYuval Mintz 	return rc;
458dacd88d6SYuval Mintz }
459dacd88d6SYuval Mintz 
460dacd88d6SYuval Mintz int qed_vf_pf_rxq_stop(struct qed_hwfn *p_hwfn, u16 rx_qid, bool cqe_completion)
461dacd88d6SYuval Mintz {
462dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
463dacd88d6SYuval Mintz 	struct vfpf_stop_rxqs_tlv *req;
464dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp;
465dacd88d6SYuval Mintz 	int rc;
466dacd88d6SYuval Mintz 
467dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
468dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_STOP_RXQS, sizeof(*req));
469dacd88d6SYuval Mintz 
470dacd88d6SYuval Mintz 	req->rx_qid = rx_qid;
471dacd88d6SYuval Mintz 	req->num_rxqs = 1;
472dacd88d6SYuval Mintz 	req->cqe_completion = cqe_completion;
473dacd88d6SYuval Mintz 
474dacd88d6SYuval Mintz 	/* add list termination tlv */
475dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
476dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
477dacd88d6SYuval Mintz 
478dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
479dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
480dacd88d6SYuval Mintz 	if (rc)
481dacd88d6SYuval Mintz 		return rc;
482dacd88d6SYuval Mintz 
483dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
484dacd88d6SYuval Mintz 		return -EINVAL;
485dacd88d6SYuval Mintz 
486dacd88d6SYuval Mintz 	return rc;
487dacd88d6SYuval Mintz }
488dacd88d6SYuval Mintz 
489dacd88d6SYuval Mintz int qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn,
490dacd88d6SYuval Mintz 			u16 tx_queue_id,
491dacd88d6SYuval Mintz 			u16 sb,
492dacd88d6SYuval Mintz 			u8 sb_index,
493dacd88d6SYuval Mintz 			dma_addr_t pbl_addr,
494dacd88d6SYuval Mintz 			u16 pbl_size, void __iomem **pp_doorbell)
495dacd88d6SYuval Mintz {
496dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
4975040acf5SYuval Mintz 	struct pfvf_start_queue_resp_tlv *resp;
498dacd88d6SYuval Mintz 	struct vfpf_start_txq_tlv *req;
499dacd88d6SYuval Mintz 	int rc;
500dacd88d6SYuval Mintz 
501dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
502dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_START_TXQ, sizeof(*req));
503dacd88d6SYuval Mintz 
504dacd88d6SYuval Mintz 	req->tx_qid = tx_queue_id;
505dacd88d6SYuval Mintz 
506dacd88d6SYuval Mintz 	/* Tx */
507dacd88d6SYuval Mintz 	req->pbl_addr = pbl_addr;
508dacd88d6SYuval Mintz 	req->pbl_size = pbl_size;
509dacd88d6SYuval Mintz 	req->hw_sb = sb;
510dacd88d6SYuval Mintz 	req->sb_index = sb_index;
511dacd88d6SYuval Mintz 
512dacd88d6SYuval Mintz 	/* add list termination tlv */
513dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
514dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
515dacd88d6SYuval Mintz 
5165040acf5SYuval Mintz 	resp = &p_iov->pf2vf_reply->queue_start;
517dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
518dacd88d6SYuval Mintz 	if (rc)
5195040acf5SYuval Mintz 		goto exit;
520dacd88d6SYuval Mintz 
5215040acf5SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
5225040acf5SYuval Mintz 		rc = -EINVAL;
5235040acf5SYuval Mintz 		goto exit;
5245040acf5SYuval Mintz 	}
525dacd88d6SYuval Mintz 
526dacd88d6SYuval Mintz 	if (pp_doorbell) {
527d8c2c7e3SYuval Mintz 		/* Modern PFs provide the actual offsets, while legacy
528d8c2c7e3SYuval Mintz 		 * provided only the queue id.
529d8c2c7e3SYuval Mintz 		 */
530d8c2c7e3SYuval Mintz 		if (!p_iov->b_pre_fp_hsi) {
531d8c2c7e3SYuval Mintz 			*pp_doorbell = (u8 __iomem *)p_hwfn->doorbells +
532d8c2c7e3SYuval Mintz 						     resp->offset;
533d8c2c7e3SYuval Mintz 		} else {
534d8c2c7e3SYuval Mintz 			u8 cid = p_iov->acquire_resp.resc.cid[tx_queue_id];
535d8c2c7e3SYuval Mintz 			u32 db_addr;
536d8c2c7e3SYuval Mintz 
537d8c2c7e3SYuval Mintz 			db_addr = qed_db_addr(cid, DQ_DEMS_LEGACY);
538d8c2c7e3SYuval Mintz 			*pp_doorbell = (u8 __iomem *)p_hwfn->doorbells +
539d8c2c7e3SYuval Mintz 						     db_addr;
540d8c2c7e3SYuval Mintz 		}
541dacd88d6SYuval Mintz 
5425040acf5SYuval Mintz 		DP_VERBOSE(p_hwfn, QED_MSG_IOV,
5435040acf5SYuval Mintz 			   "Txq[0x%02x]: doorbell at %p [offset 0x%08x]\n",
5445040acf5SYuval Mintz 			   tx_queue_id, *pp_doorbell, resp->offset);
545dacd88d6SYuval Mintz 	}
5465040acf5SYuval Mintz exit:
547dacd88d6SYuval Mintz 
548dacd88d6SYuval Mintz 	return rc;
549dacd88d6SYuval Mintz }
550dacd88d6SYuval Mintz 
551dacd88d6SYuval Mintz int qed_vf_pf_txq_stop(struct qed_hwfn *p_hwfn, u16 tx_qid)
552dacd88d6SYuval Mintz {
553dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
554dacd88d6SYuval Mintz 	struct vfpf_stop_txqs_tlv *req;
555dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp;
556dacd88d6SYuval Mintz 	int rc;
557dacd88d6SYuval Mintz 
558dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
559dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_STOP_TXQS, sizeof(*req));
560dacd88d6SYuval Mintz 
561dacd88d6SYuval Mintz 	req->tx_qid = tx_qid;
562dacd88d6SYuval Mintz 	req->num_txqs = 1;
563dacd88d6SYuval Mintz 
564dacd88d6SYuval Mintz 	/* add list termination tlv */
565dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
566dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
567dacd88d6SYuval Mintz 
568dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
569dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
570dacd88d6SYuval Mintz 	if (rc)
571dacd88d6SYuval Mintz 		return rc;
572dacd88d6SYuval Mintz 
573dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
574dacd88d6SYuval Mintz 		return -EINVAL;
575dacd88d6SYuval Mintz 
576dacd88d6SYuval Mintz 	return rc;
577dacd88d6SYuval Mintz }
578dacd88d6SYuval Mintz 
579dacd88d6SYuval Mintz int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn,
580dacd88d6SYuval Mintz 			  u8 vport_id,
581dacd88d6SYuval Mintz 			  u16 mtu,
582dacd88d6SYuval Mintz 			  u8 inner_vlan_removal,
583dacd88d6SYuval Mintz 			  enum qed_tpa_mode tpa_mode,
58408feecd7SYuval Mintz 			  u8 max_buffers_per_cqe, u8 only_untagged)
585dacd88d6SYuval Mintz {
586dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
587dacd88d6SYuval Mintz 	struct vfpf_vport_start_tlv *req;
588dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp;
589dacd88d6SYuval Mintz 	int rc, i;
590dacd88d6SYuval Mintz 
591dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
592dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_VPORT_START, sizeof(*req));
593dacd88d6SYuval Mintz 
594dacd88d6SYuval Mintz 	req->mtu = mtu;
595dacd88d6SYuval Mintz 	req->vport_id = vport_id;
596dacd88d6SYuval Mintz 	req->inner_vlan_removal = inner_vlan_removal;
597dacd88d6SYuval Mintz 	req->tpa_mode = tpa_mode;
598dacd88d6SYuval Mintz 	req->max_buffers_per_cqe = max_buffers_per_cqe;
59908feecd7SYuval Mintz 	req->only_untagged = only_untagged;
600dacd88d6SYuval Mintz 
601dacd88d6SYuval Mintz 	/* status blocks */
602dacd88d6SYuval Mintz 	for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++)
603dacd88d6SYuval Mintz 		if (p_hwfn->sbs_info[i])
604dacd88d6SYuval Mintz 			req->sb_addr[i] = p_hwfn->sbs_info[i]->sb_phys;
605dacd88d6SYuval Mintz 
606dacd88d6SYuval Mintz 	/* add list termination tlv */
607dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
608dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
609dacd88d6SYuval Mintz 
610dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
611dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
612dacd88d6SYuval Mintz 	if (rc)
613dacd88d6SYuval Mintz 		return rc;
614dacd88d6SYuval Mintz 
615dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
616dacd88d6SYuval Mintz 		return -EINVAL;
617dacd88d6SYuval Mintz 
618dacd88d6SYuval Mintz 	return rc;
619dacd88d6SYuval Mintz }
620dacd88d6SYuval Mintz 
621dacd88d6SYuval Mintz int qed_vf_pf_vport_stop(struct qed_hwfn *p_hwfn)
622dacd88d6SYuval Mintz {
623dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
624dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp = &p_iov->pf2vf_reply->default_resp;
625dacd88d6SYuval Mintz 	int rc;
626dacd88d6SYuval Mintz 
627dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
628dacd88d6SYuval Mintz 	qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_VPORT_TEARDOWN,
629dacd88d6SYuval Mintz 		       sizeof(struct vfpf_first_tlv));
630dacd88d6SYuval Mintz 
631dacd88d6SYuval Mintz 	/* add list termination tlv */
632dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
633dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
634dacd88d6SYuval Mintz 
635dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
636dacd88d6SYuval Mintz 	if (rc)
637dacd88d6SYuval Mintz 		return rc;
638dacd88d6SYuval Mintz 
639dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
640dacd88d6SYuval Mintz 		return -EINVAL;
641dacd88d6SYuval Mintz 
642dacd88d6SYuval Mintz 	return rc;
643dacd88d6SYuval Mintz }
644dacd88d6SYuval Mintz 
645dacd88d6SYuval Mintz static bool
646dacd88d6SYuval Mintz qed_vf_handle_vp_update_is_needed(struct qed_hwfn *p_hwfn,
647dacd88d6SYuval Mintz 				  struct qed_sp_vport_update_params *p_data,
648dacd88d6SYuval Mintz 				  u16 tlv)
649dacd88d6SYuval Mintz {
650dacd88d6SYuval Mintz 	switch (tlv) {
651dacd88d6SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_ACTIVATE:
652dacd88d6SYuval Mintz 		return !!(p_data->update_vport_active_rx_flg ||
653dacd88d6SYuval Mintz 			  p_data->update_vport_active_tx_flg);
65417b235c1SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH:
65517b235c1SYuval Mintz 		return !!p_data->update_tx_switching_flg;
65617b235c1SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_VLAN_STRIP:
65717b235c1SYuval Mintz 		return !!p_data->update_inner_vlan_removal_flg;
65808feecd7SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN:
65908feecd7SYuval Mintz 		return !!p_data->update_accept_any_vlan_flg;
660dacd88d6SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_MCAST:
661dacd88d6SYuval Mintz 		return !!p_data->update_approx_mcast_flg;
662dacd88d6SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM:
663dacd88d6SYuval Mintz 		return !!(p_data->accept_flags.update_rx_mode_config ||
664dacd88d6SYuval Mintz 			  p_data->accept_flags.update_tx_mode_config);
665dacd88d6SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_RSS:
666dacd88d6SYuval Mintz 		return !!p_data->rss_params;
66717b235c1SYuval Mintz 	case CHANNEL_TLV_VPORT_UPDATE_SGE_TPA:
66817b235c1SYuval Mintz 		return !!p_data->sge_tpa_params;
669dacd88d6SYuval Mintz 	default:
670dacd88d6SYuval Mintz 		DP_INFO(p_hwfn, "Unexpected vport-update TLV[%d]\n",
671dacd88d6SYuval Mintz 			tlv);
672dacd88d6SYuval Mintz 		return false;
673dacd88d6SYuval Mintz 	}
674dacd88d6SYuval Mintz }
675dacd88d6SYuval Mintz 
676dacd88d6SYuval Mintz static void
677dacd88d6SYuval Mintz qed_vf_handle_vp_update_tlvs_resp(struct qed_hwfn *p_hwfn,
678dacd88d6SYuval Mintz 				  struct qed_sp_vport_update_params *p_data)
679dacd88d6SYuval Mintz {
680dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
681dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *p_resp;
682dacd88d6SYuval Mintz 	u16 tlv;
683dacd88d6SYuval Mintz 
684dacd88d6SYuval Mintz 	for (tlv = CHANNEL_TLV_VPORT_UPDATE_ACTIVATE;
685dacd88d6SYuval Mintz 	     tlv < CHANNEL_TLV_VPORT_UPDATE_MAX; tlv++) {
686dacd88d6SYuval Mintz 		if (!qed_vf_handle_vp_update_is_needed(p_hwfn, p_data, tlv))
687dacd88d6SYuval Mintz 			continue;
688dacd88d6SYuval Mintz 
689dacd88d6SYuval Mintz 		p_resp = (struct pfvf_def_resp_tlv *)
690dacd88d6SYuval Mintz 			 qed_iov_search_list_tlvs(p_hwfn, p_iov->pf2vf_reply,
691dacd88d6SYuval Mintz 						  tlv);
692dacd88d6SYuval Mintz 		if (p_resp && p_resp->hdr.status)
693dacd88d6SYuval Mintz 			DP_VERBOSE(p_hwfn, QED_MSG_IOV,
694dacd88d6SYuval Mintz 				   "TLV[%d] Configuration %s\n",
695dacd88d6SYuval Mintz 				   tlv,
696dacd88d6SYuval Mintz 				   (p_resp && p_resp->hdr.status) ? "succeeded"
697dacd88d6SYuval Mintz 								  : "failed");
698dacd88d6SYuval Mintz 	}
699dacd88d6SYuval Mintz }
700dacd88d6SYuval Mintz 
701dacd88d6SYuval Mintz int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
702dacd88d6SYuval Mintz 			   struct qed_sp_vport_update_params *p_params)
703dacd88d6SYuval Mintz {
704dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
705dacd88d6SYuval Mintz 	struct vfpf_vport_update_tlv *req;
706dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp;
707dacd88d6SYuval Mintz 	u8 update_rx, update_tx;
708dacd88d6SYuval Mintz 	u32 resp_size = 0;
709dacd88d6SYuval Mintz 	u16 size, tlv;
710dacd88d6SYuval Mintz 	int rc;
711dacd88d6SYuval Mintz 
712dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
713dacd88d6SYuval Mintz 	resp_size = sizeof(*resp);
714dacd88d6SYuval Mintz 
715dacd88d6SYuval Mintz 	update_rx = p_params->update_vport_active_rx_flg;
716dacd88d6SYuval Mintz 	update_tx = p_params->update_vport_active_tx_flg;
717dacd88d6SYuval Mintz 
718dacd88d6SYuval Mintz 	/* clear mailbox and prep header tlv */
719dacd88d6SYuval Mintz 	qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_VPORT_UPDATE, sizeof(*req));
720dacd88d6SYuval Mintz 
721dacd88d6SYuval Mintz 	/* Prepare extended tlvs */
722dacd88d6SYuval Mintz 	if (update_rx || update_tx) {
723dacd88d6SYuval Mintz 		struct vfpf_vport_update_activate_tlv *p_act_tlv;
724dacd88d6SYuval Mintz 
725dacd88d6SYuval Mintz 		size = sizeof(struct vfpf_vport_update_activate_tlv);
726dacd88d6SYuval Mintz 		p_act_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
727dacd88d6SYuval Mintz 					CHANNEL_TLV_VPORT_UPDATE_ACTIVATE,
728dacd88d6SYuval Mintz 					size);
729dacd88d6SYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
730dacd88d6SYuval Mintz 
731dacd88d6SYuval Mintz 		if (update_rx) {
732dacd88d6SYuval Mintz 			p_act_tlv->update_rx = update_rx;
733dacd88d6SYuval Mintz 			p_act_tlv->active_rx = p_params->vport_active_rx_flg;
734dacd88d6SYuval Mintz 		}
735dacd88d6SYuval Mintz 
736dacd88d6SYuval Mintz 		if (update_tx) {
737dacd88d6SYuval Mintz 			p_act_tlv->update_tx = update_tx;
738dacd88d6SYuval Mintz 			p_act_tlv->active_tx = p_params->vport_active_tx_flg;
739dacd88d6SYuval Mintz 		}
740dacd88d6SYuval Mintz 	}
741dacd88d6SYuval Mintz 
742831bfb0eSYuval Mintz 	if (p_params->update_tx_switching_flg) {
743831bfb0eSYuval Mintz 		struct vfpf_vport_update_tx_switch_tlv *p_tx_switch_tlv;
744831bfb0eSYuval Mintz 
745831bfb0eSYuval Mintz 		size = sizeof(struct vfpf_vport_update_tx_switch_tlv);
746831bfb0eSYuval Mintz 		tlv = CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH;
747831bfb0eSYuval Mintz 		p_tx_switch_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
748831bfb0eSYuval Mintz 					      tlv, size);
749831bfb0eSYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
750831bfb0eSYuval Mintz 
751831bfb0eSYuval Mintz 		p_tx_switch_tlv->tx_switching = p_params->tx_switching_flg;
752831bfb0eSYuval Mintz 	}
753831bfb0eSYuval Mintz 
754dacd88d6SYuval Mintz 	if (p_params->update_approx_mcast_flg) {
755dacd88d6SYuval Mintz 		struct vfpf_vport_update_mcast_bin_tlv *p_mcast_tlv;
756dacd88d6SYuval Mintz 
757dacd88d6SYuval Mintz 		size = sizeof(struct vfpf_vport_update_mcast_bin_tlv);
758dacd88d6SYuval Mintz 		p_mcast_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
759dacd88d6SYuval Mintz 					  CHANNEL_TLV_VPORT_UPDATE_MCAST, size);
760dacd88d6SYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
761dacd88d6SYuval Mintz 
762dacd88d6SYuval Mintz 		memcpy(p_mcast_tlv->bins, p_params->bins,
763dacd88d6SYuval Mintz 		       sizeof(unsigned long) * ETH_MULTICAST_MAC_BINS_IN_REGS);
764dacd88d6SYuval Mintz 	}
765dacd88d6SYuval Mintz 
766dacd88d6SYuval Mintz 	update_rx = p_params->accept_flags.update_rx_mode_config;
767dacd88d6SYuval Mintz 	update_tx = p_params->accept_flags.update_tx_mode_config;
768dacd88d6SYuval Mintz 
769dacd88d6SYuval Mintz 	if (update_rx || update_tx) {
770dacd88d6SYuval Mintz 		struct vfpf_vport_update_accept_param_tlv *p_accept_tlv;
771dacd88d6SYuval Mintz 
772dacd88d6SYuval Mintz 		tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM;
773dacd88d6SYuval Mintz 		size = sizeof(struct vfpf_vport_update_accept_param_tlv);
774dacd88d6SYuval Mintz 		p_accept_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, tlv, size);
775dacd88d6SYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
776dacd88d6SYuval Mintz 
777dacd88d6SYuval Mintz 		if (update_rx) {
778dacd88d6SYuval Mintz 			p_accept_tlv->update_rx_mode = update_rx;
779dacd88d6SYuval Mintz 			p_accept_tlv->rx_accept_filter =
780dacd88d6SYuval Mintz 			    p_params->accept_flags.rx_accept_filter;
781dacd88d6SYuval Mintz 		}
782dacd88d6SYuval Mintz 
783dacd88d6SYuval Mintz 		if (update_tx) {
784dacd88d6SYuval Mintz 			p_accept_tlv->update_tx_mode = update_tx;
785dacd88d6SYuval Mintz 			p_accept_tlv->tx_accept_filter =
786dacd88d6SYuval Mintz 			    p_params->accept_flags.tx_accept_filter;
787dacd88d6SYuval Mintz 		}
788dacd88d6SYuval Mintz 	}
789dacd88d6SYuval Mintz 
790dacd88d6SYuval Mintz 	if (p_params->rss_params) {
791dacd88d6SYuval Mintz 		struct qed_rss_params *rss_params = p_params->rss_params;
792dacd88d6SYuval Mintz 		struct vfpf_vport_update_rss_tlv *p_rss_tlv;
793dacd88d6SYuval Mintz 
794dacd88d6SYuval Mintz 		size = sizeof(struct vfpf_vport_update_rss_tlv);
795dacd88d6SYuval Mintz 		p_rss_tlv = qed_add_tlv(p_hwfn,
796dacd88d6SYuval Mintz 					&p_iov->offset,
797dacd88d6SYuval Mintz 					CHANNEL_TLV_VPORT_UPDATE_RSS, size);
798dacd88d6SYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
799dacd88d6SYuval Mintz 
800dacd88d6SYuval Mintz 		if (rss_params->update_rss_config)
801dacd88d6SYuval Mintz 			p_rss_tlv->update_rss_flags |=
802dacd88d6SYuval Mintz 			    VFPF_UPDATE_RSS_CONFIG_FLAG;
803dacd88d6SYuval Mintz 		if (rss_params->update_rss_capabilities)
804dacd88d6SYuval Mintz 			p_rss_tlv->update_rss_flags |=
805dacd88d6SYuval Mintz 			    VFPF_UPDATE_RSS_CAPS_FLAG;
806dacd88d6SYuval Mintz 		if (rss_params->update_rss_ind_table)
807dacd88d6SYuval Mintz 			p_rss_tlv->update_rss_flags |=
808dacd88d6SYuval Mintz 			    VFPF_UPDATE_RSS_IND_TABLE_FLAG;
809dacd88d6SYuval Mintz 		if (rss_params->update_rss_key)
810dacd88d6SYuval Mintz 			p_rss_tlv->update_rss_flags |= VFPF_UPDATE_RSS_KEY_FLAG;
811dacd88d6SYuval Mintz 
812dacd88d6SYuval Mintz 		p_rss_tlv->rss_enable = rss_params->rss_enable;
813dacd88d6SYuval Mintz 		p_rss_tlv->rss_caps = rss_params->rss_caps;
814dacd88d6SYuval Mintz 		p_rss_tlv->rss_table_size_log = rss_params->rss_table_size_log;
815dacd88d6SYuval Mintz 		memcpy(p_rss_tlv->rss_ind_table, rss_params->rss_ind_table,
816dacd88d6SYuval Mintz 		       sizeof(rss_params->rss_ind_table));
817dacd88d6SYuval Mintz 		memcpy(p_rss_tlv->rss_key, rss_params->rss_key,
818dacd88d6SYuval Mintz 		       sizeof(rss_params->rss_key));
819dacd88d6SYuval Mintz 	}
820dacd88d6SYuval Mintz 
82108feecd7SYuval Mintz 	if (p_params->update_accept_any_vlan_flg) {
82208feecd7SYuval Mintz 		struct vfpf_vport_update_accept_any_vlan_tlv *p_any_vlan_tlv;
82308feecd7SYuval Mintz 
82408feecd7SYuval Mintz 		size = sizeof(struct vfpf_vport_update_accept_any_vlan_tlv);
82508feecd7SYuval Mintz 		tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN;
82608feecd7SYuval Mintz 		p_any_vlan_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, tlv, size);
82708feecd7SYuval Mintz 
82808feecd7SYuval Mintz 		resp_size += sizeof(struct pfvf_def_resp_tlv);
82908feecd7SYuval Mintz 		p_any_vlan_tlv->accept_any_vlan = p_params->accept_any_vlan;
83008feecd7SYuval Mintz 		p_any_vlan_tlv->update_accept_any_vlan_flg =
83108feecd7SYuval Mintz 		    p_params->update_accept_any_vlan_flg;
83208feecd7SYuval Mintz 	}
83308feecd7SYuval Mintz 
834dacd88d6SYuval Mintz 	/* add list termination tlv */
835dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
836dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
837dacd88d6SYuval Mintz 
838dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, resp_size);
839dacd88d6SYuval Mintz 	if (rc)
840dacd88d6SYuval Mintz 		return rc;
841dacd88d6SYuval Mintz 
842dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
843dacd88d6SYuval Mintz 		return -EINVAL;
844dacd88d6SYuval Mintz 
845dacd88d6SYuval Mintz 	qed_vf_handle_vp_update_tlvs_resp(p_hwfn, p_params);
846dacd88d6SYuval Mintz 
847dacd88d6SYuval Mintz 	return rc;
848dacd88d6SYuval Mintz }
849dacd88d6SYuval Mintz 
8500b55e27dSYuval Mintz int qed_vf_pf_reset(struct qed_hwfn *p_hwfn)
8510b55e27dSYuval Mintz {
8520b55e27dSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
8530b55e27dSYuval Mintz 	struct pfvf_def_resp_tlv *resp;
8540b55e27dSYuval Mintz 	struct vfpf_first_tlv *req;
8550b55e27dSYuval Mintz 	int rc;
8560b55e27dSYuval Mintz 
8570b55e27dSYuval Mintz 	/* clear mailbox and prep first tlv */
8580b55e27dSYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_CLOSE, sizeof(*req));
8590b55e27dSYuval Mintz 
8600b55e27dSYuval Mintz 	/* add list termination tlv */
8610b55e27dSYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
8620b55e27dSYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
8630b55e27dSYuval Mintz 
8640b55e27dSYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
8650b55e27dSYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
8660b55e27dSYuval Mintz 	if (rc)
8670b55e27dSYuval Mintz 		return rc;
8680b55e27dSYuval Mintz 
8690b55e27dSYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
8700b55e27dSYuval Mintz 		return -EAGAIN;
8710b55e27dSYuval Mintz 
8720b55e27dSYuval Mintz 	p_hwfn->b_int_enabled = 0;
8730b55e27dSYuval Mintz 
8740b55e27dSYuval Mintz 	return 0;
8750b55e27dSYuval Mintz }
8760b55e27dSYuval Mintz 
8770b55e27dSYuval Mintz int qed_vf_pf_release(struct qed_hwfn *p_hwfn)
8780b55e27dSYuval Mintz {
8790b55e27dSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
8800b55e27dSYuval Mintz 	struct pfvf_def_resp_tlv *resp;
8810b55e27dSYuval Mintz 	struct vfpf_first_tlv *req;
8820b55e27dSYuval Mintz 	u32 size;
8830b55e27dSYuval Mintz 	int rc;
8840b55e27dSYuval Mintz 
8850b55e27dSYuval Mintz 	/* clear mailbox and prep first tlv */
8860b55e27dSYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_RELEASE, sizeof(*req));
8870b55e27dSYuval Mintz 
8880b55e27dSYuval Mintz 	/* add list termination tlv */
8890b55e27dSYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
8900b55e27dSYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
8910b55e27dSYuval Mintz 
8920b55e27dSYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
8930b55e27dSYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
8940b55e27dSYuval Mintz 
8950b55e27dSYuval Mintz 	if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS)
8960b55e27dSYuval Mintz 		rc = -EAGAIN;
8970b55e27dSYuval Mintz 
8980b55e27dSYuval Mintz 	p_hwfn->b_int_enabled = 0;
8990b55e27dSYuval Mintz 
9000b55e27dSYuval Mintz 	if (p_iov->vf2pf_request)
9010b55e27dSYuval Mintz 		dma_free_coherent(&p_hwfn->cdev->pdev->dev,
9020b55e27dSYuval Mintz 				  sizeof(union vfpf_tlvs),
9030b55e27dSYuval Mintz 				  p_iov->vf2pf_request,
9040b55e27dSYuval Mintz 				  p_iov->vf2pf_request_phys);
9050b55e27dSYuval Mintz 	if (p_iov->pf2vf_reply)
9060b55e27dSYuval Mintz 		dma_free_coherent(&p_hwfn->cdev->pdev->dev,
9070b55e27dSYuval Mintz 				  sizeof(union pfvf_tlvs),
9080b55e27dSYuval Mintz 				  p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys);
9090b55e27dSYuval Mintz 
9100b55e27dSYuval Mintz 	if (p_iov->bulletin.p_virt) {
9110b55e27dSYuval Mintz 		size = sizeof(struct qed_bulletin_content);
9120b55e27dSYuval Mintz 		dma_free_coherent(&p_hwfn->cdev->pdev->dev,
9130b55e27dSYuval Mintz 				  size,
9140b55e27dSYuval Mintz 				  p_iov->bulletin.p_virt, p_iov->bulletin.phys);
9150b55e27dSYuval Mintz 	}
9160b55e27dSYuval Mintz 
9170b55e27dSYuval Mintz 	kfree(p_hwfn->vf_iov_info);
9180b55e27dSYuval Mintz 	p_hwfn->vf_iov_info = NULL;
9190b55e27dSYuval Mintz 
9200b55e27dSYuval Mintz 	return rc;
9210b55e27dSYuval Mintz }
9220b55e27dSYuval Mintz 
923dacd88d6SYuval Mintz void qed_vf_pf_filter_mcast(struct qed_hwfn *p_hwfn,
924dacd88d6SYuval Mintz 			    struct qed_filter_mcast *p_filter_cmd)
925dacd88d6SYuval Mintz {
926dacd88d6SYuval Mintz 	struct qed_sp_vport_update_params sp_params;
927dacd88d6SYuval Mintz 	int i;
928dacd88d6SYuval Mintz 
929dacd88d6SYuval Mintz 	memset(&sp_params, 0, sizeof(sp_params));
930dacd88d6SYuval Mintz 	sp_params.update_approx_mcast_flg = 1;
931dacd88d6SYuval Mintz 
932dacd88d6SYuval Mintz 	if (p_filter_cmd->opcode == QED_FILTER_ADD) {
933dacd88d6SYuval Mintz 		for (i = 0; i < p_filter_cmd->num_mc_addrs; i++) {
934dacd88d6SYuval Mintz 			u32 bit;
935dacd88d6SYuval Mintz 
936dacd88d6SYuval Mintz 			bit = qed_mcast_bin_from_mac(p_filter_cmd->mac[i]);
937dacd88d6SYuval Mintz 			__set_bit(bit, sp_params.bins);
938dacd88d6SYuval Mintz 		}
939dacd88d6SYuval Mintz 	}
940dacd88d6SYuval Mintz 
941dacd88d6SYuval Mintz 	qed_vf_pf_vport_update(p_hwfn, &sp_params);
942dacd88d6SYuval Mintz }
943dacd88d6SYuval Mintz 
944dacd88d6SYuval Mintz int qed_vf_pf_filter_ucast(struct qed_hwfn *p_hwfn,
945dacd88d6SYuval Mintz 			   struct qed_filter_ucast *p_ucast)
946dacd88d6SYuval Mintz {
947dacd88d6SYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
948dacd88d6SYuval Mintz 	struct vfpf_ucast_filter_tlv *req;
949dacd88d6SYuval Mintz 	struct pfvf_def_resp_tlv *resp;
950dacd88d6SYuval Mintz 	int rc;
951dacd88d6SYuval Mintz 
952dacd88d6SYuval Mintz 	/* clear mailbox and prep first tlv */
953dacd88d6SYuval Mintz 	req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_UCAST_FILTER, sizeof(*req));
954dacd88d6SYuval Mintz 	req->opcode = (u8) p_ucast->opcode;
955dacd88d6SYuval Mintz 	req->type = (u8) p_ucast->type;
956dacd88d6SYuval Mintz 	memcpy(req->mac, p_ucast->mac, ETH_ALEN);
957dacd88d6SYuval Mintz 	req->vlan = p_ucast->vlan;
958dacd88d6SYuval Mintz 
959dacd88d6SYuval Mintz 	/* add list termination tlv */
960dacd88d6SYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
961dacd88d6SYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
962dacd88d6SYuval Mintz 
963dacd88d6SYuval Mintz 	resp = &p_iov->pf2vf_reply->default_resp;
964dacd88d6SYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
965dacd88d6SYuval Mintz 	if (rc)
966dacd88d6SYuval Mintz 		return rc;
967dacd88d6SYuval Mintz 
968dacd88d6SYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
969dacd88d6SYuval Mintz 		return -EAGAIN;
970dacd88d6SYuval Mintz 
971dacd88d6SYuval Mintz 	return 0;
972dacd88d6SYuval Mintz }
973dacd88d6SYuval Mintz 
9740b55e27dSYuval Mintz int qed_vf_pf_int_cleanup(struct qed_hwfn *p_hwfn)
9750b55e27dSYuval Mintz {
9760b55e27dSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
9770b55e27dSYuval Mintz 	struct pfvf_def_resp_tlv *resp = &p_iov->pf2vf_reply->default_resp;
9780b55e27dSYuval Mintz 	int rc;
9790b55e27dSYuval Mintz 
9800b55e27dSYuval Mintz 	/* clear mailbox and prep first tlv */
9810b55e27dSYuval Mintz 	qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_INT_CLEANUP,
9820b55e27dSYuval Mintz 		       sizeof(struct vfpf_first_tlv));
9830b55e27dSYuval Mintz 
9840b55e27dSYuval Mintz 	/* add list termination tlv */
9850b55e27dSYuval Mintz 	qed_add_tlv(p_hwfn, &p_iov->offset,
9860b55e27dSYuval Mintz 		    CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
9870b55e27dSYuval Mintz 
9880b55e27dSYuval Mintz 	rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
9890b55e27dSYuval Mintz 	if (rc)
9900b55e27dSYuval Mintz 		return rc;
9910b55e27dSYuval Mintz 
9920b55e27dSYuval Mintz 	if (resp->hdr.status != PFVF_STATUS_SUCCESS)
9930b55e27dSYuval Mintz 		return -EINVAL;
9940b55e27dSYuval Mintz 
9950b55e27dSYuval Mintz 	return 0;
9960b55e27dSYuval Mintz }
9970b55e27dSYuval Mintz 
9981408cc1fSYuval Mintz u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id)
9991408cc1fSYuval Mintz {
10001408cc1fSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
10011408cc1fSYuval Mintz 
10021408cc1fSYuval Mintz 	if (!p_iov) {
10031408cc1fSYuval Mintz 		DP_NOTICE(p_hwfn, "vf_sriov_info isn't initialized\n");
10041408cc1fSYuval Mintz 		return 0;
10051408cc1fSYuval Mintz 	}
10061408cc1fSYuval Mintz 
10071408cc1fSYuval Mintz 	return p_iov->acquire_resp.resc.hw_sbs[sb_id].hw_sb_id;
10081408cc1fSYuval Mintz }
10091408cc1fSYuval Mintz 
101036558c3dSYuval Mintz int qed_vf_read_bulletin(struct qed_hwfn *p_hwfn, u8 *p_change)
101136558c3dSYuval Mintz {
101236558c3dSYuval Mintz 	struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
101336558c3dSYuval Mintz 	struct qed_bulletin_content shadow;
101436558c3dSYuval Mintz 	u32 crc, crc_size;
101536558c3dSYuval Mintz 
101636558c3dSYuval Mintz 	crc_size = sizeof(p_iov->bulletin.p_virt->crc);
101736558c3dSYuval Mintz 	*p_change = 0;
101836558c3dSYuval Mintz 
101936558c3dSYuval Mintz 	/* Need to guarantee PF is not in the middle of writing it */
102036558c3dSYuval Mintz 	memcpy(&shadow, p_iov->bulletin.p_virt, p_iov->bulletin.size);
102136558c3dSYuval Mintz 
102236558c3dSYuval Mintz 	/* If version did not update, no need to do anything */
102336558c3dSYuval Mintz 	if (shadow.version == p_iov->bulletin_shadow.version)
102436558c3dSYuval Mintz 		return 0;
102536558c3dSYuval Mintz 
102636558c3dSYuval Mintz 	/* Verify the bulletin we see is valid */
102736558c3dSYuval Mintz 	crc = crc32(0, (u8 *)&shadow + crc_size,
102836558c3dSYuval Mintz 		    p_iov->bulletin.size - crc_size);
102936558c3dSYuval Mintz 	if (crc != shadow.crc)
103036558c3dSYuval Mintz 		return -EAGAIN;
103136558c3dSYuval Mintz 
103236558c3dSYuval Mintz 	/* Set the shadow bulletin and process it */
103336558c3dSYuval Mintz 	memcpy(&p_iov->bulletin_shadow, &shadow, p_iov->bulletin.size);
103436558c3dSYuval Mintz 
103536558c3dSYuval Mintz 	DP_VERBOSE(p_hwfn, QED_MSG_IOV,
103636558c3dSYuval Mintz 		   "Read a bulletin update %08x\n", shadow.version);
103736558c3dSYuval Mintz 
103836558c3dSYuval Mintz 	*p_change = 1;
103936558c3dSYuval Mintz 
104036558c3dSYuval Mintz 	return 0;
104136558c3dSYuval Mintz }
104236558c3dSYuval Mintz 
104336558c3dSYuval Mintz void __qed_vf_get_link_params(struct qed_hwfn *p_hwfn,
104436558c3dSYuval Mintz 			      struct qed_mcp_link_params *p_params,
104536558c3dSYuval Mintz 			      struct qed_bulletin_content *p_bulletin)
104636558c3dSYuval Mintz {
104736558c3dSYuval Mintz 	memset(p_params, 0, sizeof(*p_params));
104836558c3dSYuval Mintz 
104936558c3dSYuval Mintz 	p_params->speed.autoneg = p_bulletin->req_autoneg;
105036558c3dSYuval Mintz 	p_params->speed.advertised_speeds = p_bulletin->req_adv_speed;
105136558c3dSYuval Mintz 	p_params->speed.forced_speed = p_bulletin->req_forced_speed;
105236558c3dSYuval Mintz 	p_params->pause.autoneg = p_bulletin->req_autoneg_pause;
105336558c3dSYuval Mintz 	p_params->pause.forced_rx = p_bulletin->req_forced_rx;
105436558c3dSYuval Mintz 	p_params->pause.forced_tx = p_bulletin->req_forced_tx;
105536558c3dSYuval Mintz 	p_params->loopback_mode = p_bulletin->req_loopback;
105636558c3dSYuval Mintz }
105736558c3dSYuval Mintz 
105836558c3dSYuval Mintz void qed_vf_get_link_params(struct qed_hwfn *p_hwfn,
105936558c3dSYuval Mintz 			    struct qed_mcp_link_params *params)
106036558c3dSYuval Mintz {
106136558c3dSYuval Mintz 	__qed_vf_get_link_params(p_hwfn, params,
106236558c3dSYuval Mintz 				 &(p_hwfn->vf_iov_info->bulletin_shadow));
106336558c3dSYuval Mintz }
106436558c3dSYuval Mintz 
106536558c3dSYuval Mintz void __qed_vf_get_link_state(struct qed_hwfn *p_hwfn,
106636558c3dSYuval Mintz 			     struct qed_mcp_link_state *p_link,
106736558c3dSYuval Mintz 			     struct qed_bulletin_content *p_bulletin)
106836558c3dSYuval Mintz {
106936558c3dSYuval Mintz 	memset(p_link, 0, sizeof(*p_link));
107036558c3dSYuval Mintz 
107136558c3dSYuval Mintz 	p_link->link_up = p_bulletin->link_up;
107236558c3dSYuval Mintz 	p_link->speed = p_bulletin->speed;
107336558c3dSYuval Mintz 	p_link->full_duplex = p_bulletin->full_duplex;
107436558c3dSYuval Mintz 	p_link->an = p_bulletin->autoneg;
107536558c3dSYuval Mintz 	p_link->an_complete = p_bulletin->autoneg_complete;
107636558c3dSYuval Mintz 	p_link->parallel_detection = p_bulletin->parallel_detection;
107736558c3dSYuval Mintz 	p_link->pfc_enabled = p_bulletin->pfc_enabled;
107836558c3dSYuval Mintz 	p_link->partner_adv_speed = p_bulletin->partner_adv_speed;
107936558c3dSYuval Mintz 	p_link->partner_tx_flow_ctrl_en = p_bulletin->partner_tx_flow_ctrl_en;
108036558c3dSYuval Mintz 	p_link->partner_rx_flow_ctrl_en = p_bulletin->partner_rx_flow_ctrl_en;
108136558c3dSYuval Mintz 	p_link->partner_adv_pause = p_bulletin->partner_adv_pause;
108236558c3dSYuval Mintz 	p_link->sfp_tx_fault = p_bulletin->sfp_tx_fault;
108336558c3dSYuval Mintz }
108436558c3dSYuval Mintz 
108536558c3dSYuval Mintz void qed_vf_get_link_state(struct qed_hwfn *p_hwfn,
108636558c3dSYuval Mintz 			   struct qed_mcp_link_state *link)
108736558c3dSYuval Mintz {
108836558c3dSYuval Mintz 	__qed_vf_get_link_state(p_hwfn, link,
108936558c3dSYuval Mintz 				&(p_hwfn->vf_iov_info->bulletin_shadow));
109036558c3dSYuval Mintz }
109136558c3dSYuval Mintz 
109236558c3dSYuval Mintz void __qed_vf_get_link_caps(struct qed_hwfn *p_hwfn,
109336558c3dSYuval Mintz 			    struct qed_mcp_link_capabilities *p_link_caps,
109436558c3dSYuval Mintz 			    struct qed_bulletin_content *p_bulletin)
109536558c3dSYuval Mintz {
109636558c3dSYuval Mintz 	memset(p_link_caps, 0, sizeof(*p_link_caps));
109736558c3dSYuval Mintz 	p_link_caps->speed_capabilities = p_bulletin->capability_speed;
109836558c3dSYuval Mintz }
109936558c3dSYuval Mintz 
110036558c3dSYuval Mintz void qed_vf_get_link_caps(struct qed_hwfn *p_hwfn,
110136558c3dSYuval Mintz 			  struct qed_mcp_link_capabilities *p_link_caps)
110236558c3dSYuval Mintz {
110336558c3dSYuval Mintz 	__qed_vf_get_link_caps(p_hwfn, p_link_caps,
110436558c3dSYuval Mintz 			       &(p_hwfn->vf_iov_info->bulletin_shadow));
110536558c3dSYuval Mintz }
110636558c3dSYuval Mintz 
11071408cc1fSYuval Mintz void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs)
11081408cc1fSYuval Mintz {
11091408cc1fSYuval Mintz 	*num_rxqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_rxqs;
11101408cc1fSYuval Mintz }
11111408cc1fSYuval Mintz 
11121408cc1fSYuval Mintz void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac)
11131408cc1fSYuval Mintz {
11141408cc1fSYuval Mintz 	memcpy(port_mac,
11151408cc1fSYuval Mintz 	       p_hwfn->vf_iov_info->acquire_resp.pfdev_info.port_mac, ETH_ALEN);
11161408cc1fSYuval Mintz }
11171408cc1fSYuval Mintz 
11181408cc1fSYuval Mintz void qed_vf_get_num_vlan_filters(struct qed_hwfn *p_hwfn, u8 *num_vlan_filters)
11191408cc1fSYuval Mintz {
11201408cc1fSYuval Mintz 	struct qed_vf_iov *p_vf;
11211408cc1fSYuval Mintz 
11221408cc1fSYuval Mintz 	p_vf = p_hwfn->vf_iov_info;
11231408cc1fSYuval Mintz 	*num_vlan_filters = p_vf->acquire_resp.resc.num_vlan_filters;
11241408cc1fSYuval Mintz }
11251408cc1fSYuval Mintz 
1126eff16960SYuval Mintz bool qed_vf_check_mac(struct qed_hwfn *p_hwfn, u8 *mac)
1127eff16960SYuval Mintz {
1128eff16960SYuval Mintz 	struct qed_bulletin_content *bulletin;
1129eff16960SYuval Mintz 
1130eff16960SYuval Mintz 	bulletin = &p_hwfn->vf_iov_info->bulletin_shadow;
1131eff16960SYuval Mintz 	if (!(bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED)))
1132eff16960SYuval Mintz 		return true;
1133eff16960SYuval Mintz 
1134eff16960SYuval Mintz 	/* Forbid VF from changing a MAC enforced by PF */
1135eff16960SYuval Mintz 	if (ether_addr_equal(bulletin->mac, mac))
1136eff16960SYuval Mintz 		return false;
1137eff16960SYuval Mintz 
1138eff16960SYuval Mintz 	return false;
1139eff16960SYuval Mintz }
1140eff16960SYuval Mintz 
1141eff16960SYuval Mintz bool qed_vf_bulletin_get_forced_mac(struct qed_hwfn *hwfn,
1142eff16960SYuval Mintz 				    u8 *dst_mac, u8 *p_is_forced)
1143eff16960SYuval Mintz {
1144eff16960SYuval Mintz 	struct qed_bulletin_content *bulletin;
1145eff16960SYuval Mintz 
1146eff16960SYuval Mintz 	bulletin = &hwfn->vf_iov_info->bulletin_shadow;
1147eff16960SYuval Mintz 
1148eff16960SYuval Mintz 	if (bulletin->valid_bitmap & (1 << MAC_ADDR_FORCED)) {
1149eff16960SYuval Mintz 		if (p_is_forced)
1150eff16960SYuval Mintz 			*p_is_forced = 1;
1151eff16960SYuval Mintz 	} else if (bulletin->valid_bitmap & (1 << VFPF_BULLETIN_MAC_ADDR)) {
1152eff16960SYuval Mintz 		if (p_is_forced)
1153eff16960SYuval Mintz 			*p_is_forced = 0;
1154eff16960SYuval Mintz 	} else {
1155eff16960SYuval Mintz 		return false;
1156eff16960SYuval Mintz 	}
1157eff16960SYuval Mintz 
1158eff16960SYuval Mintz 	ether_addr_copy(dst_mac, bulletin->mac);
1159eff16960SYuval Mintz 
1160eff16960SYuval Mintz 	return true;
1161eff16960SYuval Mintz }
1162eff16960SYuval Mintz 
11631408cc1fSYuval Mintz void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn,
11641408cc1fSYuval Mintz 			   u16 *fw_major, u16 *fw_minor,
11651408cc1fSYuval Mintz 			   u16 *fw_rev, u16 *fw_eng)
11661408cc1fSYuval Mintz {
11671408cc1fSYuval Mintz 	struct pf_vf_pfdev_info *info;
11681408cc1fSYuval Mintz 
11691408cc1fSYuval Mintz 	info = &p_hwfn->vf_iov_info->acquire_resp.pfdev_info;
11701408cc1fSYuval Mintz 
11711408cc1fSYuval Mintz 	*fw_major = info->fw_major;
11721408cc1fSYuval Mintz 	*fw_minor = info->fw_minor;
11731408cc1fSYuval Mintz 	*fw_rev = info->fw_rev;
11741408cc1fSYuval Mintz 	*fw_eng = info->fw_eng;
11751408cc1fSYuval Mintz }
117636558c3dSYuval Mintz 
117736558c3dSYuval Mintz static void qed_handle_bulletin_change(struct qed_hwfn *hwfn)
117836558c3dSYuval Mintz {
1179eff16960SYuval Mintz 	struct qed_eth_cb_ops *ops = hwfn->cdev->protocol_ops.eth;
1180eff16960SYuval Mintz 	u8 mac[ETH_ALEN], is_mac_exist, is_mac_forced;
1181eff16960SYuval Mintz 	void *cookie = hwfn->cdev->ops_cookie;
1182eff16960SYuval Mintz 
1183eff16960SYuval Mintz 	is_mac_exist = qed_vf_bulletin_get_forced_mac(hwfn, mac,
1184eff16960SYuval Mintz 						      &is_mac_forced);
1185eff16960SYuval Mintz 	if (is_mac_exist && is_mac_forced && cookie)
1186eff16960SYuval Mintz 		ops->force_mac(cookie, mac);
1187eff16960SYuval Mintz 
118836558c3dSYuval Mintz 	/* Always update link configuration according to bulletin */
118936558c3dSYuval Mintz 	qed_link_update(hwfn);
119036558c3dSYuval Mintz }
119136558c3dSYuval Mintz 
119236558c3dSYuval Mintz void qed_iov_vf_task(struct work_struct *work)
119336558c3dSYuval Mintz {
119436558c3dSYuval Mintz 	struct qed_hwfn *hwfn = container_of(work, struct qed_hwfn,
119536558c3dSYuval Mintz 					     iov_task.work);
119636558c3dSYuval Mintz 	u8 change = 0;
119736558c3dSYuval Mintz 
119836558c3dSYuval Mintz 	if (test_and_clear_bit(QED_IOV_WQ_STOP_WQ_FLAG, &hwfn->iov_task_flags))
119936558c3dSYuval Mintz 		return;
120036558c3dSYuval Mintz 
120136558c3dSYuval Mintz 	/* Handle bulletin board changes */
120236558c3dSYuval Mintz 	qed_vf_read_bulletin(hwfn, &change);
120336558c3dSYuval Mintz 	if (change)
120436558c3dSYuval Mintz 		qed_handle_bulletin_change(hwfn);
120536558c3dSYuval Mintz 
120636558c3dSYuval Mintz 	/* As VF is polling bulletin board, need to constantly re-schedule */
120736558c3dSYuval Mintz 	queue_delayed_work(hwfn->iov_wq, &hwfn->iov_task, HZ);
120836558c3dSYuval Mintz }
1209