4 * Copyright 2017 6WIND S.A.
5 * Copyright 2017 Mellanox.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <rte_debug.h>
38 #include <rte_atomic.h>
39 #include <rte_ethdev.h>
40 #include <rte_malloc.h>
42 #include <rte_cycles.h>
44 #include "failsafe_private.h"
46 static struct rte_eth_dev_info default_infos = {
47 /* Max possible number of elements */
48 .max_rx_pktlen = UINT32_MAX,
49 .max_rx_queues = RTE_MAX_QUEUES_PER_PORT,
50 .max_tx_queues = RTE_MAX_QUEUES_PER_PORT,
51 .max_mac_addrs = FAILSAFE_MAX_ETHADDR,
52 .max_hash_mac_addrs = UINT32_MAX,
53 .max_vfs = UINT16_MAX,
54 .max_vmdq_pools = UINT16_MAX,
59 .nb_seg_max = UINT16_MAX,
60 .nb_mtu_seg_max = UINT16_MAX,
66 .nb_seg_max = UINT16_MAX,
67 .nb_mtu_seg_max = UINT16_MAX,
70 * Set of capabilities that can be verified upon
71 * configuring a sub-device.
74 DEV_RX_OFFLOAD_VLAN_STRIP |
75 DEV_RX_OFFLOAD_QINQ_STRIP |
76 DEV_RX_OFFLOAD_IPV4_CKSUM |
77 DEV_RX_OFFLOAD_UDP_CKSUM |
78 DEV_RX_OFFLOAD_TCP_CKSUM |
79 DEV_RX_OFFLOAD_TCP_LRO,
80 .tx_offload_capa = 0x0,
81 .flow_type_rss_offloads = 0x0,
85 fs_dev_configure(struct rte_eth_dev *dev)
87 struct sub_device *sdev;
88 uint64_t supp_tx_offloads;
93 supp_tx_offloads = PRIV(dev)->infos.tx_offload_capa;
94 tx_offloads = dev->data->dev_conf.txmode.offloads;
95 if ((tx_offloads & supp_tx_offloads) != tx_offloads) {
97 ERROR("Some Tx offloads are not supported, "
98 "requested 0x%" PRIx64 " supported 0x%" PRIx64,
99 tx_offloads, supp_tx_offloads);
102 FOREACH_SUBDEV(sdev, i, dev) {
103 int rmv_interrupt = 0;
104 int lsc_interrupt = 0;
107 if (sdev->state != DEV_PROBED)
110 rmv_interrupt = ETH(sdev)->data->dev_flags &
111 RTE_ETH_DEV_INTR_RMV;
113 DEBUG("Enabling RMV interrupts for sub_device %d", i);
114 dev->data->dev_conf.intr_conf.rmv = 1;
116 DEBUG("sub_device %d does not support RMV event", i);
118 lsc_enabled = dev->data->dev_conf.intr_conf.lsc;
119 lsc_interrupt = lsc_enabled &&
120 (ETH(sdev)->data->dev_flags &
121 RTE_ETH_DEV_INTR_LSC);
123 DEBUG("Enabling LSC interrupts for sub_device %d", i);
124 dev->data->dev_conf.intr_conf.lsc = 1;
125 } else if (lsc_enabled && !lsc_interrupt) {
126 DEBUG("Disabling LSC interrupts for sub_device %d", i);
127 dev->data->dev_conf.intr_conf.lsc = 0;
129 DEBUG("Configuring sub-device %d", i);
131 ret = rte_eth_dev_configure(PORT_ID(sdev),
132 dev->data->nb_rx_queues,
133 dev->data->nb_tx_queues,
134 &dev->data->dev_conf);
136 ERROR("Could not configure sub_device %d", i);
140 ret = rte_eth_dev_callback_register(PORT_ID(sdev),
141 RTE_ETH_EVENT_INTR_RMV,
142 failsafe_eth_rmv_event_callback,
145 WARN("Failed to register RMV callback for sub_device %d",
148 dev->data->dev_conf.intr_conf.rmv = 0;
150 ret = rte_eth_dev_callback_register(PORT_ID(sdev),
151 RTE_ETH_EVENT_INTR_LSC,
152 failsafe_eth_lsc_event_callback,
155 WARN("Failed to register LSC callback for sub_device %d",
158 dev->data->dev_conf.intr_conf.lsc = lsc_enabled;
159 sdev->state = DEV_ACTIVE;
161 if (PRIV(dev)->state < DEV_ACTIVE)
162 PRIV(dev)->state = DEV_ACTIVE;
167 fs_dev_start(struct rte_eth_dev *dev)
169 struct sub_device *sdev;
173 FOREACH_SUBDEV(sdev, i, dev) {
174 if (sdev->state != DEV_ACTIVE)
176 DEBUG("Starting sub_device %d", i);
177 ret = rte_eth_dev_start(PORT_ID(sdev));
180 sdev->state = DEV_STARTED;
182 if (PRIV(dev)->state < DEV_STARTED)
183 PRIV(dev)->state = DEV_STARTED;
184 fs_switch_dev(dev, NULL);
189 fs_dev_stop(struct rte_eth_dev *dev)
191 struct sub_device *sdev;
194 PRIV(dev)->state = DEV_STARTED - 1;
195 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_STARTED) {
196 rte_eth_dev_stop(PORT_ID(sdev));
197 sdev->state = DEV_STARTED - 1;
202 fs_dev_set_link_up(struct rte_eth_dev *dev)
204 struct sub_device *sdev;
208 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
209 DEBUG("Calling rte_eth_dev_set_link_up on sub_device %d", i);
210 ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
212 ERROR("Operation rte_eth_dev_set_link_up failed for sub_device %d"
213 " with error %d", i, ret);
221 fs_dev_set_link_down(struct rte_eth_dev *dev)
223 struct sub_device *sdev;
227 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
228 DEBUG("Calling rte_eth_dev_set_link_down on sub_device %d", i);
229 ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
231 ERROR("Operation rte_eth_dev_set_link_down failed for sub_device %d"
232 " with error %d", i, ret);
239 static void fs_dev_free_queues(struct rte_eth_dev *dev);
241 fs_dev_close(struct rte_eth_dev *dev)
243 struct sub_device *sdev;
246 failsafe_hotplug_alarm_cancel(dev);
247 if (PRIV(dev)->state == DEV_STARTED)
248 dev->dev_ops->dev_stop(dev);
249 PRIV(dev)->state = DEV_ACTIVE - 1;
250 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
251 DEBUG("Closing sub_device %d", i);
252 rte_eth_dev_close(PORT_ID(sdev));
253 sdev->state = DEV_ACTIVE - 1;
255 fs_dev_free_queues(dev);
259 fs_rx_queue_release(void *queue)
261 struct rte_eth_dev *dev;
262 struct sub_device *sdev;
269 dev = rxq->priv->dev;
270 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
271 SUBOPS(sdev, rx_queue_release)
272 (ETH(sdev)->data->rx_queues[rxq->qid]);
273 dev->data->rx_queues[rxq->qid] = NULL;
278 fs_rx_queue_setup(struct rte_eth_dev *dev,
279 uint16_t rx_queue_id,
281 unsigned int socket_id,
282 const struct rte_eth_rxconf *rx_conf,
283 struct rte_mempool *mb_pool)
285 struct sub_device *sdev;
290 rxq = dev->data->rx_queues[rx_queue_id];
292 fs_rx_queue_release(rxq);
293 dev->data->rx_queues[rx_queue_id] = NULL;
295 rxq = rte_zmalloc(NULL,
297 sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
298 RTE_CACHE_LINE_SIZE);
301 FOREACH_SUBDEV(sdev, i, dev)
302 rte_atomic64_init(&rxq->refcnt[i]);
303 rxq->qid = rx_queue_id;
304 rxq->socket_id = socket_id;
305 rxq->info.mp = mb_pool;
306 rxq->info.conf = *rx_conf;
307 rxq->info.nb_desc = nb_rx_desc;
308 rxq->priv = PRIV(dev);
309 rxq->sdev = PRIV(dev)->subs;
310 dev->data->rx_queues[rx_queue_id] = rxq;
311 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
312 ret = rte_eth_rx_queue_setup(PORT_ID(sdev),
314 nb_rx_desc, socket_id,
317 ERROR("RX queue setup failed for sub_device %d", i);
323 fs_rx_queue_release(rxq);
328 fs_txq_offloads_valid(struct rte_eth_dev *dev, uint64_t offloads)
330 uint64_t port_offloads;
331 uint64_t queue_supp_offloads;
332 uint64_t port_supp_offloads;
334 port_offloads = dev->data->dev_conf.txmode.offloads;
335 queue_supp_offloads = PRIV(dev)->infos.tx_queue_offload_capa;
336 port_supp_offloads = PRIV(dev)->infos.tx_offload_capa;
337 if ((offloads & (queue_supp_offloads | port_supp_offloads)) !=
340 /* Verify we have no conflict with port offloads */
341 if ((port_offloads ^ offloads) & port_supp_offloads)
347 fs_tx_queue_release(void *queue)
349 struct rte_eth_dev *dev;
350 struct sub_device *sdev;
357 dev = txq->priv->dev;
358 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
359 SUBOPS(sdev, tx_queue_release)
360 (ETH(sdev)->data->tx_queues[txq->qid]);
361 dev->data->tx_queues[txq->qid] = NULL;
366 fs_tx_queue_setup(struct rte_eth_dev *dev,
367 uint16_t tx_queue_id,
369 unsigned int socket_id,
370 const struct rte_eth_txconf *tx_conf)
372 struct sub_device *sdev;
377 txq = dev->data->tx_queues[tx_queue_id];
379 fs_tx_queue_release(txq);
380 dev->data->tx_queues[tx_queue_id] = NULL;
383 * Don't verify queue offloads for applications which
386 if (tx_conf != NULL &&
387 (tx_conf->txq_flags & ETH_TXQ_FLAGS_IGNORE) &&
388 fs_txq_offloads_valid(dev, tx_conf->offloads) == false) {
390 ERROR("Tx queue offloads 0x%" PRIx64
391 " don't match port offloads 0x%" PRIx64
392 " or supported offloads 0x%" PRIx64,
394 dev->data->dev_conf.txmode.offloads,
395 PRIV(dev)->infos.tx_offload_capa |
396 PRIV(dev)->infos.tx_queue_offload_capa);
399 txq = rte_zmalloc("ethdev TX queue",
401 sizeof(rte_atomic64_t) * PRIV(dev)->subs_tail,
402 RTE_CACHE_LINE_SIZE);
405 FOREACH_SUBDEV(sdev, i, dev)
406 rte_atomic64_init(&txq->refcnt[i]);
407 txq->qid = tx_queue_id;
408 txq->socket_id = socket_id;
409 txq->info.conf = *tx_conf;
410 txq->info.nb_desc = nb_tx_desc;
411 txq->priv = PRIV(dev);
412 dev->data->tx_queues[tx_queue_id] = txq;
413 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
414 ret = rte_eth_tx_queue_setup(PORT_ID(sdev),
416 nb_tx_desc, socket_id,
419 ERROR("TX queue setup failed for sub_device %d", i);
425 fs_tx_queue_release(txq);
430 fs_dev_free_queues(struct rte_eth_dev *dev)
434 for (i = 0; i < dev->data->nb_rx_queues; i++) {
435 fs_rx_queue_release(dev->data->rx_queues[i]);
436 dev->data->rx_queues[i] = NULL;
438 dev->data->nb_rx_queues = 0;
439 for (i = 0; i < dev->data->nb_tx_queues; i++) {
440 fs_tx_queue_release(dev->data->tx_queues[i]);
441 dev->data->tx_queues[i] = NULL;
443 dev->data->nb_tx_queues = 0;
447 fs_promiscuous_enable(struct rte_eth_dev *dev)
449 struct sub_device *sdev;
452 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
453 rte_eth_promiscuous_enable(PORT_ID(sdev));
457 fs_promiscuous_disable(struct rte_eth_dev *dev)
459 struct sub_device *sdev;
462 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
463 rte_eth_promiscuous_disable(PORT_ID(sdev));
467 fs_allmulticast_enable(struct rte_eth_dev *dev)
469 struct sub_device *sdev;
472 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
473 rte_eth_allmulticast_enable(PORT_ID(sdev));
477 fs_allmulticast_disable(struct rte_eth_dev *dev)
479 struct sub_device *sdev;
482 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
483 rte_eth_allmulticast_disable(PORT_ID(sdev));
487 fs_link_update(struct rte_eth_dev *dev,
488 int wait_to_complete)
490 struct sub_device *sdev;
494 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
495 DEBUG("Calling link_update on sub_device %d", i);
496 ret = (SUBOPS(sdev, link_update))(ETH(sdev), wait_to_complete);
497 if (ret && ret != -1) {
498 ERROR("Link update failed for sub_device %d with error %d",
503 if (TX_SUBDEV(dev)) {
504 struct rte_eth_link *l1;
505 struct rte_eth_link *l2;
507 l1 = &dev->data->dev_link;
508 l2 = Ð(TX_SUBDEV(dev))->data->dev_link;
509 if (memcmp(l1, l2, sizeof(*l1))) {
518 fs_stats_get(struct rte_eth_dev *dev,
519 struct rte_eth_stats *stats)
521 struct sub_device *sdev;
525 rte_memcpy(stats, &PRIV(dev)->stats_accumulator, sizeof(*stats));
526 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
527 struct rte_eth_stats *snapshot = &sdev->stats_snapshot.stats;
528 uint64_t *timestamp = &sdev->stats_snapshot.timestamp;
530 ret = rte_eth_stats_get(PORT_ID(sdev), snapshot);
532 ERROR("Operation rte_eth_stats_get failed for sub_device %d with error %d",
537 *timestamp = rte_rdtsc();
538 failsafe_stats_increment(stats, snapshot);
544 fs_stats_reset(struct rte_eth_dev *dev)
546 struct sub_device *sdev;
549 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
550 rte_eth_stats_reset(PORT_ID(sdev));
551 memset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats));
553 memset(&PRIV(dev)->stats_accumulator, 0, sizeof(struct rte_eth_stats));
557 * Fail-safe dev_infos_get rules:
561 * Use the maximum possible values for any field, so as not
562 * to impede any further configuration effort.
564 * Limits capabilities to those that are understood by the
565 * fail-safe PMD. This understanding stems from the fail-safe
566 * being capable of verifying that the related capability is
567 * expressed within the device configuration (struct rte_eth_conf).
569 * At least one probed sub_device:
571 * Uses values from the active probed sub_device
572 * The rationale here is that if any sub_device is less capable
573 * (for example concerning the number of queues) than the active
574 * sub_device, then its subsequent configuration will fail.
575 * It is impossible to foresee this failure when the failing sub_device
576 * is supposed to be plugged-in later on, so the configuration process
577 * is the single point of failure and error reporting.
579 * Uses a logical AND of RX capabilities among
580 * all sub_devices and the default capabilities.
581 * Uses a logical AND of TX capabilities among
582 * the active probed sub_device and the default capabilities.
586 fs_dev_infos_get(struct rte_eth_dev *dev,
587 struct rte_eth_dev_info *infos)
589 struct sub_device *sdev;
592 sdev = TX_SUBDEV(dev);
594 DEBUG("No probed device, using default infos");
595 rte_memcpy(&PRIV(dev)->infos, &default_infos,
596 sizeof(default_infos));
598 uint32_t rx_offload_capa;
600 rx_offload_capa = default_infos.rx_offload_capa;
601 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
602 rte_eth_dev_info_get(PORT_ID(sdev),
604 rx_offload_capa &= PRIV(dev)->infos.rx_offload_capa;
606 sdev = TX_SUBDEV(dev);
607 rte_eth_dev_info_get(PORT_ID(sdev), &PRIV(dev)->infos);
608 PRIV(dev)->infos.rx_offload_capa = rx_offload_capa;
609 PRIV(dev)->infos.tx_offload_capa &=
610 default_infos.tx_offload_capa;
611 PRIV(dev)->infos.tx_queue_offload_capa &=
612 default_infos.tx_queue_offload_capa;
613 PRIV(dev)->infos.flow_type_rss_offloads &=
614 default_infos.flow_type_rss_offloads;
616 rte_memcpy(infos, &PRIV(dev)->infos, sizeof(*infos));
619 static const uint32_t *
620 fs_dev_supported_ptypes_get(struct rte_eth_dev *dev)
622 struct sub_device *sdev;
623 struct rte_eth_dev *edev;
625 sdev = TX_SUBDEV(dev);
629 /* ENOTSUP: counts as no supported ptypes */
630 if (SUBOPS(sdev, dev_supported_ptypes_get) == NULL)
633 * The API does not permit to do a clean AND of all ptypes,
634 * It is also incomplete by design and we do not really care
635 * to have a best possible value in this context.
636 * We just return the ptypes of the device of highest
637 * priority, usually the PREFERRED device.
639 return SUBOPS(sdev, dev_supported_ptypes_get)(edev);
643 fs_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
645 struct sub_device *sdev;
649 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
650 DEBUG("Calling rte_eth_dev_set_mtu on sub_device %d", i);
651 ret = rte_eth_dev_set_mtu(PORT_ID(sdev), mtu);
653 ERROR("Operation rte_eth_dev_set_mtu failed for sub_device %d with error %d",
662 fs_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
664 struct sub_device *sdev;
668 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
669 DEBUG("Calling rte_eth_dev_vlan_filter on sub_device %d", i);
670 ret = rte_eth_dev_vlan_filter(PORT_ID(sdev), vlan_id, on);
672 ERROR("Operation rte_eth_dev_vlan_filter failed for sub_device %d"
673 " with error %d", i, ret);
681 fs_flow_ctrl_get(struct rte_eth_dev *dev,
682 struct rte_eth_fc_conf *fc_conf)
684 struct sub_device *sdev;
686 sdev = TX_SUBDEV(dev);
689 if (SUBOPS(sdev, flow_ctrl_get) == NULL)
691 return SUBOPS(sdev, flow_ctrl_get)(ETH(sdev), fc_conf);
695 fs_flow_ctrl_set(struct rte_eth_dev *dev,
696 struct rte_eth_fc_conf *fc_conf)
698 struct sub_device *sdev;
702 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
703 DEBUG("Calling rte_eth_dev_flow_ctrl_set on sub_device %d", i);
704 ret = rte_eth_dev_flow_ctrl_set(PORT_ID(sdev), fc_conf);
706 ERROR("Operation rte_eth_dev_flow_ctrl_set failed for sub_device %d"
707 " with error %d", i, ret);
715 fs_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
717 struct sub_device *sdev;
720 /* No check: already done within the rte_eth_dev_mac_addr_remove
721 * call for the fail-safe device.
723 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
724 rte_eth_dev_mac_addr_remove(PORT_ID(sdev),
725 &dev->data->mac_addrs[index]);
726 PRIV(dev)->mac_addr_pool[index] = 0;
730 fs_mac_addr_add(struct rte_eth_dev *dev,
731 struct ether_addr *mac_addr,
735 struct sub_device *sdev;
739 RTE_ASSERT(index < FAILSAFE_MAX_ETHADDR);
740 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
741 ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), mac_addr, vmdq);
743 ERROR("Operation rte_eth_dev_mac_addr_add failed for sub_device %"
744 PRIu8 " with error %d", i, ret);
748 if (index >= PRIV(dev)->nb_mac_addr) {
749 DEBUG("Growing mac_addrs array");
750 PRIV(dev)->nb_mac_addr = index;
752 PRIV(dev)->mac_addr_pool[index] = vmdq;
757 fs_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
759 struct sub_device *sdev;
762 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
763 rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), mac_addr);
767 fs_filter_ctrl(struct rte_eth_dev *dev,
768 enum rte_filter_type type,
769 enum rte_filter_op op,
772 struct sub_device *sdev;
776 if (type == RTE_ETH_FILTER_GENERIC &&
777 op == RTE_ETH_FILTER_GET) {
778 *(const void **)arg = &fs_flow_ops;
781 FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
782 DEBUG("Calling rte_eth_dev_filter_ctrl on sub_device %d", i);
783 ret = rte_eth_dev_filter_ctrl(PORT_ID(sdev), type, op, arg);
785 ERROR("Operation rte_eth_dev_filter_ctrl failed for sub_device %d"
786 " with error %d", i, ret);
793 const struct eth_dev_ops failsafe_ops = {
794 .dev_configure = fs_dev_configure,
795 .dev_start = fs_dev_start,
796 .dev_stop = fs_dev_stop,
797 .dev_set_link_down = fs_dev_set_link_down,
798 .dev_set_link_up = fs_dev_set_link_up,
799 .dev_close = fs_dev_close,
800 .promiscuous_enable = fs_promiscuous_enable,
801 .promiscuous_disable = fs_promiscuous_disable,
802 .allmulticast_enable = fs_allmulticast_enable,
803 .allmulticast_disable = fs_allmulticast_disable,
804 .link_update = fs_link_update,
805 .stats_get = fs_stats_get,
806 .stats_reset = fs_stats_reset,
807 .dev_infos_get = fs_dev_infos_get,
808 .dev_supported_ptypes_get = fs_dev_supported_ptypes_get,
809 .mtu_set = fs_mtu_set,
810 .vlan_filter_set = fs_vlan_filter_set,
811 .rx_queue_setup = fs_rx_queue_setup,
812 .tx_queue_setup = fs_tx_queue_setup,
813 .rx_queue_release = fs_rx_queue_release,
814 .tx_queue_release = fs_tx_queue_release,
815 .flow_ctrl_get = fs_flow_ctrl_get,
816 .flow_ctrl_set = fs_flow_ctrl_set,
817 .mac_addr_remove = fs_mac_addr_remove,
818 .mac_addr_add = fs_mac_addr_add,
819 .mac_addr_set = fs_mac_addr_set,
820 .filter_ctrl = fs_filter_ctrl,