]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/net/ethernet/intel/i40evf/i40evf_client.c
Merge remote-tracking branches 'asoc/topic/dwc', 'asoc/topic/fallthrough', 'asoc...
[mirror_ubuntu-bionic-kernel.git] / drivers / net / ethernet / intel / i40evf / i40evf_client.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/list.h>
3 #include <linux/errno.h>
4
5 #include "i40evf.h"
6 #include "i40e_prototype.h"
7 #include "i40evf_client.h"
8
9 static
10 const char i40evf_client_interface_version_str[] = I40EVF_CLIENT_VERSION_STR;
11 static struct i40e_client *vf_registered_client;
12 static LIST_HEAD(i40evf_devices);
13 static DEFINE_MUTEX(i40evf_device_mutex);
14
15 static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
16 struct i40e_client *client,
17 u8 *msg, u16 len);
18
19 static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
20 struct i40e_client *client,
21 struct i40e_qvlist_info *qvlist_info);
22
23 static struct i40e_ops i40evf_lan_ops = {
24 .virtchnl_send = i40evf_client_virtchnl_send,
25 .setup_qvlist = i40evf_client_setup_qvlist,
26 };
27
28 /**
29 * i40evf_notify_client_message - call the client message receive callback
30 * @vsi: the VSI associated with this client
31 * @msg: message buffer
32 * @len: length of message
33 *
34 * If there is a client to this VSI, call the client
35 **/
36 void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len)
37 {
38 struct i40e_client_instance *cinst;
39
40 if (!vsi)
41 return;
42
43 cinst = vsi->back->cinst;
44 if (!cinst || !cinst->client || !cinst->client->ops ||
45 !cinst->client->ops->virtchnl_receive) {
46 dev_dbg(&vsi->back->pdev->dev,
47 "Cannot locate client instance virtchnl_receive function\n");
48 return;
49 }
50 cinst->client->ops->virtchnl_receive(&cinst->lan_info, cinst->client,
51 msg, len);
52 }
53
54 /**
55 * i40evf_notify_client_l2_params - call the client notify callback
56 * @vsi: the VSI with l2 param changes
57 *
58 * If there is a client to this VSI, call the client
59 **/
60 void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
61 {
62 struct i40e_client_instance *cinst;
63 struct i40e_params params;
64
65 if (!vsi)
66 return;
67
68 cinst = vsi->back->cinst;
69 memset(&params, 0, sizeof(params));
70 params.mtu = vsi->netdev->mtu;
71 params.link_up = vsi->back->link_up;
72 params.qos.prio_qos[0].qs_handle = vsi->qs_handle;
73
74 if (!cinst || !cinst->client || !cinst->client->ops ||
75 !cinst->client->ops->l2_param_change) {
76 dev_dbg(&vsi->back->pdev->dev,
77 "Cannot locate client instance l2_param_change function\n");
78 return;
79 }
80 cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client,
81 &params);
82 }
83
84 /**
85 * i40evf_notify_client_open - call the client open callback
86 * @vsi: the VSI with netdev opened
87 *
88 * If there is a client to this netdev, call the client with open
89 **/
90 void i40evf_notify_client_open(struct i40e_vsi *vsi)
91 {
92 struct i40evf_adapter *adapter = vsi->back;
93 struct i40e_client_instance *cinst = adapter->cinst;
94 int ret;
95
96 if (!cinst || !cinst->client || !cinst->client->ops ||
97 !cinst->client->ops->open) {
98 dev_dbg(&vsi->back->pdev->dev,
99 "Cannot locate client instance open function\n");
100 return;
101 }
102 if (!(test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state))) {
103 ret = cinst->client->ops->open(&cinst->lan_info, cinst->client);
104 if (!ret)
105 set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
106 }
107 }
108
109 /**
110 * i40evf_client_release_qvlist - send a message to the PF to release iwarp qv map
111 * @ldev: pointer to L2 context.
112 *
113 * Return 0 on success or < 0 on error
114 **/
115 static int i40evf_client_release_qvlist(struct i40e_info *ldev)
116 {
117 struct i40evf_adapter *adapter = ldev->vf;
118 i40e_status err;
119
120 if (adapter->aq_required)
121 return -EAGAIN;
122
123 err = i40e_aq_send_msg_to_pf(&adapter->hw,
124 VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
125 I40E_SUCCESS, NULL, 0, NULL);
126
127 if (err)
128 dev_err(&adapter->pdev->dev,
129 "Unable to send iWarp vector release message to PF, error %d, aq status %d\n",
130 err, adapter->hw.aq.asq_last_status);
131
132 return err;
133 }
134
135 /**
136 * i40evf_notify_client_close - call the client close callback
137 * @vsi: the VSI with netdev closed
138 * @reset: true when close called due to reset pending
139 *
140 * If there is a client to this netdev, call the client with close
141 **/
142 void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset)
143 {
144 struct i40evf_adapter *adapter = vsi->back;
145 struct i40e_client_instance *cinst = adapter->cinst;
146
147 if (!cinst || !cinst->client || !cinst->client->ops ||
148 !cinst->client->ops->close) {
149 dev_dbg(&vsi->back->pdev->dev,
150 "Cannot locate client instance close function\n");
151 return;
152 }
153 cinst->client->ops->close(&cinst->lan_info, cinst->client, reset);
154 i40evf_client_release_qvlist(&cinst->lan_info);
155 clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
156 }
157
158 /**
159 * i40evf_client_add_instance - add a client instance to the instance list
160 * @adapter: pointer to the board struct
161 * @client: pointer to a client struct in the client list.
162 *
163 * Returns cinst ptr on success, NULL on failure
164 **/
165 static struct i40e_client_instance *
166 i40evf_client_add_instance(struct i40evf_adapter *adapter)
167 {
168 struct i40e_client_instance *cinst = NULL;
169 struct netdev_hw_addr *mac = NULL;
170 struct i40e_vsi *vsi = &adapter->vsi;
171 int i;
172
173 if (!vf_registered_client)
174 goto out;
175
176 if (adapter->cinst) {
177 cinst = adapter->cinst;
178 goto out;
179 }
180
181 cinst = kzalloc(sizeof(*cinst), GFP_KERNEL);
182 if (!cinst)
183 goto out;
184
185 cinst->lan_info.vf = (void *)adapter;
186 cinst->lan_info.netdev = vsi->netdev;
187 cinst->lan_info.pcidev = adapter->pdev;
188 cinst->lan_info.fid = 0;
189 cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF;
190 cinst->lan_info.hw_addr = adapter->hw.hw_addr;
191 cinst->lan_info.ops = &i40evf_lan_ops;
192 cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR;
193 cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR;
194 cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD;
195 set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
196
197 cinst->lan_info.msix_count = adapter->num_iwarp_msix;
198 cinst->lan_info.msix_entries =
199 &adapter->msix_entries[adapter->iwarp_base_vector];
200
201 for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
202 cinst->lan_info.params.qos.prio_qos[i].tc = 0;
203 cinst->lan_info.params.qos.prio_qos[i].qs_handle =
204 vsi->qs_handle;
205 }
206
207 mac = list_first_entry(&cinst->lan_info.netdev->dev_addrs.list,
208 struct netdev_hw_addr, list);
209 if (mac)
210 ether_addr_copy(cinst->lan_info.lanmac, mac->addr);
211 else
212 dev_err(&adapter->pdev->dev, "MAC address list is empty!\n");
213
214 cinst->client = vf_registered_client;
215 adapter->cinst = cinst;
216 out:
217 return cinst;
218 }
219
220 /**
221 * i40evf_client_del_instance - removes a client instance from the list
222 * @adapter: pointer to the board struct
223 * @client: pointer to the client struct
224 *
225 **/
226 static
227 void i40evf_client_del_instance(struct i40evf_adapter *adapter)
228 {
229 kfree(adapter->cinst);
230 adapter->cinst = NULL;
231 }
232
233 /**
234 * i40evf_client_subtask - client maintenance work
235 * @adapter: board private structure
236 **/
237 void i40evf_client_subtask(struct i40evf_adapter *adapter)
238 {
239 struct i40e_client *client = vf_registered_client;
240 struct i40e_client_instance *cinst;
241 int ret = 0;
242
243 if (adapter->state < __I40EVF_DOWN)
244 return;
245
246 /* first check client is registered */
247 if (!client)
248 return;
249
250 /* Add the client instance to the instance list */
251 cinst = i40evf_client_add_instance(adapter);
252 if (!cinst)
253 return;
254
255 dev_info(&adapter->pdev->dev, "Added instance of Client %s\n",
256 client->name);
257
258 if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
259 /* Send an Open request to the client */
260
261 if (client->ops && client->ops->open)
262 ret = client->ops->open(&cinst->lan_info, client);
263 if (!ret)
264 set_bit(__I40E_CLIENT_INSTANCE_OPENED,
265 &cinst->state);
266 else
267 /* remove client instance */
268 i40evf_client_del_instance(adapter);
269 }
270 }
271
272 /**
273 * i40evf_lan_add_device - add a lan device struct to the list of lan devices
274 * @adapter: pointer to the board struct
275 *
276 * Returns 0 on success or none 0 on error
277 **/
278 int i40evf_lan_add_device(struct i40evf_adapter *adapter)
279 {
280 struct i40e_device *ldev;
281 int ret = 0;
282
283 mutex_lock(&i40evf_device_mutex);
284 list_for_each_entry(ldev, &i40evf_devices, list) {
285 if (ldev->vf == adapter) {
286 ret = -EEXIST;
287 goto out;
288 }
289 }
290 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
291 if (!ldev) {
292 ret = -ENOMEM;
293 goto out;
294 }
295 ldev->vf = adapter;
296 INIT_LIST_HEAD(&ldev->list);
297 list_add(&ldev->list, &i40evf_devices);
298 dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
299 adapter->hw.bus.bus_id, adapter->hw.bus.device,
300 adapter->hw.bus.func);
301
302 /* Since in some cases register may have happened before a device gets
303 * added, we can schedule a subtask to go initiate the clients.
304 */
305 adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
306
307 out:
308 mutex_unlock(&i40evf_device_mutex);
309 return ret;
310 }
311
312 /**
313 * i40evf_lan_del_device - removes a lan device from the device list
314 * @adapter: pointer to the board struct
315 *
316 * Returns 0 on success or non-0 on error
317 **/
318 int i40evf_lan_del_device(struct i40evf_adapter *adapter)
319 {
320 struct i40e_device *ldev, *tmp;
321 int ret = -ENODEV;
322
323 mutex_lock(&i40evf_device_mutex);
324 list_for_each_entry_safe(ldev, tmp, &i40evf_devices, list) {
325 if (ldev->vf == adapter) {
326 dev_info(&adapter->pdev->dev,
327 "Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
328 adapter->hw.bus.bus_id, adapter->hw.bus.device,
329 adapter->hw.bus.func);
330 list_del(&ldev->list);
331 kfree(ldev);
332 ret = 0;
333 break;
334 }
335 }
336
337 mutex_unlock(&i40evf_device_mutex);
338 return ret;
339 }
340
341 /**
342 * i40evf_client_release - release client specific resources
343 * @client: pointer to the registered client
344 *
345 **/
346 static void i40evf_client_release(struct i40e_client *client)
347 {
348 struct i40e_client_instance *cinst;
349 struct i40e_device *ldev;
350 struct i40evf_adapter *adapter;
351
352 mutex_lock(&i40evf_device_mutex);
353 list_for_each_entry(ldev, &i40evf_devices, list) {
354 adapter = ldev->vf;
355 cinst = adapter->cinst;
356 if (!cinst)
357 continue;
358 if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
359 if (client->ops && client->ops->close)
360 client->ops->close(&cinst->lan_info, client,
361 false);
362 i40evf_client_release_qvlist(&cinst->lan_info);
363 clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
364
365 dev_warn(&adapter->pdev->dev,
366 "Client %s instance closed\n", client->name);
367 }
368 /* delete the client instance */
369 i40evf_client_del_instance(adapter);
370 dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n",
371 client->name);
372 }
373 mutex_unlock(&i40evf_device_mutex);
374 }
375
376 /**
377 * i40evf_client_prepare - prepare client specific resources
378 * @client: pointer to the registered client
379 *
380 **/
381 static void i40evf_client_prepare(struct i40e_client *client)
382 {
383 struct i40e_device *ldev;
384 struct i40evf_adapter *adapter;
385
386 mutex_lock(&i40evf_device_mutex);
387 list_for_each_entry(ldev, &i40evf_devices, list) {
388 adapter = ldev->vf;
389 /* Signal the watchdog to service the client */
390 adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
391 }
392 mutex_unlock(&i40evf_device_mutex);
393 }
394
395 /**
396 * i40evf_client_virtchnl_send - send a message to the PF instance
397 * @ldev: pointer to L2 context.
398 * @client: Client pointer.
399 * @msg: pointer to message buffer
400 * @len: message length
401 *
402 * Return 0 on success or < 0 on error
403 **/
404 static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
405 struct i40e_client *client,
406 u8 *msg, u16 len)
407 {
408 struct i40evf_adapter *adapter = ldev->vf;
409 i40e_status err;
410
411 if (adapter->aq_required)
412 return -EAGAIN;
413
414 err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP,
415 I40E_SUCCESS, msg, len, NULL);
416 if (err)
417 dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n",
418 err, adapter->hw.aq.asq_last_status);
419
420 return err;
421 }
422
423 /**
424 * i40evf_client_setup_qvlist - send a message to the PF to setup iwarp qv map
425 * @ldev: pointer to L2 context.
426 * @client: Client pointer.
427 * @qv_info: queue and vector list
428 *
429 * Return 0 on success or < 0 on error
430 **/
431 static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
432 struct i40e_client *client,
433 struct i40e_qvlist_info *qvlist_info)
434 {
435 struct virtchnl_iwarp_qvlist_info *v_qvlist_info;
436 struct i40evf_adapter *adapter = ldev->vf;
437 struct i40e_qv_info *qv_info;
438 i40e_status err;
439 u32 v_idx, i;
440 u32 msg_size;
441
442 if (adapter->aq_required)
443 return -EAGAIN;
444
445 /* A quick check on whether the vectors belong to the client */
446 for (i = 0; i < qvlist_info->num_vectors; i++) {
447 qv_info = &qvlist_info->qv_info[i];
448 if (!qv_info)
449 continue;
450 v_idx = qv_info->v_idx;
451 if ((v_idx >=
452 (adapter->iwarp_base_vector + adapter->num_iwarp_msix)) ||
453 (v_idx < adapter->iwarp_base_vector))
454 return -EINVAL;
455 }
456
457 v_qvlist_info = (struct virtchnl_iwarp_qvlist_info *)qvlist_info;
458 msg_size = sizeof(struct virtchnl_iwarp_qvlist_info) +
459 (sizeof(struct virtchnl_iwarp_qv_info) *
460 (v_qvlist_info->num_vectors - 1));
461
462 adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP);
463 err = i40e_aq_send_msg_to_pf(&adapter->hw,
464 VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP,
465 I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL);
466
467 if (err) {
468 dev_err(&adapter->pdev->dev,
469 "Unable to send iWarp vector config message to PF, error %d, aq status %d\n",
470 err, adapter->hw.aq.asq_last_status);
471 goto out;
472 }
473
474 err = -EBUSY;
475 for (i = 0; i < 5; i++) {
476 msleep(100);
477 if (!(adapter->client_pending &
478 BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) {
479 err = 0;
480 break;
481 }
482 }
483 out:
484 return err;
485 }
486
487 /**
488 * i40evf_register_client - Register a i40e client driver with the L2 driver
489 * @client: pointer to the i40e_client struct
490 *
491 * Returns 0 on success or non-0 on error
492 **/
493 int i40evf_register_client(struct i40e_client *client)
494 {
495 int ret = 0;
496
497 if (!client) {
498 ret = -EIO;
499 goto out;
500 }
501
502 if (strlen(client->name) == 0) {
503 pr_info("i40evf: Failed to register client with no name\n");
504 ret = -EIO;
505 goto out;
506 }
507
508 if (vf_registered_client) {
509 pr_info("i40evf: Client %s has already been registered!\n",
510 client->name);
511 ret = -EEXIST;
512 goto out;
513 }
514
515 if ((client->version.major != I40EVF_CLIENT_VERSION_MAJOR) ||
516 (client->version.minor != I40EVF_CLIENT_VERSION_MINOR)) {
517 pr_info("i40evf: Failed to register client %s due to mismatched client interface version\n",
518 client->name);
519 pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n",
520 client->version.major, client->version.minor,
521 client->version.build,
522 i40evf_client_interface_version_str);
523 ret = -EIO;
524 goto out;
525 }
526
527 vf_registered_client = client;
528
529 i40evf_client_prepare(client);
530
531 pr_info("i40evf: Registered client %s with return code %d\n",
532 client->name, ret);
533 out:
534 return ret;
535 }
536 EXPORT_SYMBOL(i40evf_register_client);
537
538 /**
539 * i40evf_unregister_client - Unregister a i40e client driver with the L2 driver
540 * @client: pointer to the i40e_client struct
541 *
542 * Returns 0 on success or non-0 on error
543 **/
544 int i40evf_unregister_client(struct i40e_client *client)
545 {
546 int ret = 0;
547
548 /* When a unregister request comes through we would have to send
549 * a close for each of the client instances that were opened.
550 * client_release function is called to handle this.
551 */
552 i40evf_client_release(client);
553
554 if (vf_registered_client != client) {
555 pr_info("i40evf: Client %s has not been registered\n",
556 client->name);
557 ret = -ENODEV;
558 goto out;
559 }
560 vf_registered_client = NULL;
561 pr_info("i40evf: Unregistered client %s\n", client->name);
562 out:
563 return ret;
564 }
565 EXPORT_SYMBOL(i40evf_unregister_client);