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