brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · e6eb98d Raw
451 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell Octeon EP (EndPoint) Ethernet Driver3 *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 updated26 * 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_V232};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	else45		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	err = octep_ctrl_net_set_mac_addr(oct, vf_id, cmd.s_set_mac.mac_addr, true);160	if (err) {161		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;162		dev_err(&oct->pdev->dev, "Set VF MAC address failed via host control Mbox\n");163		return;164	}165	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;166}167 168static void octep_pfvf_get_mac_addr(struct octep_device *oct,  u32 vf_id,169				    union octep_pfvf_mbox_word cmd,170				    union octep_pfvf_mbox_word *rsp)171{172	int err;173 174	err = octep_ctrl_net_get_mac_addr(oct, vf_id, rsp->s_set_mac.mac_addr);175	if (err) {176		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;177		dev_err(&oct->pdev->dev, "Get VF MAC address failed via host control Mbox\n");178		return;179	}180	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;181}182 183static void octep_pfvf_dev_remove(struct octep_device *oct,  u32 vf_id,184				  union octep_pfvf_mbox_word cmd,185				  union octep_pfvf_mbox_word *rsp)186{187	int err;188 189	err = octep_ctrl_net_dev_remove(oct, vf_id);190	if (err) {191		rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;192		dev_err(&oct->pdev->dev, "Failed to acknowledge fw of vf %d removal\n",193			vf_id);194		return;195	}196	rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;197}198 199static void octep_pfvf_get_fw_info(struct octep_device *oct,  u32 vf_id,200				   union octep_pfvf_mbox_word cmd,201				   union octep_pfvf_mbox_word *rsp)202{203	struct octep_fw_info fw_info;204	int err;205 206	err = octep_ctrl_net_get_info(oct, vf_id, &fw_info);207	if (err) {208		rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;209		dev_err(&oct->pdev->dev, "Get VF info failed via host control Mbox\n");210		return;211	}212 213	rsp->s_fw_info.pkind = fw_info.pkind;214	rsp->s_fw_info.fsz = fw_info.fsz;215	rsp->s_fw_info.rx_ol_flags = fw_info.rx_ol_flags;216	rsp->s_fw_info.tx_ol_flags = fw_info.tx_ol_flags;217 218	rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;219}220 221static void octep_pfvf_set_offloads(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_ctrl_net_offloads offloads = {226		.rx_offloads = cmd.s_offloads.rx_ol_flags,227		.tx_offloads = cmd.s_offloads.tx_ol_flags228	};229	int err;230 231	err = octep_ctrl_net_set_offloads(oct, vf_id, &offloads, true);232	if (err) {233		rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;234		dev_err(&oct->pdev->dev, "Set VF offloads failed via host control Mbox\n");235		return;236	}237	rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;238}239 240int octep_setup_pfvf_mbox(struct octep_device *oct)241{242	int i = 0, num_vfs = 0, rings_per_vf = 0;243	int ring = 0;244 245	num_vfs = oct->conf->sriov_cfg.active_vfs;246	rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;247 248	for (i = 0; i < num_vfs; i++) {249		ring  = rings_per_vf * i;250		oct->mbox[ring] = vzalloc(sizeof(*oct->mbox[ring]));251 252		if (!oct->mbox[ring])253			goto free_mbox;254 255		memset(oct->mbox[ring], 0, sizeof(struct octep_mbox));256		memset(&oct->vf_info[i], 0, sizeof(struct octep_pfvf_info));257		mutex_init(&oct->mbox[ring]->lock);258		INIT_WORK(&oct->mbox[ring]->wk.work, octep_pfvf_mbox_work);259		oct->mbox[ring]->wk.ctxptr = oct->mbox[ring];260		oct->mbox[ring]->oct = oct;261		oct->mbox[ring]->vf_id = i;262		oct->hw_ops.setup_mbox_regs(oct, ring);263	}264	return 0;265 266free_mbox:267	while (i) {268		i--;269		ring  = rings_per_vf * i;270		cancel_work_sync(&oct->mbox[ring]->wk.work);271		mutex_destroy(&oct->mbox[ring]->lock);272		vfree(oct->mbox[ring]);273		oct->mbox[ring] = NULL;274	}275	return -ENOMEM;276}277 278void octep_delete_pfvf_mbox(struct octep_device *oct)279{280	int rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;281	int num_vfs = oct->conf->sriov_cfg.active_vfs;282	int i = 0, ring = 0, vf_srn = 0;283 284	for (i = 0; i < num_vfs; i++) {285		ring  = vf_srn + rings_per_vf * i;286		if (!oct->mbox[ring])287			continue;288 289		if (work_pending(&oct->mbox[ring]->wk.work))290			cancel_work_sync(&oct->mbox[ring]->wk.work);291 292		mutex_destroy(&oct->mbox[ring]->lock);293		vfree(oct->mbox[ring]);294		oct->mbox[ring] = NULL;295	}296}297 298static void octep_pfvf_pf_get_data(struct octep_device *oct,299				   struct octep_mbox *mbox, int vf_id,300				   union octep_pfvf_mbox_word cmd,301				   union octep_pfvf_mbox_word *rsp)302{303	int length = 0;304	int i = 0;305	int err;306	struct octep_iface_link_info link_info;307	struct octep_iface_rx_stats rx_stats;308	struct octep_iface_tx_stats tx_stats;309 310	rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;311 312	if (cmd.s_data.frag != OCTEP_PFVF_MBOX_MORE_FRAG_FLAG) {313		mbox->config_data_index = 0;314		memset(mbox->config_data, 0, MAX_VF_PF_MBOX_DATA_SIZE);315		/* Based on the OPCODE CMD the PF driver316		 * specific API should be called to fetch317		 * the requested data318		 */319		switch (cmd.s.opcode) {320		case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:321			memset(&link_info, 0, sizeof(link_info));322			err = octep_ctrl_net_get_link_info(oct, vf_id, &link_info);323			if (!err) {324				mbox->message_len = sizeof(link_info);325				*((int32_t *)rsp->s_data.data) = mbox->message_len;326				memcpy(mbox->config_data, (u8 *)&link_info, sizeof(link_info));327			} else {328				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;329				return;330			}331			break;332		case OCTEP_PFVF_MBOX_CMD_GET_STATS:333			memset(&rx_stats, 0, sizeof(rx_stats));334			memset(&tx_stats, 0, sizeof(tx_stats));335			err = octep_ctrl_net_get_if_stats(oct, vf_id, &rx_stats, &tx_stats);336			if (!err) {337				mbox->message_len = sizeof(rx_stats) + sizeof(tx_stats);338				*((int32_t *)rsp->s_data.data) = mbox->message_len;339				memcpy(mbox->config_data, (u8 *)&rx_stats, sizeof(rx_stats));340				memcpy(mbox->config_data + sizeof(rx_stats), (u8 *)&tx_stats,341				       sizeof(tx_stats));342 343			} else {344				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;345				return;346			}347			break;348		}349		*((int32_t *)rsp->s_data.data) = mbox->message_len;350		return;351	}352 353	if (mbox->message_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE)354		length = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;355	else356		length = mbox->message_len;357 358	mbox->message_len -= length;359 360	for (i = 0; i < length; i++) {361		rsp->s_data.data[i] =362			mbox->config_data[mbox->config_data_index];363		mbox->config_data_index++;364	}365}366 367void octep_pfvf_notify(struct octep_device *oct, struct octep_ctrl_mbox_msg *msg)368{369	union octep_pfvf_mbox_word notif = { 0 };370	struct octep_ctrl_net_f2h_req *req;371 372	req = (struct octep_ctrl_net_f2h_req *)msg->sg_list[0].msg;373	switch (req->hdr.s.cmd) {374	case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:375		notif.s_link_status.opcode = OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS;376		notif.s_link_status.status = req->link.state;377		break;378	default:379		pr_info("Unknown mbox notif for vf: %u\n",380			req->hdr.s.cmd);381		return;382	}383 384	notif.s.type = OCTEP_PFVF_MBOX_TYPE_CMD;385	octep_send_notification(oct, msg->hdr.s.vf_idx, notif);386}387 388void octep_pfvf_mbox_work(struct work_struct *work)389{390	struct octep_pfvf_mbox_wk *wk = container_of(work, struct octep_pfvf_mbox_wk, work);391	union octep_pfvf_mbox_word cmd = { 0 };392	union octep_pfvf_mbox_word rsp = { 0 };393	struct octep_mbox *mbox = NULL;394	struct octep_device *oct = NULL;395	int vf_id;396 397	mbox = (struct octep_mbox *)wk->ctxptr;398	oct = (struct octep_device *)mbox->oct;399	vf_id = mbox->vf_id;400 401	mutex_lock(&mbox->lock);402	cmd.u64 = readq(mbox->vf_pf_data_reg);403	rsp.u64 = 0;404 405	switch (cmd.s.opcode) {406	case OCTEP_PFVF_MBOX_CMD_VERSION:407		octep_pfvf_validate_version(oct, vf_id, cmd, &rsp);408		break;409	case OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS:410		octep_pfvf_get_link_status(oct, vf_id, cmd, &rsp);411		break;412	case OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS:413		octep_pfvf_set_link_status(oct, vf_id, cmd, &rsp);414		break;415	case OCTEP_PFVF_MBOX_CMD_SET_RX_STATE:416		octep_pfvf_set_rx_state(oct, vf_id, cmd, &rsp);417		break;418	case OCTEP_PFVF_MBOX_CMD_SET_MTU:419		octep_pfvf_set_mtu(oct, vf_id, cmd, &rsp);420		break;421	case OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR:422		octep_pfvf_set_mac_addr(oct, vf_id, cmd, &rsp);423		break;424	case OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR:425		octep_pfvf_get_mac_addr(oct, vf_id, cmd, &rsp);426		break;427	case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:428	case OCTEP_PFVF_MBOX_CMD_GET_STATS:429		octep_pfvf_pf_get_data(oct, mbox, vf_id, cmd, &rsp);430		break;431	case OCTEP_PFVF_MBOX_CMD_GET_MTU:432		octep_pfvf_get_mtu(oct, vf_id, cmd, &rsp);433		break;434	case OCTEP_PFVF_MBOX_CMD_DEV_REMOVE:435		octep_pfvf_dev_remove(oct, vf_id, cmd, &rsp);436		break;437	case OCTEP_PFVF_MBOX_CMD_GET_FW_INFO:438		octep_pfvf_get_fw_info(oct, vf_id, cmd, &rsp);439		break;440	case OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS:441		octep_pfvf_set_offloads(oct, vf_id, cmd, &rsp);442		break;443	default:444		dev_err(&oct->pdev->dev, "PF-VF mailbox: invalid opcode %d\n", cmd.s.opcode);445		rsp.s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;446		break;447	}448	writeq(rsp.u64, mbox->vf_pf_data_reg);449	mutex_unlock(&mbox->lock);450}451