File Index
Files and directories
Sign in
FILE

octep_pfvf_mbox.c

File preview with syntax highlighting.

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