xref: /linux/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell Octeon EP (EndPoint) Ethernet Driver
3  *
4  * Copyright (C) 2020 Marvell.
5  *
6  */
7 
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/string.h>
11 #include <linux/mutex.h>
12 #include <linux/jiffies.h>
13 #include <linux/sched.h>
14 #include <linux/sched/signal.h>
15 #include <linux/io.h>
16 #include <linux/pci.h>
17 #include <linux/etherdevice.h>
18 
19 #include "octep_config.h"
20 #include "octep_main.h"
21 #include "octep_pfvf_mbox.h"
22 #include "octep_ctrl_net.h"
23 
24 /* When a new command is implemented, the below table should be updated
25  * with new command and it's version info.
26  */
27 static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = {
28 	[0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1,
29 	[OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] =
30 		OCTEP_PFVF_MBOX_VERSION_V2
31 };
32 
33 static void octep_pfvf_validate_version(struct octep_device *oct,  u32 vf_id,
34 					union octep_pfvf_mbox_word cmd,
35 					union octep_pfvf_mbox_word *rsp)
36 {
37 	u32 vf_version = (u32)cmd.s_version.version;
38 
39 	dev_dbg(&oct->pdev->dev, "VF id:%d VF version:%d PF version:%d\n",
40 		vf_id, vf_version, OCTEP_PFVF_MBOX_VERSION_CURRENT);
41 	if (vf_version < OCTEP_PFVF_MBOX_VERSION_CURRENT)
42 		rsp->s_version.version = vf_version;
43 	else
44 		rsp->s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT;
45 
46 	oct->vf_info[vf_id].mbox_version = rsp->s_version.version;
47 	dev_dbg(&oct->pdev->dev, "VF id:%d negotiated VF version:%d\n",
48 		vf_id, oct->vf_info[vf_id].mbox_version);
49 
50 	rsp->s_version.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
51 }
52 
53 static void octep_pfvf_get_link_status(struct octep_device *oct, u32 vf_id,
54 				       union octep_pfvf_mbox_word cmd,
55 				       union octep_pfvf_mbox_word *rsp)
56 {
57 	int status;
58 
59 	status = octep_ctrl_net_get_link_status(oct, vf_id);
60 	if (status < 0) {
61 		rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
62 		dev_err(&oct->pdev->dev, "Get VF link status failed via host control Mbox\n");
63 		return;
64 	}
65 	rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
66 	rsp->s_link_status.status = status;
67 }
68 
69 static void octep_pfvf_set_link_status(struct octep_device *oct, u32 vf_id,
70 				       union octep_pfvf_mbox_word cmd,
71 				       union octep_pfvf_mbox_word *rsp)
72 {
73 	int err;
74 
75 	err = octep_ctrl_net_set_link_status(oct, vf_id, cmd.s_link_status.status, true);
76 	if (err) {
77 		rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
78 		dev_err(&oct->pdev->dev, "Set VF link status failed via host control Mbox\n");
79 		return;
80 	}
81 	rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
82 }
83 
84 static void octep_pfvf_set_rx_state(struct octep_device *oct, u32 vf_id,
85 				    union octep_pfvf_mbox_word cmd,
86 				    union octep_pfvf_mbox_word *rsp)
87 {
88 	int err;
89 
90 	err = octep_ctrl_net_set_rx_state(oct, vf_id, cmd.s_link_state.state, true);
91 	if (err) {
92 		rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
93 		dev_err(&oct->pdev->dev, "Set VF Rx link state failed via host control Mbox\n");
94 		return;
95 	}
96 	rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
97 }
98 
99 static int octep_send_notification(struct octep_device *oct, u32 vf_id,
100 				   union octep_pfvf_mbox_word cmd)
101 {
102 	u32 max_rings_per_vf, vf_mbox_queue;
103 	struct octep_mbox *mbox;
104 
105 	/* check if VF PF Mailbox is compatible for this notification */
106 	if (pfvf_cmd_versions[cmd.s.opcode] > oct->vf_info[vf_id].mbox_version) {
107 		dev_dbg(&oct->pdev->dev, "VF Mbox doesn't support Notification:%d on VF ver:%d\n",
108 			cmd.s.opcode, oct->vf_info[vf_id].mbox_version);
109 		return -EOPNOTSUPP;
110 	}
111 
112 	max_rings_per_vf = CFG_GET_MAX_RPVF(oct->conf);
113 	vf_mbox_queue = vf_id * max_rings_per_vf;
114 	if (!oct->mbox[vf_mbox_queue]) {
115 		dev_err(&oct->pdev->dev, "Notif obtained for bad mbox vf %d\n", vf_id);
116 		return -EINVAL;
117 	}
118 	mbox = oct->mbox[vf_mbox_queue];
119 
120 	mutex_lock(&mbox->lock);
121 	writeq(cmd.u64, mbox->pf_vf_data_reg);
122 	mutex_unlock(&mbox->lock);
123 
124 	return 0;
125 }
126 
127 static void octep_pfvf_set_mtu(struct octep_device *oct, u32 vf_id,
128 			       union octep_pfvf_mbox_word cmd,
129 			       union octep_pfvf_mbox_word *rsp)
130 {
131 	int err;
132 
133 	err = octep_ctrl_net_set_mtu(oct, vf_id, cmd.s_set_mtu.mtu, true);
134 	if (err) {
135 		rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
136 		dev_err(&oct->pdev->dev, "Set VF MTU failed via host control Mbox\n");
137 		return;
138 	}
139 	rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
140 }
141 
142 static void octep_pfvf_get_mtu(struct octep_device *oct, u32 vf_id,
143 			       union octep_pfvf_mbox_word cmd,
144 			       union octep_pfvf_mbox_word *rsp)
145 {
146 	int max_rx_pktlen = oct->netdev->max_mtu + (ETH_HLEN + ETH_FCS_LEN);
147 
148 	rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
149 	rsp->s_get_mtu.mtu = max_rx_pktlen;
150 }
151 
152 static void octep_pfvf_set_mac_addr(struct octep_device *oct,  u32 vf_id,
153 				    union octep_pfvf_mbox_word cmd,
154 				    union octep_pfvf_mbox_word *rsp)
155 {
156 	int err;
157 
158 	err = octep_ctrl_net_set_mac_addr(oct, vf_id, cmd.s_set_mac.mac_addr, true);
159 	if (err) {
160 		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
161 		dev_err(&oct->pdev->dev, "Set VF MAC address failed via host control Mbox\n");
162 		return;
163 	}
164 	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
165 }
166 
167 static void octep_pfvf_get_mac_addr(struct octep_device *oct,  u32 vf_id,
168 				    union octep_pfvf_mbox_word cmd,
169 				    union octep_pfvf_mbox_word *rsp)
170 {
171 	int err;
172 
173 	err = octep_ctrl_net_get_mac_addr(oct, vf_id, rsp->s_set_mac.mac_addr);
174 	if (err) {
175 		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
176 		dev_err(&oct->pdev->dev, "Get VF MAC address failed via host control Mbox\n");
177 		return;
178 	}
179 	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
180 }
181 
182 static void octep_pfvf_dev_remove(struct octep_device *oct,  u32 vf_id,
183 				  union octep_pfvf_mbox_word cmd,
184 				  union octep_pfvf_mbox_word *rsp)
185 {
186 	int err;
187 
188 	err = octep_ctrl_net_dev_remove(oct, vf_id);
189 	if (err) {
190 		rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
191 		dev_err(&oct->pdev->dev, "Failed to acknowledge fw of vf %d removal\n",
192 			vf_id);
193 		return;
194 	}
195 	rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
196 }
197 
198 static void octep_pfvf_get_fw_info(struct octep_device *oct,  u32 vf_id,
199 				   union octep_pfvf_mbox_word cmd,
200 				   union octep_pfvf_mbox_word *rsp)
201 {
202 	struct octep_fw_info fw_info;
203 	int err;
204 
205 	err = octep_ctrl_net_get_info(oct, vf_id, &fw_info);
206 	if (err) {
207 		rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
208 		dev_err(&oct->pdev->dev, "Get VF info failed via host control Mbox\n");
209 		return;
210 	}
211 
212 	rsp->s_fw_info.pkind = fw_info.pkind;
213 	rsp->s_fw_info.fsz = fw_info.fsz;
214 	rsp->s_fw_info.rx_ol_flags = fw_info.rx_ol_flags;
215 	rsp->s_fw_info.tx_ol_flags = fw_info.tx_ol_flags;
216 
217 	rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
218 }
219 
220 static void octep_pfvf_set_offloads(struct octep_device *oct, u32 vf_id,
221 				    union octep_pfvf_mbox_word cmd,
222 				    union octep_pfvf_mbox_word *rsp)
223 {
224 	struct octep_ctrl_net_offloads offloads = {
225 		.rx_offloads = cmd.s_offloads.rx_ol_flags,
226 		.tx_offloads = cmd.s_offloads.tx_ol_flags
227 	};
228 	int err;
229 
230 	err = octep_ctrl_net_set_offloads(oct, vf_id, &offloads, true);
231 	if (err) {
232 		rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
233 		dev_err(&oct->pdev->dev, "Set VF offloads failed via host control Mbox\n");
234 		return;
235 	}
236 	rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
237 }
238 
239 int octep_setup_pfvf_mbox(struct octep_device *oct)
240 {
241 	int i = 0, num_vfs = 0, rings_per_vf = 0;
242 	int ring = 0;
243 
244 	num_vfs = oct->conf->sriov_cfg.active_vfs;
245 	rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
246 
247 	for (i = 0; i < num_vfs; i++) {
248 		ring  = rings_per_vf * i;
249 		oct->mbox[ring] = vzalloc(sizeof(*oct->mbox[ring]));
250 
251 		if (!oct->mbox[ring])
252 			goto free_mbox;
253 
254 		memset(oct->mbox[ring], 0, sizeof(struct octep_mbox));
255 		memset(&oct->vf_info[i], 0, sizeof(struct octep_pfvf_info));
256 		mutex_init(&oct->mbox[ring]->lock);
257 		INIT_WORK(&oct->mbox[ring]->wk.work, octep_pfvf_mbox_work);
258 		oct->mbox[ring]->wk.ctxptr = oct->mbox[ring];
259 		oct->mbox[ring]->oct = oct;
260 		oct->mbox[ring]->vf_id = i;
261 		oct->hw_ops.setup_mbox_regs(oct, ring);
262 	}
263 	return 0;
264 
265 free_mbox:
266 	while (i) {
267 		i--;
268 		ring  = rings_per_vf * i;
269 		cancel_work_sync(&oct->mbox[ring]->wk.work);
270 		mutex_destroy(&oct->mbox[ring]->lock);
271 		vfree(oct->mbox[ring]);
272 		oct->mbox[ring] = NULL;
273 	}
274 	return -ENOMEM;
275 }
276 
277 void octep_delete_pfvf_mbox(struct octep_device *oct)
278 {
279 	int rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
280 	int num_vfs = oct->conf->sriov_cfg.active_vfs;
281 	int i = 0, ring = 0, vf_srn = 0;
282 
283 	for (i = 0; i < num_vfs; i++) {
284 		ring  = vf_srn + rings_per_vf * i;
285 		if (!oct->mbox[ring])
286 			continue;
287 
288 		if (work_pending(&oct->mbox[ring]->wk.work))
289 			cancel_work_sync(&oct->mbox[ring]->wk.work);
290 
291 		mutex_destroy(&oct->mbox[ring]->lock);
292 		vfree(oct->mbox[ring]);
293 		oct->mbox[ring] = NULL;
294 	}
295 }
296 
297 static void octep_pfvf_pf_get_data(struct octep_device *oct,
298 				   struct octep_mbox *mbox, int vf_id,
299 				   union octep_pfvf_mbox_word cmd,
300 				   union octep_pfvf_mbox_word *rsp)
301 {
302 	int length = 0;
303 	int i = 0;
304 	int err;
305 	struct octep_iface_link_info link_info;
306 	struct octep_iface_rx_stats rx_stats;
307 	struct octep_iface_tx_stats tx_stats;
308 
309 	rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
310 
311 	if (cmd.s_data.frag != OCTEP_PFVF_MBOX_MORE_FRAG_FLAG) {
312 		mbox->config_data_index = 0;
313 		memset(mbox->config_data, 0, MAX_VF_PF_MBOX_DATA_SIZE);
314 		/* Based on the OPCODE CMD the PF driver
315 		 * specific API should be called to fetch
316 		 * the requested data
317 		 */
318 		switch (cmd.s.opcode) {
319 		case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
320 			memset(&link_info, 0, sizeof(link_info));
321 			err = octep_ctrl_net_get_link_info(oct, vf_id, &link_info);
322 			if (!err) {
323 				mbox->message_len = sizeof(link_info);
324 				*((int32_t *)rsp->s_data.data) = mbox->message_len;
325 				memcpy(mbox->config_data, (u8 *)&link_info, sizeof(link_info));
326 			} else {
327 				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
328 				return;
329 			}
330 			break;
331 		case OCTEP_PFVF_MBOX_CMD_GET_STATS:
332 			memset(&rx_stats, 0, sizeof(rx_stats));
333 			memset(&tx_stats, 0, sizeof(tx_stats));
334 			err = octep_ctrl_net_get_if_stats(oct, vf_id, &rx_stats, &tx_stats);
335 			if (!err) {
336 				mbox->message_len = sizeof(rx_stats) + sizeof(tx_stats);
337 				*((int32_t *)rsp->s_data.data) = mbox->message_len;
338 				memcpy(mbox->config_data, (u8 *)&rx_stats, sizeof(rx_stats));
339 				memcpy(mbox->config_data + sizeof(rx_stats), (u8 *)&tx_stats,
340 				       sizeof(tx_stats));
341 
342 			} else {
343 				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
344 				return;
345 			}
346 			break;
347 		}
348 		*((int32_t *)rsp->s_data.data) = mbox->message_len;
349 		return;
350 	}
351 
352 	if (mbox->message_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE)
353 		length = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
354 	else
355 		length = mbox->message_len;
356 
357 	mbox->message_len -= length;
358 
359 	for (i = 0; i < length; i++) {
360 		rsp->s_data.data[i] =
361 			mbox->config_data[mbox->config_data_index];
362 		mbox->config_data_index++;
363 	}
364 }
365 
366 void octep_pfvf_notify(struct octep_device *oct, struct octep_ctrl_mbox_msg *msg)
367 {
368 	union octep_pfvf_mbox_word notif = { 0 };
369 	struct octep_ctrl_net_f2h_req *req;
370 
371 	req = (struct octep_ctrl_net_f2h_req *)msg->sg_list[0].msg;
372 	switch (req->hdr.s.cmd) {
373 	case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:
374 		notif.s_link_status.opcode = OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS;
375 		notif.s_link_status.status = req->link.state;
376 		break;
377 	default:
378 		pr_info("Unknown mbox notif for vf: %u\n",
379 			req->hdr.s.cmd);
380 		return;
381 	}
382 
383 	notif.s.type = OCTEP_PFVF_MBOX_TYPE_CMD;
384 	octep_send_notification(oct, msg->hdr.s.vf_idx, notif);
385 }
386 
387 void octep_pfvf_mbox_work(struct work_struct *work)
388 {
389 	struct octep_pfvf_mbox_wk *wk = container_of(work, struct octep_pfvf_mbox_wk, work);
390 	union octep_pfvf_mbox_word cmd = { 0 };
391 	union octep_pfvf_mbox_word rsp = { 0 };
392 	struct octep_mbox *mbox = NULL;
393 	struct octep_device *oct = NULL;
394 	int vf_id;
395 
396 	mbox = (struct octep_mbox *)wk->ctxptr;
397 	oct = (struct octep_device *)mbox->oct;
398 	vf_id = mbox->vf_id;
399 
400 	mutex_lock(&mbox->lock);
401 	cmd.u64 = readq(mbox->vf_pf_data_reg);
402 	rsp.u64 = 0;
403 
404 	switch (cmd.s.opcode) {
405 	case OCTEP_PFVF_MBOX_CMD_VERSION:
406 		octep_pfvf_validate_version(oct, vf_id, cmd, &rsp);
407 		break;
408 	case OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS:
409 		octep_pfvf_get_link_status(oct, vf_id, cmd, &rsp);
410 		break;
411 	case OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS:
412 		octep_pfvf_set_link_status(oct, vf_id, cmd, &rsp);
413 		break;
414 	case OCTEP_PFVF_MBOX_CMD_SET_RX_STATE:
415 		octep_pfvf_set_rx_state(oct, vf_id, cmd, &rsp);
416 		break;
417 	case OCTEP_PFVF_MBOX_CMD_SET_MTU:
418 		octep_pfvf_set_mtu(oct, vf_id, cmd, &rsp);
419 		break;
420 	case OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR:
421 		octep_pfvf_set_mac_addr(oct, vf_id, cmd, &rsp);
422 		break;
423 	case OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR:
424 		octep_pfvf_get_mac_addr(oct, vf_id, cmd, &rsp);
425 		break;
426 	case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
427 	case OCTEP_PFVF_MBOX_CMD_GET_STATS:
428 		octep_pfvf_pf_get_data(oct, mbox, vf_id, cmd, &rsp);
429 		break;
430 	case OCTEP_PFVF_MBOX_CMD_GET_MTU:
431 		octep_pfvf_get_mtu(oct, vf_id, cmd, &rsp);
432 		break;
433 	case OCTEP_PFVF_MBOX_CMD_DEV_REMOVE:
434 		octep_pfvf_dev_remove(oct, vf_id, cmd, &rsp);
435 		break;
436 	case OCTEP_PFVF_MBOX_CMD_GET_FW_INFO:
437 		octep_pfvf_get_fw_info(oct, vf_id, cmd, &rsp);
438 		break;
439 	case OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS:
440 		octep_pfvf_set_offloads(oct, vf_id, cmd, &rsp);
441 		break;
442 	default:
443 		dev_err(&oct->pdev->dev, "PF-VF mailbox: invalid opcode %d\n", cmd.s.opcode);
444 		rsp.s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
445 		break;
446 	}
447 	writeq(rsp.u64, mbox->vf_pf_data_reg);
448 	mutex_unlock(&mbox->lock);
449 }
450