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 */
27static 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
33static 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
53static 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, vfid: 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
69static 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, vfid: vf_id, up: cmd.s_link_status.status, wait_for_response: 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
84static 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, vfid: vf_id, up: cmd.s_link_state.state, wait_for_response: 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
99static 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(val: cmd.u64, addr: mbox->pf_vf_data_reg);
122 mutex_unlock(lock: &mbox->lock);
123
124 return 0;
125}
126
127static 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, vfid: vf_id, mtu: cmd.s_set_mtu.mtu, wait_for_response: 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
142static 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
152static 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, vfid: vf_id, addr: cmd.s_set_mac.mac_addr, wait_for_response: 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
167static 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, vfid: vf_id, addr: 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
182static 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, vfid: 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
198static 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, vfid: vf_id, info: &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
220static 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, vfid: vf_id, offloads: &offloads, wait_for_response: 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
239int 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(size: 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
265free_mbox:
266 while (i) {
267 i--;
268 ring = rings_per_vf * i;
269 cancel_work_sync(work: &oct->mbox[ring]->wk.work);
270 mutex_destroy(lock: &oct->mbox[ring]->lock);
271 vfree(addr: oct->mbox[ring]);
272 oct->mbox[ring] = NULL;
273 }
274 return -ENOMEM;
275}
276
277void 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(work: &oct->mbox[ring]->wk.work);
290
291 mutex_destroy(lock: &oct->mbox[ring]->lock);
292 vfree(addr: oct->mbox[ring]);
293 oct->mbox[ring] = NULL;
294 }
295}
296
297static 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, vfid: vf_id, link_info: &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, vfid: vf_id, rx_stats: &rx_stats, tx_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
366void 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, vf_id: msg->hdr.s.vf_idx, cmd: notif);
385}
386
387void 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(addr: 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: &rsp);
407 break;
408 case OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS:
409 octep_pfvf_get_link_status(oct, vf_id, cmd, rsp: &rsp);
410 break;
411 case OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS:
412 octep_pfvf_set_link_status(oct, vf_id, cmd, rsp: &rsp);
413 break;
414 case OCTEP_PFVF_MBOX_CMD_SET_RX_STATE:
415 octep_pfvf_set_rx_state(oct, vf_id, cmd, rsp: &rsp);
416 break;
417 case OCTEP_PFVF_MBOX_CMD_SET_MTU:
418 octep_pfvf_set_mtu(oct, vf_id, cmd, rsp: &rsp);
419 break;
420 case OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR:
421 octep_pfvf_set_mac_addr(oct, vf_id, cmd, rsp: &rsp);
422 break;
423 case OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR:
424 octep_pfvf_get_mac_addr(oct, vf_id, cmd, rsp: &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: &rsp);
429 break;
430 case OCTEP_PFVF_MBOX_CMD_GET_MTU:
431 octep_pfvf_get_mtu(oct, vf_id, cmd, rsp: &rsp);
432 break;
433 case OCTEP_PFVF_MBOX_CMD_DEV_REMOVE:
434 octep_pfvf_dev_remove(oct, vf_id, cmd, rsp: &rsp);
435 break;
436 case OCTEP_PFVF_MBOX_CMD_GET_FW_INFO:
437 octep_pfvf_get_fw_info(oct, vf_id, cmd, rsp: &rsp);
438 break;
439 case OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS:
440 octep_pfvf_set_offloads(oct, vf_id, cmd, rsp: &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(val: rsp.u64, addr: mbox->vf_pf_data_reg);
448 mutex_unlock(lock: &mbox->lock);
449}
450

source code of linux/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c