1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2016 Cavium, Inc.
4  */
5 
6 #include "cptvf.h"
7 
cptvf_send_msg_to_pf(struct cpt_vf * cptvf,struct cpt_mbox * mbx)8 static void cptvf_send_msg_to_pf(struct cpt_vf *cptvf, struct cpt_mbox *mbx)
9 {
10 	/* Writing mbox(1) causes interrupt */
11 	cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0),
12 			mbx->msg);
13 	cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1),
14 			mbx->data);
15 }
16 
17 /* Interrupt handler to handle mailbox messages from VFs */
cptvf_handle_mbox_intr(struct cpt_vf * cptvf)18 void cptvf_handle_mbox_intr(struct cpt_vf *cptvf)
19 {
20 	struct cpt_mbox mbx = {};
21 
22 	/*
23 	 * MBOX[0] contains msg
24 	 * MBOX[1] contains data
25 	 */
26 	mbx.msg  = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0));
27 	mbx.data = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1));
28 	dev_dbg(&cptvf->pdev->dev, "%s: Mailbox msg 0x%llx from PF\n",
29 		__func__, mbx.msg);
30 	switch (mbx.msg) {
31 	case CPT_MSG_READY:
32 	{
33 		cptvf->pf_acked = true;
34 		cptvf->vfid = mbx.data;
35 		dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid);
36 		break;
37 	}
38 	case CPT_MSG_QBIND_GRP:
39 		cptvf->pf_acked = true;
40 		cptvf->vftype = mbx.data;
41 		dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n",
42 			cptvf->vfid, ((mbx.data == SE_TYPES) ? "SE" : "AE"),
43 			cptvf->vfgrp);
44 		break;
45 	case CPT_MBOX_MSG_TYPE_ACK:
46 		cptvf->pf_acked = true;
47 		break;
48 	case CPT_MBOX_MSG_TYPE_NACK:
49 		cptvf->pf_nacked = true;
50 		break;
51 	default:
52 		dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n",
53 			mbx.msg);
54 		break;
55 	}
56 }
57 
cptvf_send_msg_to_pf_timeout(struct cpt_vf * cptvf,struct cpt_mbox * mbx)58 static int cptvf_send_msg_to_pf_timeout(struct cpt_vf *cptvf,
59 					struct cpt_mbox *mbx)
60 {
61 	int timeout = CPT_MBOX_MSG_TIMEOUT;
62 	int sleep = 10;
63 
64 	cptvf->pf_acked = false;
65 	cptvf->pf_nacked = false;
66 	cptvf_send_msg_to_pf(cptvf, mbx);
67 	/* Wait for previous message to be acked, timeout 2sec */
68 	while (!cptvf->pf_acked) {
69 		if (cptvf->pf_nacked)
70 			return -EINVAL;
71 		msleep(sleep);
72 		if (cptvf->pf_acked)
73 			break;
74 		timeout -= sleep;
75 		if (!timeout) {
76 			dev_err(&cptvf->pdev->dev, "PF didn't ack to mbox msg %llx from VF%u\n",
77 				(mbx->msg & 0xFF), cptvf->vfid);
78 			return -EBUSY;
79 		}
80 	}
81 
82 	return 0;
83 }
84 
85 /*
86  * Checks if VF is able to comminicate with PF
87  * and also gets the CPT number this VF is associated to.
88  */
cptvf_check_pf_ready(struct cpt_vf * cptvf)89 int cptvf_check_pf_ready(struct cpt_vf *cptvf)
90 {
91 	struct pci_dev *pdev = cptvf->pdev;
92 	struct cpt_mbox mbx = {};
93 
94 	mbx.msg = CPT_MSG_READY;
95 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
96 		dev_err(&pdev->dev, "PF didn't respond to READY msg\n");
97 		return -EBUSY;
98 	}
99 
100 	return 0;
101 }
102 
103 /*
104  * Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF.
105  * Must be ACKed.
106  */
cptvf_send_vq_size_msg(struct cpt_vf * cptvf)107 int cptvf_send_vq_size_msg(struct cpt_vf *cptvf)
108 {
109 	struct pci_dev *pdev = cptvf->pdev;
110 	struct cpt_mbox mbx = {};
111 
112 	mbx.msg = CPT_MSG_QLEN;
113 	mbx.data = cptvf->qsize;
114 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
115 		dev_err(&pdev->dev, "PF didn't respond to vq_size msg\n");
116 		return -EBUSY;
117 	}
118 
119 	return 0;
120 }
121 
122 /*
123  * Communicate VF group required to PF and get the VQ binded to that group
124  */
cptvf_send_vf_to_grp_msg(struct cpt_vf * cptvf)125 int cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf)
126 {
127 	struct pci_dev *pdev = cptvf->pdev;
128 	struct cpt_mbox mbx = {};
129 
130 	mbx.msg = CPT_MSG_QBIND_GRP;
131 	/* Convey group of the VF */
132 	mbx.data = cptvf->vfgrp;
133 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
134 		dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
135 		return -EBUSY;
136 	}
137 
138 	return 0;
139 }
140 
141 /*
142  * Communicate VF group required to PF and get the VQ binded to that group
143  */
cptvf_send_vf_priority_msg(struct cpt_vf * cptvf)144 int cptvf_send_vf_priority_msg(struct cpt_vf *cptvf)
145 {
146 	struct pci_dev *pdev = cptvf->pdev;
147 	struct cpt_mbox mbx = {};
148 
149 	mbx.msg = CPT_MSG_VQ_PRIORITY;
150 	/* Convey group of the VF */
151 	mbx.data = cptvf->priority;
152 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
153 		dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
154 		return -EBUSY;
155 	}
156 	return 0;
157 }
158 
159 /*
160  * Communicate to PF that VF is UP and running
161  */
cptvf_send_vf_up(struct cpt_vf * cptvf)162 int cptvf_send_vf_up(struct cpt_vf *cptvf)
163 {
164 	struct pci_dev *pdev = cptvf->pdev;
165 	struct cpt_mbox mbx = {};
166 
167 	mbx.msg = CPT_MSG_VF_UP;
168 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
169 		dev_err(&pdev->dev, "PF didn't respond to UP msg\n");
170 		return -EBUSY;
171 	}
172 
173 	return 0;
174 }
175 
176 /*
177  * Communicate to PF that VF is DOWN and running
178  */
cptvf_send_vf_down(struct cpt_vf * cptvf)179 int cptvf_send_vf_down(struct cpt_vf *cptvf)
180 {
181 	struct pci_dev *pdev = cptvf->pdev;
182 	struct cpt_mbox mbx = {};
183 
184 	mbx.msg = CPT_MSG_VF_DOWN;
185 	if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
186 		dev_err(&pdev->dev, "PF didn't respond to DOWN msg\n");
187 		return -EBUSY;
188 	}
189 
190 	return 0;
191 }
192