File Index
Files and directories
Sign in
FILE

octep_vf_mbox.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_mbox.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Marvell Octeon EP (EndPoint) VF Ethernet Driver
  3 *
  4 * Copyright (C) 2020 Marvell.
  5 *
  6 */
  7#include <linux/types.h>
  8#include <linux/pci.h>
  9#include <linux/netdevice.h>
 10#include <linux/vmalloc.h>
 11#include "octep_vf_config.h"
 12#include "octep_vf_main.h"
 13
 14/* When a new command is implemented, the below table should be updated
 15 * with new command and it's version info.
 16 */
 17static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = {
 18	[0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1,
 19	[OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] =
 20		OCTEP_PFVF_MBOX_VERSION_V2
 21};
 22
 23int octep_vf_setup_mbox(struct octep_vf_device *oct)
 24{
 25	int ring = 0;
 26
 27	oct->mbox = vzalloc(sizeof(*oct->mbox));
 28	if (!oct->mbox)
 29		return -1;
 30
 31	mutex_init(&oct->mbox->lock);
 32
 33	oct->hw_ops.setup_mbox_regs(oct, ring);
 34	INIT_WORK(&oct->mbox->wk.work, octep_vf_mbox_work);
 35	oct->mbox->wk.ctxptr = oct;
 36	oct->mbox_neg_ver = OCTEP_PFVF_MBOX_VERSION_CURRENT;
 37	dev_info(&oct->pdev->dev, "setup vf mbox successfully\n");
 38	return 0;
 39}
 40
 41void octep_vf_delete_mbox(struct octep_vf_device *oct)
 42{
 43	if (oct->mbox) {
 44		if (work_pending(&oct->mbox->wk.work))
 45			cancel_work_sync(&oct->mbox->wk.work);
 46
 47		mutex_destroy(&oct->mbox->lock);
 48		vfree(oct->mbox);
 49		oct->mbox = NULL;
 50		dev_info(&oct->pdev->dev, "Deleted vf mbox successfully\n");
 51	}
 52}
 53
 54int octep_vf_mbox_version_check(struct octep_vf_device *oct)
 55{
 56	union octep_pfvf_mbox_word cmd;
 57	union octep_pfvf_mbox_word rsp;
 58	int ret;
 59
 60	cmd.u64 = 0;
 61	cmd.s_version.opcode = OCTEP_PFVF_MBOX_CMD_VERSION;
 62	cmd.s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT;
 63	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
 64	if (ret == OCTEP_PFVF_MBOX_CMD_STATUS_NACK) {
 65		dev_err(&oct->pdev->dev,
 66			"VF Mbox version is incompatible with PF\n");
 67		return -EINVAL;
 68	}
 69	oct->mbox_neg_ver = (u32)rsp.s_version.version;
 70	dev_dbg(&oct->pdev->dev,
 71		"VF Mbox version:%u Negotiated VF version with PF:%u\n",
 72		 (u32)cmd.s_version.version,
 73		 (u32)rsp.s_version.version);
 74	return 0;
 75}
 76
 77void octep_vf_mbox_work(struct work_struct *work)
 78{
 79	struct octep_vf_mbox_wk *wk = container_of(work, struct octep_vf_mbox_wk, work);
 80	struct octep_vf_iface_link_info *link_info;
 81	struct octep_vf_device *oct = NULL;
 82	struct octep_vf_mbox *mbox = NULL;
 83	union octep_pfvf_mbox_word *notif;
 84	u64 pf_vf_data;
 85
 86	oct = (struct octep_vf_device *)wk->ctxptr;
 87	link_info = &oct->link_info;
 88	mbox = oct->mbox;
 89	pf_vf_data = readq(mbox->mbox_read_reg);
 90
 91	notif = (union octep_pfvf_mbox_word *)&pf_vf_data;
 92
 93	switch (notif->s.opcode) {
 94	case OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS:
 95		if (notif->s_link_status.status) {
 96			link_info->oper_up = OCTEP_PFVF_LINK_STATUS_UP;
 97			netif_carrier_on(oct->netdev);
 98			dev_info(&oct->pdev->dev, "netif_carrier_on\n");
 99		} else {
100			link_info->oper_up = OCTEP_PFVF_LINK_STATUS_DOWN;
101			netif_carrier_off(oct->netdev);
102			dev_info(&oct->pdev->dev, "netif_carrier_off\n");
103		}
104		break;
105	default:
106		dev_err(&oct->pdev->dev,
107			"Received unsupported notif %d\n", notif->s.opcode);
108		break;
109	}
110}
111
112static int __octep_vf_mbox_send_cmd(struct octep_vf_device *oct,
113				    union octep_pfvf_mbox_word cmd,
114				    union octep_pfvf_mbox_word *rsp)
115{
116	struct octep_vf_mbox *mbox = oct->mbox;
117	u64 reg_val = 0ull;
118	int count;
119
120	if (!mbox)
121		return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
122
123	cmd.s.type = OCTEP_PFVF_MBOX_TYPE_CMD;
124	writeq(cmd.u64, mbox->mbox_write_reg);
125
126	/* No response for notification messages */
127	if (!rsp)
128		return 0;
129
130	for (count = 0; count < OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT; count++) {
131		usleep_range(1000, 1500);
132		reg_val = readq(mbox->mbox_write_reg);
133		if (reg_val != cmd.u64) {
134			rsp->u64 = reg_val;
135			break;
136		}
137	}
138	if (count == OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT) {
139		dev_err(&oct->pdev->dev, "mbox send command timed out\n");
140		return OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT;
141	}
142	if (rsp->s.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
143		dev_err(&oct->pdev->dev, "mbox_send: Received NACK\n");
144		return OCTEP_PFVF_MBOX_CMD_STATUS_NACK;
145	}
146	rsp->u64 = reg_val;
147	return 0;
148}
149
150int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd,
151			   union octep_pfvf_mbox_word *rsp)
152{
153	struct octep_vf_mbox *mbox = oct->mbox;
154	int ret;
155
156	if (!mbox)
157		return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
158	mutex_lock(&mbox->lock);
159	if (pfvf_cmd_versions[cmd.s.opcode] > oct->mbox_neg_ver) {
160		dev_dbg(&oct->pdev->dev, "CMD:%d not supported in Version:%d\n",
161			cmd.s.opcode, oct->mbox_neg_ver);
162		mutex_unlock(&mbox->lock);
163		return -EOPNOTSUPP;
164	}
165	ret = __octep_vf_mbox_send_cmd(oct, cmd, rsp);
166	mutex_unlock(&mbox->lock);
167	return ret;
168}
169
170int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode,
171			    u8 *data, int *size)
172{
173	struct octep_vf_mbox *mbox = oct->mbox;
174	union octep_pfvf_mbox_word cmd;
175	union octep_pfvf_mbox_word rsp;
176	int data_len = 0, tmp_len = 0;
177	int read_cnt, i = 0, ret;
178
179	if (!mbox)
180		return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP;
181
182	mutex_lock(&mbox->lock);
183	cmd.u64 = 0;
184	cmd.s_data.opcode = opcode;
185	cmd.s_data.frag = 0;
186	/* Send cmd to read data from PF */
187	ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp);
188	if (ret) {
189		dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n");
190		mutex_unlock(&mbox->lock);
191		return ret;
192	}
193	/*  PF sends the data length of requested CMD
194	 *  in  ACK
195	 */
196	data_len = *((int32_t *)rsp.s_data.data);
197	tmp_len = data_len;
198	cmd.u64 = 0;
199	rsp.u64 = 0;
200	cmd.s_data.opcode = opcode;
201	cmd.s_data.frag = 1;
202	while (data_len) {
203		ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp);
204		if (ret) {
205			dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n");
206			mutex_unlock(&mbox->lock);
207			mbox->mbox_data.data_index = 0;
208			memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE);
209			return ret;
210		}
211		if (data_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE) {
212			data_len -= OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
213			read_cnt = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
214		} else {
215			read_cnt = data_len;
216			data_len = 0;
217		}
218		for (i = 0; i < read_cnt; i++) {
219			mbox->mbox_data.recv_data[mbox->mbox_data.data_index] =
220				rsp.s_data.data[i];
221			mbox->mbox_data.data_index++;
222		}
223		cmd.u64 = 0;
224		rsp.u64 = 0;
225		cmd.s_data.opcode = opcode;
226		cmd.s_data.frag = 1;
227	}
228	memcpy(data, mbox->mbox_data.recv_data, tmp_len);
229	*size = tmp_len;
230	mbox->mbox_data.data_index = 0;
231	memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE);
232	mutex_unlock(&mbox->lock);
233	return 0;
234}
235
236int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu)
237{
238	int frame_size = mtu + ETH_HLEN + ETH_FCS_LEN;
239	union octep_pfvf_mbox_word cmd;
240	union octep_pfvf_mbox_word rsp;
241	int ret = 0;
242
243	if (mtu < ETH_MIN_MTU || frame_size > ETH_MAX_MTU) {
244		dev_err(&oct->pdev->dev,
245			"Failed to set MTU to %d MIN MTU:%d MAX MTU:%d\n",
246			mtu, ETH_MIN_MTU, ETH_MAX_MTU);
247		return -EINVAL;
248	}
249
250	cmd.u64 = 0;
251	cmd.s_set_mtu.opcode = OCTEP_PFVF_MBOX_CMD_SET_MTU;
252	cmd.s_set_mtu.mtu = mtu;
253
254	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
255	if (ret) {
256		dev_err(&oct->pdev->dev, "Mbox send failed; err=%d\n", ret);
257		return ret;
258	}
259	if (rsp.s_set_mtu.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
260		dev_err(&oct->pdev->dev, "Received Mbox NACK from PF for MTU:%d\n", mtu);
261		return -EINVAL;
262	}
263
264	return 0;
265}
266
267int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr)
268{
269	union octep_pfvf_mbox_word cmd;
270	union octep_pfvf_mbox_word rsp;
271	int i, ret;
272
273	cmd.u64 = 0;
274	cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR;
275	for (i = 0; i < ETH_ALEN; i++)
276		cmd.s_set_mac.mac_addr[i] = mac_addr[i];
277	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
278	if (ret) {
279		dev_err(&oct->pdev->dev, "Mbox send failed; err = %d\n", ret);
280		return ret;
281	}
282	if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
283		dev_err(&oct->pdev->dev, "received NACK\n");
284		return -EINVAL;
285	}
286	return 0;
287}
288
289int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr)
290{
291	union octep_pfvf_mbox_word cmd;
292	union octep_pfvf_mbox_word rsp;
293	int i, ret;
294
295	cmd.u64 = 0;
296	cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR;
297	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
298	if (ret) {
299		dev_err(&oct->pdev->dev, "get_mac: mbox send failed; err = %d\n", ret);
300		return ret;
301	}
302	if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
303		dev_err(&oct->pdev->dev, "get_mac: received NACK\n");
304		return -EINVAL;
305	}
306	for (i = 0; i < ETH_ALEN; i++)
307		mac_addr[i] = rsp.s_set_mac.mac_addr[i];
308	return 0;
309}
310
311int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state)
312{
313	union octep_pfvf_mbox_word cmd;
314	union octep_pfvf_mbox_word rsp;
315	int ret;
316
317	cmd.u64 = 0;
318	cmd.s_link_state.opcode = OCTEP_PFVF_MBOX_CMD_SET_RX_STATE;
319	cmd.s_link_state.state = state;
320	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
321	if (ret) {
322		dev_err(&oct->pdev->dev, "Set Rx state via VF Mbox send failed\n");
323		return ret;
324	}
325	if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
326		dev_err(&oct->pdev->dev, "Set Rx state received NACK\n");
327		return -EINVAL;
328	}
329	return 0;
330}
331
332int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status)
333{
334	union octep_pfvf_mbox_word cmd;
335	union octep_pfvf_mbox_word rsp;
336	int ret;
337
338	cmd.u64 = 0;
339	cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS;
340	cmd.s_link_status.status = status;
341	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
342	if (ret) {
343		dev_err(&oct->pdev->dev, "Set link status via VF Mbox send failed\n");
344		return ret;
345	}
346	if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
347		dev_err(&oct->pdev->dev, "Set link status received NACK\n");
348		return -EINVAL;
349	}
350	return 0;
351}
352
353int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up)
354{
355	union octep_pfvf_mbox_word cmd;
356	union octep_pfvf_mbox_word rsp;
357	int ret;
358
359	cmd.u64 = 0;
360	cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS;
361	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
362	if (ret) {
363		dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n");
364		return ret;
365	}
366	if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
367		dev_err(&oct->pdev->dev, "Get link status received NACK\n");
368		return -EINVAL;
369	}
370	*oper_up = rsp.s_link_status.status;
371	return 0;
372}
373
374int octep_vf_mbox_dev_remove(struct octep_vf_device *oct)
375{
376	union octep_pfvf_mbox_word cmd;
377	int ret;
378
379	cmd.u64 = 0;
380	cmd.s.opcode = OCTEP_PFVF_MBOX_CMD_DEV_REMOVE;
381	ret = octep_vf_mbox_send_cmd(oct, cmd, NULL);
382	return ret;
383}
384
385int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct)
386{
387	union octep_pfvf_mbox_word cmd;
388	union octep_pfvf_mbox_word rsp;
389	int ret;
390
391	cmd.u64 = 0;
392	cmd.s_fw_info.opcode = OCTEP_PFVF_MBOX_CMD_GET_FW_INFO;
393	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
394	if (ret) {
395		dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n");
396		return ret;
397	}
398	if (rsp.s_fw_info.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
399		dev_err(&oct->pdev->dev, "Get link status received NACK\n");
400		return -EINVAL;
401	}
402	oct->fw_info.pkind = rsp.s_fw_info.pkind;
403	oct->fw_info.fsz = rsp.s_fw_info.fsz;
404	oct->fw_info.rx_ol_flags = rsp.s_fw_info.rx_ol_flags;
405	oct->fw_info.tx_ol_flags = rsp.s_fw_info.tx_ol_flags;
406
407	return 0;
408}
409
410int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads,
411			       u16 rx_offloads)
412{
413	union octep_pfvf_mbox_word cmd;
414	union octep_pfvf_mbox_word rsp;
415	int ret;
416
417	cmd.u64 = 0;
418	cmd.s_offloads.opcode = OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS;
419	cmd.s_offloads.rx_ol_flags = rx_offloads;
420	cmd.s_offloads.tx_ol_flags = tx_offloads;
421	ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp);
422	if (ret) {
423		dev_err(&oct->pdev->dev, "Set offloads via VF Mbox send failed\n");
424		return ret;
425	}
426	if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) {
427		dev_err(&oct->pdev->dev, "Set offloads received NACK\n");
428		return -EINVAL;
429	}
430	return 0;
431}
~/ Read-only file preview.