1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2ebea83f8SGaetan Rivet * Copyright 2017 6WIND S.A. 3ebea83f8SGaetan Rivet * Copyright 2017 Mellanox. 4ebea83f8SGaetan Rivet */ 5ebea83f8SGaetan Rivet 6ebea83f8SGaetan Rivet #include <unistd.h> 7ebea83f8SGaetan Rivet 8b737a1eeSGaetan Rivet #include <rte_flow.h> 9b737a1eeSGaetan Rivet #include <rte_flow_driver.h> 109dda3e33SMatan Azrad #include <rte_cycles.h> 11b737a1eeSGaetan Rivet 12ebea83f8SGaetan Rivet #include "failsafe_private.h" 13ebea83f8SGaetan Rivet 14b737a1eeSGaetan Rivet /** Print a message out of a flow error. */ 15b737a1eeSGaetan Rivet static int 16b737a1eeSGaetan Rivet fs_flow_complain(struct rte_flow_error *error) 17b737a1eeSGaetan Rivet { 18b737a1eeSGaetan Rivet static const char *const errstrlist[] = { 19b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_NONE] = "no error", 20b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified", 21b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)", 22b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field", 23b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field", 24b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field", 25b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field", 26b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure", 27b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length", 28b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item", 29b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions", 30b737a1eeSGaetan Rivet [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action", 31b737a1eeSGaetan Rivet }; 32b737a1eeSGaetan Rivet const char *errstr; 33b737a1eeSGaetan Rivet char buf[32]; 34b737a1eeSGaetan Rivet int err = rte_errno; 35b737a1eeSGaetan Rivet 36b737a1eeSGaetan Rivet if ((unsigned int)error->type >= RTE_DIM(errstrlist) || 37b737a1eeSGaetan Rivet !errstrlist[error->type]) 38b737a1eeSGaetan Rivet errstr = "unknown type"; 39b737a1eeSGaetan Rivet else 40b737a1eeSGaetan Rivet errstr = errstrlist[error->type]; 41b737a1eeSGaetan Rivet ERROR("Caught error type %d (%s): %s%s\n", 42b737a1eeSGaetan Rivet error->type, errstr, 43b737a1eeSGaetan Rivet error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ", 44b737a1eeSGaetan Rivet error->cause), buf) : "", 45b737a1eeSGaetan Rivet error->message ? error->message : "(no stated reason)"); 46b737a1eeSGaetan Rivet return -err; 47b737a1eeSGaetan Rivet } 48b737a1eeSGaetan Rivet 49ebea83f8SGaetan Rivet static int 502cc52cd7SGaetan Rivet eth_dev_flow_isolate_set(struct rte_eth_dev *dev, 512cc52cd7SGaetan Rivet struct sub_device *sdev) 522cc52cd7SGaetan Rivet { 532cc52cd7SGaetan Rivet struct rte_flow_error ferror; 542cc52cd7SGaetan Rivet int ret; 552cc52cd7SGaetan Rivet 562cc52cd7SGaetan Rivet if (!PRIV(dev)->flow_isolated) { 572cc52cd7SGaetan Rivet DEBUG("Flow isolation already disabled"); 582cc52cd7SGaetan Rivet } else { 592cc52cd7SGaetan Rivet DEBUG("Enabling flow isolation"); 602cc52cd7SGaetan Rivet ret = rte_flow_isolate(PORT_ID(sdev), 612cc52cd7SGaetan Rivet PRIV(dev)->flow_isolated, 622cc52cd7SGaetan Rivet &ferror); 632cc52cd7SGaetan Rivet if (ret) { 642cc52cd7SGaetan Rivet fs_flow_complain(&ferror); 652cc52cd7SGaetan Rivet return ret; 662cc52cd7SGaetan Rivet } 672cc52cd7SGaetan Rivet } 682cc52cd7SGaetan Rivet return 0; 692cc52cd7SGaetan Rivet } 702cc52cd7SGaetan Rivet 712cc52cd7SGaetan Rivet static int 72ebea83f8SGaetan Rivet fs_eth_dev_conf_apply(struct rte_eth_dev *dev, 73ebea83f8SGaetan Rivet struct sub_device *sdev) 74ebea83f8SGaetan Rivet { 75ebea83f8SGaetan Rivet struct rte_eth_dev *edev; 76ebea83f8SGaetan Rivet struct rte_vlan_filter_conf *vfc1; 77ebea83f8SGaetan Rivet struct rte_vlan_filter_conf *vfc2; 78b737a1eeSGaetan Rivet struct rte_flow *flow; 79b737a1eeSGaetan Rivet struct rte_flow_error ferror; 80ebea83f8SGaetan Rivet uint32_t i; 81ebea83f8SGaetan Rivet int ret; 82ebea83f8SGaetan Rivet 83ebea83f8SGaetan Rivet edev = ETH(sdev); 84ebea83f8SGaetan Rivet /* RX queue setup */ 85ebea83f8SGaetan Rivet for (i = 0; i < dev->data->nb_rx_queues; i++) { 86ebea83f8SGaetan Rivet struct rxq *rxq; 87ebea83f8SGaetan Rivet 88ebea83f8SGaetan Rivet rxq = dev->data->rx_queues[i]; 89ebea83f8SGaetan Rivet ret = rte_eth_rx_queue_setup(PORT_ID(sdev), i, 90ebea83f8SGaetan Rivet rxq->info.nb_desc, rxq->socket_id, 91ebea83f8SGaetan Rivet &rxq->info.conf, rxq->info.mp); 92ebea83f8SGaetan Rivet if (ret) { 93ebea83f8SGaetan Rivet ERROR("rx_queue_setup failed"); 94ebea83f8SGaetan Rivet return ret; 95ebea83f8SGaetan Rivet } 96ebea83f8SGaetan Rivet } 97ebea83f8SGaetan Rivet /* TX queue setup */ 98ebea83f8SGaetan Rivet for (i = 0; i < dev->data->nb_tx_queues; i++) { 99ebea83f8SGaetan Rivet struct txq *txq; 100ebea83f8SGaetan Rivet 101ebea83f8SGaetan Rivet txq = dev->data->tx_queues[i]; 102ebea83f8SGaetan Rivet ret = rte_eth_tx_queue_setup(PORT_ID(sdev), i, 103ebea83f8SGaetan Rivet txq->info.nb_desc, txq->socket_id, 104ebea83f8SGaetan Rivet &txq->info.conf); 105ebea83f8SGaetan Rivet if (ret) { 106ebea83f8SGaetan Rivet ERROR("tx_queue_setup failed"); 107ebea83f8SGaetan Rivet return ret; 108ebea83f8SGaetan Rivet } 109ebea83f8SGaetan Rivet } 110ebea83f8SGaetan Rivet /* dev_link.link_status */ 111ebea83f8SGaetan Rivet if (dev->data->dev_link.link_status != 112ebea83f8SGaetan Rivet edev->data->dev_link.link_status) { 113ebea83f8SGaetan Rivet DEBUG("Configuring link_status"); 114ebea83f8SGaetan Rivet if (dev->data->dev_link.link_status) 115ebea83f8SGaetan Rivet ret = rte_eth_dev_set_link_up(PORT_ID(sdev)); 116ebea83f8SGaetan Rivet else 117ebea83f8SGaetan Rivet ret = rte_eth_dev_set_link_down(PORT_ID(sdev)); 118ebea83f8SGaetan Rivet if (ret) { 119ebea83f8SGaetan Rivet ERROR("Failed to apply link_status"); 120ebea83f8SGaetan Rivet return ret; 121ebea83f8SGaetan Rivet } 122ebea83f8SGaetan Rivet } else { 123ebea83f8SGaetan Rivet DEBUG("link_status already set"); 124ebea83f8SGaetan Rivet } 125ebea83f8SGaetan Rivet /* promiscuous */ 126ebea83f8SGaetan Rivet if (dev->data->promiscuous != edev->data->promiscuous) { 127ebea83f8SGaetan Rivet DEBUG("Configuring promiscuous"); 128ebea83f8SGaetan Rivet if (dev->data->promiscuous) 129ebea83f8SGaetan Rivet rte_eth_promiscuous_enable(PORT_ID(sdev)); 130ebea83f8SGaetan Rivet else 131ebea83f8SGaetan Rivet rte_eth_promiscuous_disable(PORT_ID(sdev)); 132ebea83f8SGaetan Rivet } else { 133ebea83f8SGaetan Rivet DEBUG("promiscuous already set"); 134ebea83f8SGaetan Rivet } 135ebea83f8SGaetan Rivet /* all_multicast */ 136ebea83f8SGaetan Rivet if (dev->data->all_multicast != edev->data->all_multicast) { 137ebea83f8SGaetan Rivet DEBUG("Configuring all_multicast"); 138ebea83f8SGaetan Rivet if (dev->data->all_multicast) 139ebea83f8SGaetan Rivet rte_eth_allmulticast_enable(PORT_ID(sdev)); 140ebea83f8SGaetan Rivet else 141ebea83f8SGaetan Rivet rte_eth_allmulticast_disable(PORT_ID(sdev)); 142ebea83f8SGaetan Rivet } else { 143ebea83f8SGaetan Rivet DEBUG("all_multicast already set"); 144ebea83f8SGaetan Rivet } 145ebea83f8SGaetan Rivet /* MTU */ 146ebea83f8SGaetan Rivet if (dev->data->mtu != edev->data->mtu) { 147ebea83f8SGaetan Rivet DEBUG("Configuring MTU"); 148ebea83f8SGaetan Rivet ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu); 149ebea83f8SGaetan Rivet if (ret) { 150ebea83f8SGaetan Rivet ERROR("Failed to apply MTU"); 151ebea83f8SGaetan Rivet return ret; 152ebea83f8SGaetan Rivet } 153ebea83f8SGaetan Rivet } else { 154ebea83f8SGaetan Rivet DEBUG("MTU already set"); 155ebea83f8SGaetan Rivet } 156ebea83f8SGaetan Rivet /* default MAC */ 157ebea83f8SGaetan Rivet DEBUG("Configuring default MAC address"); 158ebea83f8SGaetan Rivet ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 159ebea83f8SGaetan Rivet &dev->data->mac_addrs[0]); 160ebea83f8SGaetan Rivet if (ret) { 161ebea83f8SGaetan Rivet ERROR("Setting default MAC address failed"); 162ebea83f8SGaetan Rivet return ret; 163ebea83f8SGaetan Rivet } 164ebea83f8SGaetan Rivet /* additional MAC */ 165ebea83f8SGaetan Rivet if (PRIV(dev)->nb_mac_addr > 1) 166ebea83f8SGaetan Rivet DEBUG("Configure additional MAC address%s", 167ebea83f8SGaetan Rivet (PRIV(dev)->nb_mac_addr > 2 ? "es" : "")); 168ebea83f8SGaetan Rivet for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) { 169ebea83f8SGaetan Rivet struct ether_addr *ea; 170ebea83f8SGaetan Rivet 171ebea83f8SGaetan Rivet ea = &dev->data->mac_addrs[i]; 172ebea83f8SGaetan Rivet ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea, 173ebea83f8SGaetan Rivet PRIV(dev)->mac_addr_pool[i]); 174ebea83f8SGaetan Rivet if (ret) { 175ebea83f8SGaetan Rivet char ea_fmt[ETHER_ADDR_FMT_SIZE]; 176ebea83f8SGaetan Rivet 177ebea83f8SGaetan Rivet ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea); 178ebea83f8SGaetan Rivet ERROR("Adding MAC address %s failed", ea_fmt); 179ae7cb246SMatan Azrad return ret; 180ebea83f8SGaetan Rivet } 181ebea83f8SGaetan Rivet } 182ebea83f8SGaetan Rivet /* VLAN filter */ 183ebea83f8SGaetan Rivet vfc1 = &dev->data->vlan_filter_conf; 184ebea83f8SGaetan Rivet vfc2 = &edev->data->vlan_filter_conf; 185ebea83f8SGaetan Rivet if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) { 186ebea83f8SGaetan Rivet uint64_t vbit; 187ebea83f8SGaetan Rivet uint64_t ids; 188ebea83f8SGaetan Rivet size_t i; 189ebea83f8SGaetan Rivet uint16_t vlan_id; 190ebea83f8SGaetan Rivet 191ebea83f8SGaetan Rivet DEBUG("Configuring VLAN filter"); 192ebea83f8SGaetan Rivet for (i = 0; i < RTE_DIM(vfc1->ids); i++) { 193ebea83f8SGaetan Rivet if (vfc1->ids[i] == 0) 194ebea83f8SGaetan Rivet continue; 195ebea83f8SGaetan Rivet ids = vfc1->ids[i]; 196ebea83f8SGaetan Rivet while (ids) { 197ebea83f8SGaetan Rivet vlan_id = 64 * i; 198ebea83f8SGaetan Rivet /* count trailing zeroes */ 199ebea83f8SGaetan Rivet vbit = ~ids & (ids - 1); 200ebea83f8SGaetan Rivet /* clear least significant bit set */ 201ebea83f8SGaetan Rivet ids ^= (ids ^ (ids - 1)) ^ vbit; 202ebea83f8SGaetan Rivet for (; vbit; vlan_id++) 203ebea83f8SGaetan Rivet vbit >>= 1; 204ebea83f8SGaetan Rivet ret = rte_eth_dev_vlan_filter( 205ebea83f8SGaetan Rivet PORT_ID(sdev), vlan_id, 1); 206ebea83f8SGaetan Rivet if (ret) { 207ebea83f8SGaetan Rivet ERROR("Failed to apply VLAN filter %hu", 208ebea83f8SGaetan Rivet vlan_id); 209ebea83f8SGaetan Rivet return ret; 210ebea83f8SGaetan Rivet } 211ebea83f8SGaetan Rivet } 212ebea83f8SGaetan Rivet } 213ebea83f8SGaetan Rivet } else { 214ebea83f8SGaetan Rivet DEBUG("VLAN filter already set"); 215ebea83f8SGaetan Rivet } 216b737a1eeSGaetan Rivet /* rte_flow */ 217b737a1eeSGaetan Rivet if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) { 218b737a1eeSGaetan Rivet DEBUG("rte_flow already set"); 219b737a1eeSGaetan Rivet } else { 220b737a1eeSGaetan Rivet DEBUG("Resetting rte_flow configuration"); 221b737a1eeSGaetan Rivet ret = rte_flow_flush(PORT_ID(sdev), &ferror); 222b737a1eeSGaetan Rivet if (ret) { 223b737a1eeSGaetan Rivet fs_flow_complain(&ferror); 224b737a1eeSGaetan Rivet return ret; 225b737a1eeSGaetan Rivet } 226b737a1eeSGaetan Rivet i = 0; 227b737a1eeSGaetan Rivet rte_errno = 0; 228b737a1eeSGaetan Rivet DEBUG("Configuring rte_flow"); 229b737a1eeSGaetan Rivet TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) { 230b737a1eeSGaetan Rivet DEBUG("Creating flow #%" PRIu32, i++); 231b737a1eeSGaetan Rivet flow->flows[SUB_ID(sdev)] = 232b737a1eeSGaetan Rivet rte_flow_create(PORT_ID(sdev), 233b737a1eeSGaetan Rivet &flow->fd->attr, 234b737a1eeSGaetan Rivet flow->fd->items, 235b737a1eeSGaetan Rivet flow->fd->actions, 236b737a1eeSGaetan Rivet &ferror); 237b737a1eeSGaetan Rivet ret = rte_errno; 238b737a1eeSGaetan Rivet if (ret) 239b737a1eeSGaetan Rivet break; 240b737a1eeSGaetan Rivet } 241b737a1eeSGaetan Rivet if (ret) { 242b737a1eeSGaetan Rivet fs_flow_complain(&ferror); 243b737a1eeSGaetan Rivet return ret; 244b737a1eeSGaetan Rivet } 245b737a1eeSGaetan Rivet } 246ebea83f8SGaetan Rivet return 0; 247ebea83f8SGaetan Rivet } 248ebea83f8SGaetan Rivet 249598fb8aeSGaetan Rivet static void 250598fb8aeSGaetan Rivet fs_dev_remove(struct sub_device *sdev) 251598fb8aeSGaetan Rivet { 252598fb8aeSGaetan Rivet int ret; 253598fb8aeSGaetan Rivet 254598fb8aeSGaetan Rivet if (sdev == NULL) 255598fb8aeSGaetan Rivet return; 256598fb8aeSGaetan Rivet switch (sdev->state) { 257598fb8aeSGaetan Rivet case DEV_STARTED: 258f234e5bdSMoti Haimovsky failsafe_rx_intr_uninstall_subdevice(sdev); 259598fb8aeSGaetan Rivet rte_eth_dev_stop(PORT_ID(sdev)); 260598fb8aeSGaetan Rivet sdev->state = DEV_ACTIVE; 261598fb8aeSGaetan Rivet /* fallthrough */ 262598fb8aeSGaetan Rivet case DEV_ACTIVE: 263598fb8aeSGaetan Rivet rte_eth_dev_close(PORT_ID(sdev)); 264598fb8aeSGaetan Rivet sdev->state = DEV_PROBED; 265598fb8aeSGaetan Rivet /* fallthrough */ 266598fb8aeSGaetan Rivet case DEV_PROBED: 267598fb8aeSGaetan Rivet ret = rte_eal_hotplug_remove(sdev->bus->name, 268598fb8aeSGaetan Rivet sdev->dev->name); 269598fb8aeSGaetan Rivet if (ret) { 270598fb8aeSGaetan Rivet ERROR("Bus detach failed for sub_device %u", 271598fb8aeSGaetan Rivet SUB_ID(sdev)); 272598fb8aeSGaetan Rivet } else { 273fac0ae54SMatan Azrad rte_eth_dev_release_port(ETH(sdev)); 274598fb8aeSGaetan Rivet } 275598fb8aeSGaetan Rivet sdev->state = DEV_PARSED; 276598fb8aeSGaetan Rivet /* fallthrough */ 277598fb8aeSGaetan Rivet case DEV_PARSED: 278598fb8aeSGaetan Rivet case DEV_UNDEFINED: 279598fb8aeSGaetan Rivet sdev->state = DEV_UNDEFINED; 280598fb8aeSGaetan Rivet /* the end */ 281598fb8aeSGaetan Rivet break; 282598fb8aeSGaetan Rivet } 283*82bae1eaSMatan Azrad sdev->remove = 0; 284598fb8aeSGaetan Rivet failsafe_hotplug_alarm_install(sdev->fs_dev); 285598fb8aeSGaetan Rivet } 286598fb8aeSGaetan Rivet 2876265ab51SMatan Azrad static void 2886265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev) 2896265ab51SMatan Azrad { 290321809bbSMatan Azrad struct rte_eth_stats stats; 291321809bbSMatan Azrad int err; 292321809bbSMatan Azrad 293321809bbSMatan Azrad /* Attempt to read current stats. */ 294321809bbSMatan Azrad err = rte_eth_stats_get(PORT_ID(sdev), &stats); 2959dda3e33SMatan Azrad if (err) { 2969dda3e33SMatan Azrad uint64_t timestamp = sdev->stats_snapshot.timestamp; 2979dda3e33SMatan Azrad 2989dda3e33SMatan Azrad WARN("Could not access latest statistics from sub-device %d.\n", 2999dda3e33SMatan Azrad SUB_ID(sdev)); 3009dda3e33SMatan Azrad if (timestamp != 0) 3019dda3e33SMatan Azrad WARN("Using latest snapshot taken before %"PRIu64" seconds.\n", 3029dda3e33SMatan Azrad (rte_rdtsc() - timestamp) / rte_get_tsc_hz()); 3039dda3e33SMatan Azrad } 3046265ab51SMatan Azrad failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator, 3059dda3e33SMatan Azrad err ? &sdev->stats_snapshot.stats : &stats); 3069dda3e33SMatan Azrad memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot)); 3076265ab51SMatan Azrad } 3086265ab51SMatan Azrad 309598fb8aeSGaetan Rivet static inline int 310598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev) 311598fb8aeSGaetan Rivet { 312598fb8aeSGaetan Rivet uint16_t i; 313598fb8aeSGaetan Rivet 314598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++) 315598fb8aeSGaetan Rivet if (FS_ATOMIC_RX(sdev, i)) 316598fb8aeSGaetan Rivet return 0; 317598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++) 318598fb8aeSGaetan Rivet if (FS_ATOMIC_TX(sdev, i)) 319598fb8aeSGaetan Rivet return 0; 320598fb8aeSGaetan Rivet return 1; 321598fb8aeSGaetan Rivet } 322598fb8aeSGaetan Rivet 323598fb8aeSGaetan Rivet void 324598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev) 325598fb8aeSGaetan Rivet { 326598fb8aeSGaetan Rivet struct sub_device *sdev; 327598fb8aeSGaetan Rivet uint8_t i; 328598fb8aeSGaetan Rivet 329598fb8aeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) 3306265ab51SMatan Azrad if (sdev->remove && fs_rxtx_clean(sdev)) { 3316265ab51SMatan Azrad fs_dev_stats_save(sdev); 332598fb8aeSGaetan Rivet fs_dev_remove(sdev); 333598fb8aeSGaetan Rivet } 3346265ab51SMatan Azrad } 335598fb8aeSGaetan Rivet 336ebea83f8SGaetan Rivet int 337ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev) 338ebea83f8SGaetan Rivet { 339ebea83f8SGaetan Rivet struct sub_device *sdev; 340ebea83f8SGaetan Rivet uint32_t inactive; 341ebea83f8SGaetan Rivet int ret; 342ebea83f8SGaetan Rivet uint8_t i; 343ebea83f8SGaetan Rivet 344a0194d82SGaetan Rivet if (PRIV(dev)->state < DEV_PARSED) 345a0194d82SGaetan Rivet return 0; 346a0194d82SGaetan Rivet 347a0194d82SGaetan Rivet ret = failsafe_args_parse_subs(dev); 348a0194d82SGaetan Rivet if (ret) 349598fb8aeSGaetan Rivet goto err_remove; 350a0194d82SGaetan Rivet 351ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_PROBED) 352ebea83f8SGaetan Rivet return 0; 353ebea83f8SGaetan Rivet ret = failsafe_eal_init(dev); 354ebea83f8SGaetan Rivet if (ret) 355598fb8aeSGaetan Rivet goto err_remove; 356ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_ACTIVE) 357ebea83f8SGaetan Rivet return 0; 358ebea83f8SGaetan Rivet inactive = 0; 3592cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 3602cc52cd7SGaetan Rivet if (sdev->state == DEV_PROBED) { 361ebea83f8SGaetan Rivet inactive |= UINT32_C(1) << i; 3622cc52cd7SGaetan Rivet ret = eth_dev_flow_isolate_set(dev, sdev); 3632cc52cd7SGaetan Rivet if (ret) { 3642cc52cd7SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 3652cc52cd7SGaetan Rivet i); 3662cc52cd7SGaetan Rivet goto err_remove; 3672cc52cd7SGaetan Rivet } 3682cc52cd7SGaetan Rivet } 3692cc52cd7SGaetan Rivet } 370ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_configure(dev); 371ebea83f8SGaetan Rivet if (ret) 372598fb8aeSGaetan Rivet goto err_remove; 373ebea83f8SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 374ebea83f8SGaetan Rivet if (inactive & (UINT32_C(1) << i)) { 375ebea83f8SGaetan Rivet ret = fs_eth_dev_conf_apply(dev, sdev); 376ebea83f8SGaetan Rivet if (ret) { 377ebea83f8SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 378ebea83f8SGaetan Rivet i); 379598fb8aeSGaetan Rivet goto err_remove; 380ebea83f8SGaetan Rivet } 381ebea83f8SGaetan Rivet } 382ebea83f8SGaetan Rivet } 383ebea83f8SGaetan Rivet /* 384ebea83f8SGaetan Rivet * If new devices have been configured, check if 385ebea83f8SGaetan Rivet * the link state has changed. 386ebea83f8SGaetan Rivet */ 387ebea83f8SGaetan Rivet if (inactive) 388ebea83f8SGaetan Rivet dev->dev_ops->link_update(dev, 1); 389ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_STARTED) 390ebea83f8SGaetan Rivet return 0; 391ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_start(dev); 392ebea83f8SGaetan Rivet if (ret) 393598fb8aeSGaetan Rivet goto err_remove; 394598fb8aeSGaetan Rivet return 0; 395598fb8aeSGaetan Rivet err_remove: 396598fb8aeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 397598fb8aeSGaetan Rivet if (sdev->state != PRIV(dev)->state) 398598fb8aeSGaetan Rivet sdev->remove = 1; 399ebea83f8SGaetan Rivet return ret; 400598fb8aeSGaetan Rivet } 401598fb8aeSGaetan Rivet 4026265ab51SMatan Azrad void 4036265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from) 4046265ab51SMatan Azrad { 4056265ab51SMatan Azrad uint32_t i; 4066265ab51SMatan Azrad 4076265ab51SMatan Azrad RTE_ASSERT(to != NULL && from != NULL); 4086265ab51SMatan Azrad to->ipackets += from->ipackets; 4096265ab51SMatan Azrad to->opackets += from->opackets; 4106265ab51SMatan Azrad to->ibytes += from->ibytes; 4116265ab51SMatan Azrad to->obytes += from->obytes; 4126265ab51SMatan Azrad to->imissed += from->imissed; 4136265ab51SMatan Azrad to->ierrors += from->ierrors; 4146265ab51SMatan Azrad to->oerrors += from->oerrors; 4156265ab51SMatan Azrad to->rx_nombuf += from->rx_nombuf; 4166265ab51SMatan Azrad for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { 4176265ab51SMatan Azrad to->q_ipackets[i] += from->q_ipackets[i]; 4186265ab51SMatan Azrad to->q_opackets[i] += from->q_opackets[i]; 4196265ab51SMatan Azrad to->q_ibytes[i] += from->q_ibytes[i]; 4206265ab51SMatan Azrad to->q_obytes[i] += from->q_obytes[i]; 4216265ab51SMatan Azrad to->q_errors[i] += from->q_errors[i]; 4226265ab51SMatan Azrad } 4236265ab51SMatan Azrad } 4246265ab51SMatan Azrad 425598fb8aeSGaetan Rivet int 426f8244c63SZhiyong Yang failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused, 427598fb8aeSGaetan Rivet enum rte_eth_event_type event __rte_unused, 428598fb8aeSGaetan Rivet void *cb_arg, void *out __rte_unused) 429598fb8aeSGaetan Rivet { 430598fb8aeSGaetan Rivet struct sub_device *sdev = cb_arg; 431598fb8aeSGaetan Rivet 432598fb8aeSGaetan Rivet /* Switch as soon as possible tx_dev. */ 433598fb8aeSGaetan Rivet fs_switch_dev(sdev->fs_dev, sdev); 434598fb8aeSGaetan Rivet /* Use safe bursts in any case. */ 435598fb8aeSGaetan Rivet set_burst_fn(sdev->fs_dev, 1); 436598fb8aeSGaetan Rivet /* 437598fb8aeSGaetan Rivet * Async removal, the sub-PMD will try to unregister 438598fb8aeSGaetan Rivet * the callback at the source of the current thread context. 439598fb8aeSGaetan Rivet */ 440598fb8aeSGaetan Rivet sdev->remove = 1; 441ebea83f8SGaetan Rivet return 0; 442ebea83f8SGaetan Rivet } 443ad7d6a35SGaetan Rivet 444ad7d6a35SGaetan Rivet int 445f8244c63SZhiyong Yang failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused, 446ad7d6a35SGaetan Rivet enum rte_eth_event_type event __rte_unused, 447ad7d6a35SGaetan Rivet void *cb_arg, void *out __rte_unused) 448ad7d6a35SGaetan Rivet { 449ad7d6a35SGaetan Rivet struct rte_eth_dev *dev = cb_arg; 450ad7d6a35SGaetan Rivet int ret; 451ad7d6a35SGaetan Rivet 452ad7d6a35SGaetan Rivet ret = dev->dev_ops->link_update(dev, 0); 453ad7d6a35SGaetan Rivet /* We must pass on the LSC event */ 454ad7d6a35SGaetan Rivet if (ret) 455ad7d6a35SGaetan Rivet return _rte_eth_dev_callback_process(dev, 456ad7d6a35SGaetan Rivet RTE_ETH_EVENT_INTR_LSC, 457cebe3d7bSThomas Monjalon NULL); 458ad7d6a35SGaetan Rivet else 459ad7d6a35SGaetan Rivet return 0; 460ad7d6a35SGaetan Rivet } 461