162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "cptvf.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistatic void cptvf_send_msg_to_pf(struct cpt_vf *cptvf, struct cpt_mbox *mbx)
962306a36Sopenharmony_ci{
1062306a36Sopenharmony_ci	/* Writing mbox(1) causes interrupt */
1162306a36Sopenharmony_ci	cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0),
1262306a36Sopenharmony_ci			mbx->msg);
1362306a36Sopenharmony_ci	cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1),
1462306a36Sopenharmony_ci			mbx->data);
1562306a36Sopenharmony_ci}
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */
1862306a36Sopenharmony_civoid cptvf_handle_mbox_intr(struct cpt_vf *cptvf)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/*
2362306a36Sopenharmony_ci	 * MBOX[0] contains msg
2462306a36Sopenharmony_ci	 * MBOX[1] contains data
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	mbx.msg  = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0));
2762306a36Sopenharmony_ci	mbx.data = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1));
2862306a36Sopenharmony_ci	dev_dbg(&cptvf->pdev->dev, "%s: Mailbox msg 0x%llx from PF\n",
2962306a36Sopenharmony_ci		__func__, mbx.msg);
3062306a36Sopenharmony_ci	switch (mbx.msg) {
3162306a36Sopenharmony_ci	case CPT_MSG_READY:
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		cptvf->pf_acked = true;
3462306a36Sopenharmony_ci		cptvf->vfid = mbx.data;
3562306a36Sopenharmony_ci		dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid);
3662306a36Sopenharmony_ci		break;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci	case CPT_MSG_QBIND_GRP:
3962306a36Sopenharmony_ci		cptvf->pf_acked = true;
4062306a36Sopenharmony_ci		cptvf->vftype = mbx.data;
4162306a36Sopenharmony_ci		dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n",
4262306a36Sopenharmony_ci			cptvf->vfid, ((mbx.data == SE_TYPES) ? "SE" : "AE"),
4362306a36Sopenharmony_ci			cptvf->vfgrp);
4462306a36Sopenharmony_ci		break;
4562306a36Sopenharmony_ci	case CPT_MBOX_MSG_TYPE_ACK:
4662306a36Sopenharmony_ci		cptvf->pf_acked = true;
4762306a36Sopenharmony_ci		break;
4862306a36Sopenharmony_ci	case CPT_MBOX_MSG_TYPE_NACK:
4962306a36Sopenharmony_ci		cptvf->pf_nacked = true;
5062306a36Sopenharmony_ci		break;
5162306a36Sopenharmony_ci	default:
5262306a36Sopenharmony_ci		dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n",
5362306a36Sopenharmony_ci			mbx.msg);
5462306a36Sopenharmony_ci		break;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int cptvf_send_msg_to_pf_timeout(struct cpt_vf *cptvf,
5962306a36Sopenharmony_ci					struct cpt_mbox *mbx)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int timeout = CPT_MBOX_MSG_TIMEOUT;
6262306a36Sopenharmony_ci	int sleep = 10;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	cptvf->pf_acked = false;
6562306a36Sopenharmony_ci	cptvf->pf_nacked = false;
6662306a36Sopenharmony_ci	cptvf_send_msg_to_pf(cptvf, mbx);
6762306a36Sopenharmony_ci	/* Wait for previous message to be acked, timeout 2sec */
6862306a36Sopenharmony_ci	while (!cptvf->pf_acked) {
6962306a36Sopenharmony_ci		if (cptvf->pf_nacked)
7062306a36Sopenharmony_ci			return -EINVAL;
7162306a36Sopenharmony_ci		msleep(sleep);
7262306a36Sopenharmony_ci		if (cptvf->pf_acked)
7362306a36Sopenharmony_ci			break;
7462306a36Sopenharmony_ci		timeout -= sleep;
7562306a36Sopenharmony_ci		if (!timeout) {
7662306a36Sopenharmony_ci			dev_err(&cptvf->pdev->dev, "PF didn't ack to mbox msg %llx from VF%u\n",
7762306a36Sopenharmony_ci				(mbx->msg & 0xFF), cptvf->vfid);
7862306a36Sopenharmony_ci			return -EBUSY;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * Checks if VF is able to comminicate with PF
8762306a36Sopenharmony_ci * and also gets the CPT number this VF is associated to.
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_ciint cptvf_check_pf_ready(struct cpt_vf *cptvf)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
9262306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	mbx.msg = CPT_MSG_READY;
9562306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
9662306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to READY msg\n");
9762306a36Sopenharmony_ci		return -EBUSY;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF.
10562306a36Sopenharmony_ci * Must be ACKed.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ciint cptvf_send_vq_size_msg(struct cpt_vf *cptvf)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
11062306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	mbx.msg = CPT_MSG_QLEN;
11362306a36Sopenharmony_ci	mbx.data = cptvf->qsize;
11462306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
11562306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to vq_size msg\n");
11662306a36Sopenharmony_ci		return -EBUSY;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * Communicate VF group required to PF and get the VQ binded to that group
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_ciint cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
12862306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	mbx.msg = CPT_MSG_QBIND_GRP;
13162306a36Sopenharmony_ci	/* Convey group of the VF */
13262306a36Sopenharmony_ci	mbx.data = cptvf->vfgrp;
13362306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
13462306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
13562306a36Sopenharmony_ci		return -EBUSY;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * Communicate VF group required to PF and get the VQ binded to that group
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ciint cptvf_send_vf_priority_msg(struct cpt_vf *cptvf)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
14762306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	mbx.msg = CPT_MSG_VQ_PRIORITY;
15062306a36Sopenharmony_ci	/* Convey group of the VF */
15162306a36Sopenharmony_ci	mbx.data = cptvf->priority;
15262306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
15362306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
15462306a36Sopenharmony_ci		return -EBUSY;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Communicate to PF that VF is UP and running
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ciint cptvf_send_vf_up(struct cpt_vf *cptvf)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
16562306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	mbx.msg = CPT_MSG_VF_UP;
16862306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
16962306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to UP msg\n");
17062306a36Sopenharmony_ci		return -EBUSY;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/*
17762306a36Sopenharmony_ci * Communicate to PF that VF is DOWN and running
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ciint cptvf_send_vf_down(struct cpt_vf *cptvf)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct pci_dev *pdev = cptvf->pdev;
18262306a36Sopenharmony_ci	struct cpt_mbox mbx = {};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	mbx.msg = CPT_MSG_VF_DOWN;
18562306a36Sopenharmony_ci	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
18662306a36Sopenharmony_ci		dev_err(&pdev->dev, "PF didn't respond to DOWN msg\n");
18762306a36Sopenharmony_ci		return -EBUSY;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
192