1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 2ebea83f8SGaetan Rivet * Copyright 2017 6WIND S.A. 35feecc57SShahaf Shuler * Copyright 2017 Mellanox Technologies, Ltd 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]; 41*f665790aSDavid Marchand ERROR("Caught error type %d (%s): %s%s", 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) 1296f6d5d21SIvan Ilchenko ret = rte_eth_promiscuous_enable(PORT_ID(sdev)); 130ebea83f8SGaetan Rivet else 1316f6d5d21SIvan Ilchenko ret = rte_eth_promiscuous_disable(PORT_ID(sdev)); 1326f6d5d21SIvan Ilchenko if (ret != 0) { 1336f6d5d21SIvan Ilchenko ERROR("Failed to apply promiscuous mode"); 1346f6d5d21SIvan Ilchenko return ret; 1356f6d5d21SIvan Ilchenko } 136ebea83f8SGaetan Rivet } else { 137ebea83f8SGaetan Rivet DEBUG("promiscuous already set"); 138ebea83f8SGaetan Rivet } 139ebea83f8SGaetan Rivet /* all_multicast */ 140ebea83f8SGaetan Rivet if (dev->data->all_multicast != edev->data->all_multicast) { 141ebea83f8SGaetan Rivet DEBUG("Configuring all_multicast"); 142ebea83f8SGaetan Rivet if (dev->data->all_multicast) 1435bc4baf0SIvan Ilchenko ret = rte_eth_allmulticast_enable(PORT_ID(sdev)); 144ebea83f8SGaetan Rivet else 1455bc4baf0SIvan Ilchenko ret = rte_eth_allmulticast_disable(PORT_ID(sdev)); 1465bc4baf0SIvan Ilchenko if (ret != 0) { 1475bc4baf0SIvan Ilchenko ERROR("Failed to apply allmulticast mode"); 1485bc4baf0SIvan Ilchenko return ret; 1495bc4baf0SIvan Ilchenko } 150ebea83f8SGaetan Rivet } else { 151ebea83f8SGaetan Rivet DEBUG("all_multicast already set"); 152ebea83f8SGaetan Rivet } 153ebea83f8SGaetan Rivet /* MTU */ 154ebea83f8SGaetan Rivet if (dev->data->mtu != edev->data->mtu) { 155ebea83f8SGaetan Rivet DEBUG("Configuring MTU"); 156ebea83f8SGaetan Rivet ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu); 157ebea83f8SGaetan Rivet if (ret) { 158ebea83f8SGaetan Rivet ERROR("Failed to apply MTU"); 159ebea83f8SGaetan Rivet return ret; 160ebea83f8SGaetan Rivet } 161ebea83f8SGaetan Rivet } else { 162ebea83f8SGaetan Rivet DEBUG("MTU already set"); 163ebea83f8SGaetan Rivet } 164ebea83f8SGaetan Rivet /* default MAC */ 165ebea83f8SGaetan Rivet DEBUG("Configuring default MAC address"); 166ebea83f8SGaetan Rivet ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev), 167ebea83f8SGaetan Rivet &dev->data->mac_addrs[0]); 168ebea83f8SGaetan Rivet if (ret) { 169ebea83f8SGaetan Rivet ERROR("Setting default MAC address failed"); 170ebea83f8SGaetan Rivet return ret; 171ebea83f8SGaetan Rivet } 172ebea83f8SGaetan Rivet /* additional MAC */ 173ebea83f8SGaetan Rivet if (PRIV(dev)->nb_mac_addr > 1) 174ebea83f8SGaetan Rivet DEBUG("Configure additional MAC address%s", 175ebea83f8SGaetan Rivet (PRIV(dev)->nb_mac_addr > 2 ? "es" : "")); 176ebea83f8SGaetan Rivet for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) { 1776d13ea8eSOlivier Matz struct rte_ether_addr *ea; 178ebea83f8SGaetan Rivet 179ebea83f8SGaetan Rivet ea = &dev->data->mac_addrs[i]; 180ebea83f8SGaetan Rivet ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea, 181ebea83f8SGaetan Rivet PRIV(dev)->mac_addr_pool[i]); 182ebea83f8SGaetan Rivet if (ret) { 18335b2d13fSOlivier Matz char ea_fmt[RTE_ETHER_ADDR_FMT_SIZE]; 184ebea83f8SGaetan Rivet 18535b2d13fSOlivier Matz rte_ether_format_addr(ea_fmt, 18635b2d13fSOlivier Matz RTE_ETHER_ADDR_FMT_SIZE, ea); 187ebea83f8SGaetan Rivet ERROR("Adding MAC address %s failed", ea_fmt); 188ae7cb246SMatan Azrad return ret; 189ebea83f8SGaetan Rivet } 190ebea83f8SGaetan Rivet } 191901efc0dSEvgeny Im /* 192901efc0dSEvgeny Im * Propagate multicast MAC addresses to sub-devices, 193901efc0dSEvgeny Im * if non zero number of addresses is set. 194901efc0dSEvgeny Im * The condition is required to avoid breakage of failsafe 195901efc0dSEvgeny Im * for sub-devices which do not support the operation 196901efc0dSEvgeny Im * if the feature is really not used. 197901efc0dSEvgeny Im */ 198901efc0dSEvgeny Im if (PRIV(dev)->nb_mcast_addr > 0) { 199901efc0dSEvgeny Im DEBUG("Configuring multicast MAC addresses"); 200901efc0dSEvgeny Im ret = rte_eth_dev_set_mc_addr_list(PORT_ID(sdev), 201901efc0dSEvgeny Im PRIV(dev)->mcast_addrs, 202901efc0dSEvgeny Im PRIV(dev)->nb_mcast_addr); 203901efc0dSEvgeny Im if (ret) { 204901efc0dSEvgeny Im ERROR("Failed to apply multicast MAC addresses"); 205901efc0dSEvgeny Im return ret; 206901efc0dSEvgeny Im } 207901efc0dSEvgeny Im } 208ebea83f8SGaetan Rivet /* VLAN filter */ 209ebea83f8SGaetan Rivet vfc1 = &dev->data->vlan_filter_conf; 210ebea83f8SGaetan Rivet vfc2 = &edev->data->vlan_filter_conf; 211ebea83f8SGaetan Rivet if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) { 212ebea83f8SGaetan Rivet uint64_t vbit; 213ebea83f8SGaetan Rivet uint64_t ids; 214ebea83f8SGaetan Rivet size_t i; 215ebea83f8SGaetan Rivet uint16_t vlan_id; 216ebea83f8SGaetan Rivet 217ebea83f8SGaetan Rivet DEBUG("Configuring VLAN filter"); 218ebea83f8SGaetan Rivet for (i = 0; i < RTE_DIM(vfc1->ids); i++) { 219ebea83f8SGaetan Rivet if (vfc1->ids[i] == 0) 220ebea83f8SGaetan Rivet continue; 221ebea83f8SGaetan Rivet ids = vfc1->ids[i]; 222ebea83f8SGaetan Rivet while (ids) { 223ebea83f8SGaetan Rivet vlan_id = 64 * i; 224ebea83f8SGaetan Rivet /* count trailing zeroes */ 225ebea83f8SGaetan Rivet vbit = ~ids & (ids - 1); 226ebea83f8SGaetan Rivet /* clear least significant bit set */ 227ebea83f8SGaetan Rivet ids ^= (ids ^ (ids - 1)) ^ vbit; 228ebea83f8SGaetan Rivet for (; vbit; vlan_id++) 229ebea83f8SGaetan Rivet vbit >>= 1; 230ebea83f8SGaetan Rivet ret = rte_eth_dev_vlan_filter( 231ebea83f8SGaetan Rivet PORT_ID(sdev), vlan_id, 1); 232ebea83f8SGaetan Rivet if (ret) { 233ebea83f8SGaetan Rivet ERROR("Failed to apply VLAN filter %hu", 234ebea83f8SGaetan Rivet vlan_id); 235ebea83f8SGaetan Rivet return ret; 236ebea83f8SGaetan Rivet } 237ebea83f8SGaetan Rivet } 238ebea83f8SGaetan Rivet } 239ebea83f8SGaetan Rivet } else { 240ebea83f8SGaetan Rivet DEBUG("VLAN filter already set"); 241ebea83f8SGaetan Rivet } 242b737a1eeSGaetan Rivet /* rte_flow */ 243b737a1eeSGaetan Rivet if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) { 244b737a1eeSGaetan Rivet DEBUG("rte_flow already set"); 245b737a1eeSGaetan Rivet } else { 246b737a1eeSGaetan Rivet DEBUG("Resetting rte_flow configuration"); 247b737a1eeSGaetan Rivet ret = rte_flow_flush(PORT_ID(sdev), &ferror); 248b737a1eeSGaetan Rivet if (ret) { 249b737a1eeSGaetan Rivet fs_flow_complain(&ferror); 250b737a1eeSGaetan Rivet return ret; 251b737a1eeSGaetan Rivet } 252b737a1eeSGaetan Rivet i = 0; 253b737a1eeSGaetan Rivet rte_errno = 0; 254b737a1eeSGaetan Rivet DEBUG("Configuring rte_flow"); 255b737a1eeSGaetan Rivet TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) { 256b737a1eeSGaetan Rivet DEBUG("Creating flow #%" PRIu32, i++); 257b737a1eeSGaetan Rivet flow->flows[SUB_ID(sdev)] = 258b737a1eeSGaetan Rivet rte_flow_create(PORT_ID(sdev), 25933fcf207SAdrien Mazarguil flow->rule.attr, 26033fcf207SAdrien Mazarguil flow->rule.pattern, 26133fcf207SAdrien Mazarguil flow->rule.actions, 262b737a1eeSGaetan Rivet &ferror); 263b737a1eeSGaetan Rivet ret = rte_errno; 264b737a1eeSGaetan Rivet if (ret) 265b737a1eeSGaetan Rivet break; 266b737a1eeSGaetan Rivet } 267b737a1eeSGaetan Rivet if (ret) { 268b737a1eeSGaetan Rivet fs_flow_complain(&ferror); 269b737a1eeSGaetan Rivet return ret; 270b737a1eeSGaetan Rivet } 271b737a1eeSGaetan Rivet } 272ebea83f8SGaetan Rivet return 0; 273ebea83f8SGaetan Rivet } 274ebea83f8SGaetan Rivet 275598fb8aeSGaetan Rivet static void 276598fb8aeSGaetan Rivet fs_dev_remove(struct sub_device *sdev) 277598fb8aeSGaetan Rivet { 278598fb8aeSGaetan Rivet int ret; 279598fb8aeSGaetan Rivet 280598fb8aeSGaetan Rivet if (sdev == NULL) 281598fb8aeSGaetan Rivet return; 282598fb8aeSGaetan Rivet switch (sdev->state) { 283598fb8aeSGaetan Rivet case DEV_STARTED: 284f234e5bdSMoti Haimovsky failsafe_rx_intr_uninstall_subdevice(sdev); 28597742c7bSIvan Ilchenko ret = rte_eth_dev_stop(PORT_ID(sdev)); 28697742c7bSIvan Ilchenko if (ret < 0) 28797742c7bSIvan Ilchenko ERROR("Failed to stop sub-device %u", SUB_ID(sdev)); 288598fb8aeSGaetan Rivet sdev->state = DEV_ACTIVE; 289598fb8aeSGaetan Rivet /* fallthrough */ 290598fb8aeSGaetan Rivet case DEV_ACTIVE: 2910545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(sdev); 2928a5a0aadSThomas Monjalon ret = rte_eth_dev_close(PORT_ID(sdev)); 2938a5a0aadSThomas Monjalon if (ret < 0) { 2948a5a0aadSThomas Monjalon ERROR("Port close failed for sub-device %u", 2958a5a0aadSThomas Monjalon PORT_ID(sdev)); 2968a5a0aadSThomas Monjalon } 297598fb8aeSGaetan Rivet sdev->state = DEV_PROBED; 298598fb8aeSGaetan Rivet /* fallthrough */ 299598fb8aeSGaetan Rivet case DEV_PROBED: 300911462ebSThomas Monjalon ret = rte_dev_remove(sdev->dev); 30175b66decSIlya Maximets if (ret < 0) { 302598fb8aeSGaetan Rivet ERROR("Bus detach failed for sub_device %u", 303598fb8aeSGaetan Rivet SUB_ID(sdev)); 304598fb8aeSGaetan Rivet } else { 305fac0ae54SMatan Azrad rte_eth_dev_release_port(ETH(sdev)); 306598fb8aeSGaetan Rivet } 307598fb8aeSGaetan Rivet sdev->state = DEV_PARSED; 308598fb8aeSGaetan Rivet /* fallthrough */ 309598fb8aeSGaetan Rivet case DEV_PARSED: 310598fb8aeSGaetan Rivet case DEV_UNDEFINED: 311598fb8aeSGaetan Rivet sdev->state = DEV_UNDEFINED; 3122f4b9983SRaslan Darawsheh sdev->sdev_port_id = RTE_MAX_ETHPORTS; 313598fb8aeSGaetan Rivet /* the end */ 314598fb8aeSGaetan Rivet break; 315598fb8aeSGaetan Rivet } 31682bae1eaSMatan Azrad sdev->remove = 0; 317fa7bb47aSRaslan Darawsheh failsafe_hotplug_alarm_install(fs_dev(sdev)); 318598fb8aeSGaetan Rivet } 319598fb8aeSGaetan Rivet 3206265ab51SMatan Azrad static void 3216265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev) 3226265ab51SMatan Azrad { 323321809bbSMatan Azrad struct rte_eth_stats stats; 324321809bbSMatan Azrad int err; 325321809bbSMatan Azrad 326321809bbSMatan Azrad /* Attempt to read current stats. */ 327321809bbSMatan Azrad err = rte_eth_stats_get(PORT_ID(sdev), &stats); 3289dda3e33SMatan Azrad if (err) { 3299dda3e33SMatan Azrad uint64_t timestamp = sdev->stats_snapshot.timestamp; 3309dda3e33SMatan Azrad 33109c00246SStephen Hemminger WARN("Could not access latest statistics from sub-device %d.", 3329dda3e33SMatan Azrad SUB_ID(sdev)); 3339dda3e33SMatan Azrad if (timestamp != 0) 33409c00246SStephen Hemminger WARN("Using latest snapshot taken before %"PRIu64" seconds.", 3359dda3e33SMatan Azrad (rte_rdtsc() - timestamp) / rte_get_tsc_hz()); 3369dda3e33SMatan Azrad } 337fa7bb47aSRaslan Darawsheh failsafe_stats_increment 338fa7bb47aSRaslan Darawsheh (&PRIV(fs_dev(sdev))->stats_accumulator, 3399dda3e33SMatan Azrad err ? &sdev->stats_snapshot.stats : &stats); 3409dda3e33SMatan Azrad memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot)); 3416265ab51SMatan Azrad } 3426265ab51SMatan Azrad 343598fb8aeSGaetan Rivet static inline int 344598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev) 345598fb8aeSGaetan Rivet { 346598fb8aeSGaetan Rivet uint16_t i; 347598fb8aeSGaetan Rivet 348598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++) 349598fb8aeSGaetan Rivet if (FS_ATOMIC_RX(sdev, i)) 350598fb8aeSGaetan Rivet return 0; 351598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++) 352598fb8aeSGaetan Rivet if (FS_ATOMIC_TX(sdev, i)) 353598fb8aeSGaetan Rivet return 0; 354598fb8aeSGaetan Rivet return 1; 355598fb8aeSGaetan Rivet } 356598fb8aeSGaetan Rivet 357598fb8aeSGaetan Rivet void 3580545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev) 3590545c580SMatan Azrad { 3600545c580SMatan Azrad int ret; 3610545c580SMatan Azrad 3620545c580SMatan Azrad if (sdev == NULL) 3630545c580SMatan Azrad return; 3640545c580SMatan Azrad if (sdev->rmv_callback) { 3650545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3660545c580SMatan Azrad RTE_ETH_EVENT_INTR_RMV, 3670545c580SMatan Azrad failsafe_eth_rmv_event_callback, 3680545c580SMatan Azrad sdev); 3690545c580SMatan Azrad if (ret) 3700545c580SMatan Azrad WARN("Failed to unregister RMV callback for sub_device" 3710545c580SMatan Azrad " %d", SUB_ID(sdev)); 3720545c580SMatan Azrad sdev->rmv_callback = 0; 3730545c580SMatan Azrad } 3740545c580SMatan Azrad if (sdev->lsc_callback) { 3750545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3760545c580SMatan Azrad RTE_ETH_EVENT_INTR_LSC, 3770545c580SMatan Azrad failsafe_eth_lsc_event_callback, 3780545c580SMatan Azrad sdev); 3790545c580SMatan Azrad if (ret) 3800545c580SMatan Azrad WARN("Failed to unregister LSC callback for sub_device" 3810545c580SMatan Azrad " %d", SUB_ID(sdev)); 3820545c580SMatan Azrad sdev->lsc_callback = 0; 3830545c580SMatan Azrad } 3840545c580SMatan Azrad } 3850545c580SMatan Azrad 3860545c580SMatan Azrad void 387598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev) 388598fb8aeSGaetan Rivet { 389598fb8aeSGaetan Rivet struct sub_device *sdev; 390598fb8aeSGaetan Rivet uint8_t i; 391598fb8aeSGaetan Rivet 392352074b3SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 393352074b3SGaetan Rivet if (!sdev->remove) 394352074b3SGaetan Rivet continue; 395352074b3SGaetan Rivet 396352074b3SGaetan Rivet /* Active devices must have finished their burst and 397352074b3SGaetan Rivet * their stats must be saved. 398352074b3SGaetan Rivet */ 399352074b3SGaetan Rivet if (sdev->state >= DEV_ACTIVE && 400352074b3SGaetan Rivet fs_rxtx_clean(sdev) == 0) 401352074b3SGaetan Rivet continue; 402655fcd68SMatan Azrad if (fs_lock(dev, 1) != 0) 403655fcd68SMatan Azrad return; 404352074b3SGaetan Rivet if (sdev->state >= DEV_ACTIVE) 4056265ab51SMatan Azrad fs_dev_stats_save(sdev); 406598fb8aeSGaetan Rivet fs_dev_remove(sdev); 407655fcd68SMatan Azrad fs_unlock(dev, 1); 408598fb8aeSGaetan Rivet } 4096265ab51SMatan Azrad } 410598fb8aeSGaetan Rivet 4113db7001eSIan Dolzhansky static int 4123db7001eSIan Dolzhansky failsafe_eth_dev_rx_queues_sync(struct rte_eth_dev *dev) 4133db7001eSIan Dolzhansky { 4143db7001eSIan Dolzhansky struct rxq *rxq; 4153db7001eSIan Dolzhansky int ret; 4163db7001eSIan Dolzhansky uint16_t i; 4173db7001eSIan Dolzhansky 4183db7001eSIan Dolzhansky for (i = 0; i < dev->data->nb_rx_queues; i++) { 4193db7001eSIan Dolzhansky rxq = dev->data->rx_queues[i]; 4203db7001eSIan Dolzhansky 4213db7001eSIan Dolzhansky if (rxq->info.conf.rx_deferred_start && 4223db7001eSIan Dolzhansky dev->data->rx_queue_state[i] == 4233db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 4243db7001eSIan Dolzhansky /* 4253db7001eSIan Dolzhansky * The subdevice Rx queue does not launch on device 4263db7001eSIan Dolzhansky * start if deferred start flag is set. It needs to be 4273db7001eSIan Dolzhansky * started manually in case an appropriate failsafe Rx 4283db7001eSIan Dolzhansky * queue has been started earlier. 4293db7001eSIan Dolzhansky */ 4303db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_start(dev, i); 4313db7001eSIan Dolzhansky if (ret) { 4323db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 4333db7001eSIan Dolzhansky return ret; 4343db7001eSIan Dolzhansky } 4353db7001eSIan Dolzhansky } else if (dev->data->rx_queue_state[i] == 4363db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 4373db7001eSIan Dolzhansky /* 4383db7001eSIan Dolzhansky * The subdevice Rx queue needs to be stopped manually 4393db7001eSIan Dolzhansky * in case an appropriate failsafe Rx queue has been 4403db7001eSIan Dolzhansky * stopped earlier. 4413db7001eSIan Dolzhansky */ 4423db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_stop(dev, i); 4433db7001eSIan Dolzhansky if (ret) { 4443db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 4453db7001eSIan Dolzhansky return ret; 4463db7001eSIan Dolzhansky } 4473db7001eSIan Dolzhansky } 4483db7001eSIan Dolzhansky } 4493db7001eSIan Dolzhansky return 0; 4503db7001eSIan Dolzhansky } 4513db7001eSIan Dolzhansky 452b32c9075SIan Dolzhansky static int 453b32c9075SIan Dolzhansky failsafe_eth_dev_tx_queues_sync(struct rte_eth_dev *dev) 454b32c9075SIan Dolzhansky { 455b32c9075SIan Dolzhansky struct txq *txq; 456b32c9075SIan Dolzhansky int ret; 457b32c9075SIan Dolzhansky uint16_t i; 458b32c9075SIan Dolzhansky 459b32c9075SIan Dolzhansky for (i = 0; i < dev->data->nb_tx_queues; i++) { 460b32c9075SIan Dolzhansky txq = dev->data->tx_queues[i]; 461b32c9075SIan Dolzhansky 462b32c9075SIan Dolzhansky if (txq->info.conf.tx_deferred_start && 463b32c9075SIan Dolzhansky dev->data->tx_queue_state[i] == 464b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 465b32c9075SIan Dolzhansky /* 466b32c9075SIan Dolzhansky * The subdevice Tx queue does not launch on device 467b32c9075SIan Dolzhansky * start if deferred start flag is set. It needs to be 468b32c9075SIan Dolzhansky * started manually in case an appropriate failsafe Tx 469b32c9075SIan Dolzhansky * queue has been started earlier. 470b32c9075SIan Dolzhansky */ 471b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_start(dev, i); 472b32c9075SIan Dolzhansky if (ret) { 473b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 474b32c9075SIan Dolzhansky return ret; 475b32c9075SIan Dolzhansky } 476b32c9075SIan Dolzhansky } else if (dev->data->tx_queue_state[i] == 477b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 478b32c9075SIan Dolzhansky /* 479b32c9075SIan Dolzhansky * The subdevice Tx queue needs to be stopped manually 480b32c9075SIan Dolzhansky * in case an appropriate failsafe Tx queue has been 481b32c9075SIan Dolzhansky * stopped earlier. 482b32c9075SIan Dolzhansky */ 483b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_stop(dev, i); 484b32c9075SIan Dolzhansky if (ret) { 485b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 486b32c9075SIan Dolzhansky return ret; 487b32c9075SIan Dolzhansky } 488b32c9075SIan Dolzhansky } 489b32c9075SIan Dolzhansky } 490b32c9075SIan Dolzhansky return 0; 491b32c9075SIan Dolzhansky } 492b32c9075SIan Dolzhansky 493ebea83f8SGaetan Rivet int 494ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev) 495ebea83f8SGaetan Rivet { 496ebea83f8SGaetan Rivet struct sub_device *sdev; 497ebea83f8SGaetan Rivet uint32_t inactive; 498ebea83f8SGaetan Rivet int ret; 499ebea83f8SGaetan Rivet uint8_t i; 500ebea83f8SGaetan Rivet 501a0194d82SGaetan Rivet if (PRIV(dev)->state < DEV_PARSED) 502a0194d82SGaetan Rivet return 0; 503a0194d82SGaetan Rivet 504a0194d82SGaetan Rivet ret = failsafe_args_parse_subs(dev); 505a0194d82SGaetan Rivet if (ret) 506598fb8aeSGaetan Rivet goto err_remove; 507a0194d82SGaetan Rivet 508ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_PROBED) 509ebea83f8SGaetan Rivet return 0; 510ebea83f8SGaetan Rivet ret = failsafe_eal_init(dev); 511ebea83f8SGaetan Rivet if (ret) 512598fb8aeSGaetan Rivet goto err_remove; 513ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_ACTIVE) 514ebea83f8SGaetan Rivet return 0; 515ebea83f8SGaetan Rivet inactive = 0; 5162cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 5172cc52cd7SGaetan Rivet if (sdev->state == DEV_PROBED) { 518ebea83f8SGaetan Rivet inactive |= UINT32_C(1) << i; 5192cc52cd7SGaetan Rivet ret = eth_dev_flow_isolate_set(dev, sdev); 5202cc52cd7SGaetan Rivet if (ret) { 5212cc52cd7SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 5222cc52cd7SGaetan Rivet i); 5232cc52cd7SGaetan Rivet goto err_remove; 5242cc52cd7SGaetan Rivet } 5252cc52cd7SGaetan Rivet } 5262cc52cd7SGaetan Rivet } 527ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_configure(dev); 528ebea83f8SGaetan Rivet if (ret) 529598fb8aeSGaetan Rivet goto err_remove; 530ebea83f8SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 531ebea83f8SGaetan Rivet if (inactive & (UINT32_C(1) << i)) { 532ebea83f8SGaetan Rivet ret = fs_eth_dev_conf_apply(dev, sdev); 533ebea83f8SGaetan Rivet if (ret) { 534ebea83f8SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 535ebea83f8SGaetan Rivet i); 536598fb8aeSGaetan Rivet goto err_remove; 537ebea83f8SGaetan Rivet } 538ebea83f8SGaetan Rivet } 539ebea83f8SGaetan Rivet } 540ebea83f8SGaetan Rivet /* 541ebea83f8SGaetan Rivet * If new devices have been configured, check if 542ebea83f8SGaetan Rivet * the link state has changed. 543ebea83f8SGaetan Rivet */ 544ebea83f8SGaetan Rivet if (inactive) 545ebea83f8SGaetan Rivet dev->dev_ops->link_update(dev, 1); 546ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_STARTED) 547ebea83f8SGaetan Rivet return 0; 548ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_start(dev); 549ebea83f8SGaetan Rivet if (ret) 550598fb8aeSGaetan Rivet goto err_remove; 5513db7001eSIan Dolzhansky ret = failsafe_eth_dev_rx_queues_sync(dev); 5523db7001eSIan Dolzhansky if (ret) 5533db7001eSIan Dolzhansky goto err_remove; 554b32c9075SIan Dolzhansky ret = failsafe_eth_dev_tx_queues_sync(dev); 555b32c9075SIan Dolzhansky if (ret) 556b32c9075SIan Dolzhansky goto err_remove; 557598fb8aeSGaetan Rivet return 0; 558598fb8aeSGaetan Rivet err_remove: 559598fb8aeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 560598fb8aeSGaetan Rivet if (sdev->state != PRIV(dev)->state) 561598fb8aeSGaetan Rivet sdev->remove = 1; 562ebea83f8SGaetan Rivet return ret; 563598fb8aeSGaetan Rivet } 564598fb8aeSGaetan Rivet 5656265ab51SMatan Azrad void 5666265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from) 5676265ab51SMatan Azrad { 5686265ab51SMatan Azrad uint32_t i; 5696265ab51SMatan Azrad 5706265ab51SMatan Azrad RTE_ASSERT(to != NULL && from != NULL); 5716265ab51SMatan Azrad to->ipackets += from->ipackets; 5726265ab51SMatan Azrad to->opackets += from->opackets; 5736265ab51SMatan Azrad to->ibytes += from->ibytes; 5746265ab51SMatan Azrad to->obytes += from->obytes; 5756265ab51SMatan Azrad to->imissed += from->imissed; 5766265ab51SMatan Azrad to->ierrors += from->ierrors; 5776265ab51SMatan Azrad to->oerrors += from->oerrors; 5786265ab51SMatan Azrad to->rx_nombuf += from->rx_nombuf; 5796265ab51SMatan Azrad for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { 5806265ab51SMatan Azrad to->q_ipackets[i] += from->q_ipackets[i]; 5816265ab51SMatan Azrad to->q_opackets[i] += from->q_opackets[i]; 5826265ab51SMatan Azrad to->q_ibytes[i] += from->q_ibytes[i]; 5836265ab51SMatan Azrad to->q_obytes[i] += from->q_obytes[i]; 5846265ab51SMatan Azrad to->q_errors[i] += from->q_errors[i]; 5856265ab51SMatan Azrad } 5866265ab51SMatan Azrad } 5876265ab51SMatan Azrad 588598fb8aeSGaetan Rivet int 589f8244c63SZhiyong Yang failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused, 590598fb8aeSGaetan Rivet enum rte_eth_event_type event __rte_unused, 591598fb8aeSGaetan Rivet void *cb_arg, void *out __rte_unused) 592598fb8aeSGaetan Rivet { 593598fb8aeSGaetan Rivet struct sub_device *sdev = cb_arg; 594598fb8aeSGaetan Rivet 595813f085fSDavid Marchand if (fs_lock(fs_dev(sdev), 0) != 0) 596813f085fSDavid Marchand return -1; 597598fb8aeSGaetan Rivet /* Switch as soon as possible tx_dev. */ 598fa7bb47aSRaslan Darawsheh fs_switch_dev(fs_dev(sdev), sdev); 599598fb8aeSGaetan Rivet /* Use safe bursts in any case. */ 600fa7bb47aSRaslan Darawsheh failsafe_set_burst_fn(fs_dev(sdev), 1); 601598fb8aeSGaetan Rivet /* 602598fb8aeSGaetan Rivet * Async removal, the sub-PMD will try to unregister 603598fb8aeSGaetan Rivet * the callback at the source of the current thread context. 604598fb8aeSGaetan Rivet */ 605598fb8aeSGaetan Rivet sdev->remove = 1; 606fa7bb47aSRaslan Darawsheh fs_unlock(fs_dev(sdev), 0); 607ebea83f8SGaetan Rivet return 0; 608ebea83f8SGaetan Rivet } 609ad7d6a35SGaetan Rivet 610ad7d6a35SGaetan Rivet int 611f8244c63SZhiyong Yang failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused, 612ad7d6a35SGaetan Rivet enum rte_eth_event_type event __rte_unused, 613ad7d6a35SGaetan Rivet void *cb_arg, void *out __rte_unused) 614ad7d6a35SGaetan Rivet { 615ad7d6a35SGaetan Rivet struct rte_eth_dev *dev = cb_arg; 616ad7d6a35SGaetan Rivet int ret; 617ad7d6a35SGaetan Rivet 618ad7d6a35SGaetan Rivet ret = dev->dev_ops->link_update(dev, 0); 619ad7d6a35SGaetan Rivet /* We must pass on the LSC event */ 620ad7d6a35SGaetan Rivet if (ret) 6215723fbedSFerruh Yigit return rte_eth_dev_callback_process(dev, 622ad7d6a35SGaetan Rivet RTE_ETH_EVENT_INTR_LSC, 623cebe3d7bSThomas Monjalon NULL); 624ad7d6a35SGaetan Rivet else 625ad7d6a35SGaetan Rivet return 0; 626ad7d6a35SGaetan Rivet } 6277fda13d3SMatan Azrad 6287fda13d3SMatan Azrad /* Take sub-device ownership before it becomes exposed to the application. */ 6297fda13d3SMatan Azrad int 6307fda13d3SMatan Azrad failsafe_eth_new_event_callback(uint16_t port_id, 6317fda13d3SMatan Azrad enum rte_eth_event_type event __rte_unused, 6327fda13d3SMatan Azrad void *cb_arg, void *out __rte_unused) 6337fda13d3SMatan Azrad { 6347fda13d3SMatan Azrad struct rte_eth_dev *fs_dev = cb_arg; 6357fda13d3SMatan Azrad struct sub_device *sdev; 6367fda13d3SMatan Azrad struct rte_eth_dev *dev = &rte_eth_devices[port_id]; 6377fda13d3SMatan Azrad uint8_t i; 6387fda13d3SMatan Azrad 6397fda13d3SMatan Azrad FOREACH_SUBDEV_STATE(sdev, i, fs_dev, DEV_PARSED) { 6407fda13d3SMatan Azrad if (sdev->state >= DEV_PROBED) 6417fda13d3SMatan Azrad continue; 64294a6f2deSGaetan Rivet if (dev->device == NULL) { 643*f665790aSDavid Marchand WARN("Trying to probe malformed device %s.", 64494a6f2deSGaetan Rivet sdev->devargs.name); 64594a6f2deSGaetan Rivet continue; 64694a6f2deSGaetan Rivet } 6477fda13d3SMatan Azrad if (strcmp(sdev->devargs.name, dev->device->name) != 0) 6487fda13d3SMatan Azrad continue; 6497fda13d3SMatan Azrad rte_eth_dev_owner_set(port_id, &PRIV(fs_dev)->my_owner); 6507fda13d3SMatan Azrad /* The actual owner will be checked after the port probing. */ 6517fda13d3SMatan Azrad break; 6527fda13d3SMatan Azrad } 6537fda13d3SMatan Azrad return 0; 6547fda13d3SMatan Azrad } 655