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