432 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Marvell Octeon EP (EndPoint) VF Ethernet Driver3 *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 updated15 * 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_V221};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 CMD194 * in ACK195 */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}432