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]; 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) 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); 285598fb8aeSGaetan Rivet rte_eth_dev_stop(PORT_ID(sdev)); 286598fb8aeSGaetan Rivet sdev->state = DEV_ACTIVE; 287598fb8aeSGaetan Rivet /* fallthrough */ 288598fb8aeSGaetan Rivet case DEV_ACTIVE: 2890545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(sdev); 290598fb8aeSGaetan Rivet rte_eth_dev_close(PORT_ID(sdev)); 291598fb8aeSGaetan Rivet sdev->state = DEV_PROBED; 292598fb8aeSGaetan Rivet /* fallthrough */ 293598fb8aeSGaetan Rivet case DEV_PROBED: 294911462ebSThomas Monjalon ret = rte_dev_remove(sdev->dev); 29575b66decSIlya Maximets if (ret < 0) { 296598fb8aeSGaetan Rivet ERROR("Bus detach failed for sub_device %u", 297598fb8aeSGaetan Rivet SUB_ID(sdev)); 298598fb8aeSGaetan Rivet } else { 299fac0ae54SMatan Azrad rte_eth_dev_release_port(ETH(sdev)); 300598fb8aeSGaetan Rivet } 301598fb8aeSGaetan Rivet sdev->state = DEV_PARSED; 302598fb8aeSGaetan Rivet /* fallthrough */ 303598fb8aeSGaetan Rivet case DEV_PARSED: 304598fb8aeSGaetan Rivet case DEV_UNDEFINED: 305598fb8aeSGaetan Rivet sdev->state = DEV_UNDEFINED; 3062f4b9983SRaslan Darawsheh sdev->sdev_port_id = RTE_MAX_ETHPORTS; 307598fb8aeSGaetan Rivet /* the end */ 308598fb8aeSGaetan Rivet break; 309598fb8aeSGaetan Rivet } 31082bae1eaSMatan Azrad sdev->remove = 0; 311fa7bb47aSRaslan Darawsheh failsafe_hotplug_alarm_install(fs_dev(sdev)); 312598fb8aeSGaetan Rivet } 313598fb8aeSGaetan Rivet 3146265ab51SMatan Azrad static void 3156265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev) 3166265ab51SMatan Azrad { 317321809bbSMatan Azrad struct rte_eth_stats stats; 318321809bbSMatan Azrad int err; 319321809bbSMatan Azrad 320321809bbSMatan Azrad /* Attempt to read current stats. */ 321321809bbSMatan Azrad err = rte_eth_stats_get(PORT_ID(sdev), &stats); 3229dda3e33SMatan Azrad if (err) { 3239dda3e33SMatan Azrad uint64_t timestamp = sdev->stats_snapshot.timestamp; 3249dda3e33SMatan Azrad 325*09c00246SStephen Hemminger WARN("Could not access latest statistics from sub-device %d.", 3269dda3e33SMatan Azrad SUB_ID(sdev)); 3279dda3e33SMatan Azrad if (timestamp != 0) 328*09c00246SStephen Hemminger WARN("Using latest snapshot taken before %"PRIu64" seconds.", 3299dda3e33SMatan Azrad (rte_rdtsc() - timestamp) / rte_get_tsc_hz()); 3309dda3e33SMatan Azrad } 331fa7bb47aSRaslan Darawsheh failsafe_stats_increment 332fa7bb47aSRaslan Darawsheh (&PRIV(fs_dev(sdev))->stats_accumulator, 3339dda3e33SMatan Azrad err ? &sdev->stats_snapshot.stats : &stats); 3349dda3e33SMatan Azrad memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot)); 3356265ab51SMatan Azrad } 3366265ab51SMatan Azrad 337598fb8aeSGaetan Rivet static inline int 338598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev) 339598fb8aeSGaetan Rivet { 340598fb8aeSGaetan Rivet uint16_t i; 341598fb8aeSGaetan Rivet 342598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++) 343598fb8aeSGaetan Rivet if (FS_ATOMIC_RX(sdev, i)) 344598fb8aeSGaetan Rivet return 0; 345598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++) 346598fb8aeSGaetan Rivet if (FS_ATOMIC_TX(sdev, i)) 347598fb8aeSGaetan Rivet return 0; 348598fb8aeSGaetan Rivet return 1; 349598fb8aeSGaetan Rivet } 350598fb8aeSGaetan Rivet 351598fb8aeSGaetan Rivet void 3520545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev) 3530545c580SMatan Azrad { 3540545c580SMatan Azrad int ret; 3550545c580SMatan Azrad 3560545c580SMatan Azrad if (sdev == NULL) 3570545c580SMatan Azrad return; 3580545c580SMatan Azrad if (sdev->rmv_callback) { 3590545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3600545c580SMatan Azrad RTE_ETH_EVENT_INTR_RMV, 3610545c580SMatan Azrad failsafe_eth_rmv_event_callback, 3620545c580SMatan Azrad sdev); 3630545c580SMatan Azrad if (ret) 3640545c580SMatan Azrad WARN("Failed to unregister RMV callback for sub_device" 3650545c580SMatan Azrad " %d", SUB_ID(sdev)); 3660545c580SMatan Azrad sdev->rmv_callback = 0; 3670545c580SMatan Azrad } 3680545c580SMatan Azrad if (sdev->lsc_callback) { 3690545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3700545c580SMatan Azrad RTE_ETH_EVENT_INTR_LSC, 3710545c580SMatan Azrad failsafe_eth_lsc_event_callback, 3720545c580SMatan Azrad sdev); 3730545c580SMatan Azrad if (ret) 3740545c580SMatan Azrad WARN("Failed to unregister LSC callback for sub_device" 3750545c580SMatan Azrad " %d", SUB_ID(sdev)); 3760545c580SMatan Azrad sdev->lsc_callback = 0; 3770545c580SMatan Azrad } 3780545c580SMatan Azrad } 3790545c580SMatan Azrad 3800545c580SMatan Azrad void 381598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev) 382598fb8aeSGaetan Rivet { 383598fb8aeSGaetan Rivet struct sub_device *sdev; 384598fb8aeSGaetan Rivet uint8_t i; 385598fb8aeSGaetan Rivet 386598fb8aeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) 3876265ab51SMatan Azrad if (sdev->remove && fs_rxtx_clean(sdev)) { 388655fcd68SMatan Azrad if (fs_lock(dev, 1) != 0) 389655fcd68SMatan Azrad return; 3906265ab51SMatan Azrad fs_dev_stats_save(sdev); 391598fb8aeSGaetan Rivet fs_dev_remove(sdev); 392655fcd68SMatan Azrad fs_unlock(dev, 1); 393598fb8aeSGaetan Rivet } 3946265ab51SMatan Azrad } 395598fb8aeSGaetan Rivet 3963db7001eSIan Dolzhansky static int 3973db7001eSIan Dolzhansky failsafe_eth_dev_rx_queues_sync(struct rte_eth_dev *dev) 3983db7001eSIan Dolzhansky { 3993db7001eSIan Dolzhansky struct rxq *rxq; 4003db7001eSIan Dolzhansky int ret; 4013db7001eSIan Dolzhansky uint16_t i; 4023db7001eSIan Dolzhansky 4033db7001eSIan Dolzhansky for (i = 0; i < dev->data->nb_rx_queues; i++) { 4043db7001eSIan Dolzhansky rxq = dev->data->rx_queues[i]; 4053db7001eSIan Dolzhansky 4063db7001eSIan Dolzhansky if (rxq->info.conf.rx_deferred_start && 4073db7001eSIan Dolzhansky dev->data->rx_queue_state[i] == 4083db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 4093db7001eSIan Dolzhansky /* 4103db7001eSIan Dolzhansky * The subdevice Rx queue does not launch on device 4113db7001eSIan Dolzhansky * start if deferred start flag is set. It needs to be 4123db7001eSIan Dolzhansky * started manually in case an appropriate failsafe Rx 4133db7001eSIan Dolzhansky * queue has been started earlier. 4143db7001eSIan Dolzhansky */ 4153db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_start(dev, i); 4163db7001eSIan Dolzhansky if (ret) { 4173db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 4183db7001eSIan Dolzhansky return ret; 4193db7001eSIan Dolzhansky } 4203db7001eSIan Dolzhansky } else if (dev->data->rx_queue_state[i] == 4213db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 4223db7001eSIan Dolzhansky /* 4233db7001eSIan Dolzhansky * The subdevice Rx queue needs to be stopped manually 4243db7001eSIan Dolzhansky * in case an appropriate failsafe Rx queue has been 4253db7001eSIan Dolzhansky * stopped earlier. 4263db7001eSIan Dolzhansky */ 4273db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_stop(dev, i); 4283db7001eSIan Dolzhansky if (ret) { 4293db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 4303db7001eSIan Dolzhansky return ret; 4313db7001eSIan Dolzhansky } 4323db7001eSIan Dolzhansky } 4333db7001eSIan Dolzhansky } 4343db7001eSIan Dolzhansky return 0; 4353db7001eSIan Dolzhansky } 4363db7001eSIan Dolzhansky 437b32c9075SIan Dolzhansky static int 438b32c9075SIan Dolzhansky failsafe_eth_dev_tx_queues_sync(struct rte_eth_dev *dev) 439b32c9075SIan Dolzhansky { 440b32c9075SIan Dolzhansky struct txq *txq; 441b32c9075SIan Dolzhansky int ret; 442b32c9075SIan Dolzhansky uint16_t i; 443b32c9075SIan Dolzhansky 444b32c9075SIan Dolzhansky for (i = 0; i < dev->data->nb_tx_queues; i++) { 445b32c9075SIan Dolzhansky txq = dev->data->tx_queues[i]; 446b32c9075SIan Dolzhansky 447b32c9075SIan Dolzhansky if (txq->info.conf.tx_deferred_start && 448b32c9075SIan Dolzhansky dev->data->tx_queue_state[i] == 449b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 450b32c9075SIan Dolzhansky /* 451b32c9075SIan Dolzhansky * The subdevice Tx queue does not launch on device 452b32c9075SIan Dolzhansky * start if deferred start flag is set. It needs to be 453b32c9075SIan Dolzhansky * started manually in case an appropriate failsafe Tx 454b32c9075SIan Dolzhansky * queue has been started earlier. 455b32c9075SIan Dolzhansky */ 456b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_start(dev, i); 457b32c9075SIan Dolzhansky if (ret) { 458b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 459b32c9075SIan Dolzhansky return ret; 460b32c9075SIan Dolzhansky } 461b32c9075SIan Dolzhansky } else if (dev->data->tx_queue_state[i] == 462b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 463b32c9075SIan Dolzhansky /* 464b32c9075SIan Dolzhansky * The subdevice Tx queue needs to be stopped manually 465b32c9075SIan Dolzhansky * in case an appropriate failsafe Tx queue has been 466b32c9075SIan Dolzhansky * stopped earlier. 467b32c9075SIan Dolzhansky */ 468b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_stop(dev, i); 469b32c9075SIan Dolzhansky if (ret) { 470b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 471b32c9075SIan Dolzhansky return ret; 472b32c9075SIan Dolzhansky } 473b32c9075SIan Dolzhansky } 474b32c9075SIan Dolzhansky } 475b32c9075SIan Dolzhansky return 0; 476b32c9075SIan Dolzhansky } 477b32c9075SIan Dolzhansky 478ebea83f8SGaetan Rivet int 479ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev) 480ebea83f8SGaetan Rivet { 481ebea83f8SGaetan Rivet struct sub_device *sdev; 482ebea83f8SGaetan Rivet uint32_t inactive; 483ebea83f8SGaetan Rivet int ret; 484ebea83f8SGaetan Rivet uint8_t i; 485ebea83f8SGaetan Rivet 486a0194d82SGaetan Rivet if (PRIV(dev)->state < DEV_PARSED) 487a0194d82SGaetan Rivet return 0; 488a0194d82SGaetan Rivet 489a0194d82SGaetan Rivet ret = failsafe_args_parse_subs(dev); 490a0194d82SGaetan Rivet if (ret) 491598fb8aeSGaetan Rivet goto err_remove; 492a0194d82SGaetan Rivet 493ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_PROBED) 494ebea83f8SGaetan Rivet return 0; 495ebea83f8SGaetan Rivet ret = failsafe_eal_init(dev); 496ebea83f8SGaetan Rivet if (ret) 497598fb8aeSGaetan Rivet goto err_remove; 498ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_ACTIVE) 499ebea83f8SGaetan Rivet return 0; 500ebea83f8SGaetan Rivet inactive = 0; 5012cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 5022cc52cd7SGaetan Rivet if (sdev->state == DEV_PROBED) { 503ebea83f8SGaetan Rivet inactive |= UINT32_C(1) << i; 5042cc52cd7SGaetan Rivet ret = eth_dev_flow_isolate_set(dev, sdev); 5052cc52cd7SGaetan Rivet if (ret) { 5062cc52cd7SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 5072cc52cd7SGaetan Rivet i); 5082cc52cd7SGaetan Rivet goto err_remove; 5092cc52cd7SGaetan Rivet } 5102cc52cd7SGaetan Rivet } 5112cc52cd7SGaetan Rivet } 512ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_configure(dev); 513ebea83f8SGaetan Rivet if (ret) 514598fb8aeSGaetan Rivet goto err_remove; 515ebea83f8SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 516ebea83f8SGaetan Rivet if (inactive & (UINT32_C(1) << i)) { 517ebea83f8SGaetan Rivet ret = fs_eth_dev_conf_apply(dev, sdev); 518ebea83f8SGaetan Rivet if (ret) { 519ebea83f8SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 520ebea83f8SGaetan Rivet i); 521598fb8aeSGaetan Rivet goto err_remove; 522ebea83f8SGaetan Rivet } 523ebea83f8SGaetan Rivet } 524ebea83f8SGaetan Rivet } 525ebea83f8SGaetan Rivet /* 526ebea83f8SGaetan Rivet * If new devices have been configured, check if 527ebea83f8SGaetan Rivet * the link state has changed. 528ebea83f8SGaetan Rivet */ 529ebea83f8SGaetan Rivet if (inactive) 530ebea83f8SGaetan Rivet dev->dev_ops->link_update(dev, 1); 531ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_STARTED) 532ebea83f8SGaetan Rivet return 0; 533ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_start(dev); 534ebea83f8SGaetan Rivet if (ret) 535598fb8aeSGaetan Rivet goto err_remove; 5363db7001eSIan Dolzhansky ret = failsafe_eth_dev_rx_queues_sync(dev); 5373db7001eSIan Dolzhansky if (ret) 5383db7001eSIan Dolzhansky goto err_remove; 539b32c9075SIan Dolzhansky ret = failsafe_eth_dev_tx_queues_sync(dev); 540b32c9075SIan Dolzhansky if (ret) 541b32c9075SIan Dolzhansky goto err_remove; 542598fb8aeSGaetan Rivet return 0; 543598fb8aeSGaetan Rivet err_remove: 544598fb8aeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 545598fb8aeSGaetan Rivet if (sdev->state != PRIV(dev)->state) 546598fb8aeSGaetan Rivet sdev->remove = 1; 547ebea83f8SGaetan Rivet return ret; 548598fb8aeSGaetan Rivet } 549598fb8aeSGaetan Rivet 5506265ab51SMatan Azrad void 5516265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from) 5526265ab51SMatan Azrad { 5536265ab51SMatan Azrad uint32_t i; 5546265ab51SMatan Azrad 5556265ab51SMatan Azrad RTE_ASSERT(to != NULL && from != NULL); 5566265ab51SMatan Azrad to->ipackets += from->ipackets; 5576265ab51SMatan Azrad to->opackets += from->opackets; 5586265ab51SMatan Azrad to->ibytes += from->ibytes; 5596265ab51SMatan Azrad to->obytes += from->obytes; 5606265ab51SMatan Azrad to->imissed += from->imissed; 5616265ab51SMatan Azrad to->ierrors += from->ierrors; 5626265ab51SMatan Azrad to->oerrors += from->oerrors; 5636265ab51SMatan Azrad to->rx_nombuf += from->rx_nombuf; 5646265ab51SMatan Azrad for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { 5656265ab51SMatan Azrad to->q_ipackets[i] += from->q_ipackets[i]; 5666265ab51SMatan Azrad to->q_opackets[i] += from->q_opackets[i]; 5676265ab51SMatan Azrad to->q_ibytes[i] += from->q_ibytes[i]; 5686265ab51SMatan Azrad to->q_obytes[i] += from->q_obytes[i]; 5696265ab51SMatan Azrad to->q_errors[i] += from->q_errors[i]; 5706265ab51SMatan Azrad } 5716265ab51SMatan Azrad } 5726265ab51SMatan Azrad 573598fb8aeSGaetan Rivet int 574f8244c63SZhiyong Yang failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused, 575598fb8aeSGaetan Rivet enum rte_eth_event_type event __rte_unused, 576598fb8aeSGaetan Rivet void *cb_arg, void *out __rte_unused) 577598fb8aeSGaetan Rivet { 578598fb8aeSGaetan Rivet struct sub_device *sdev = cb_arg; 579598fb8aeSGaetan Rivet 580fa7bb47aSRaslan Darawsheh fs_lock(fs_dev(sdev), 0); 581598fb8aeSGaetan Rivet /* Switch as soon as possible tx_dev. */ 582fa7bb47aSRaslan Darawsheh fs_switch_dev(fs_dev(sdev), sdev); 583598fb8aeSGaetan Rivet /* Use safe bursts in any case. */ 584fa7bb47aSRaslan Darawsheh failsafe_set_burst_fn(fs_dev(sdev), 1); 585598fb8aeSGaetan Rivet /* 586598fb8aeSGaetan Rivet * Async removal, the sub-PMD will try to unregister 587598fb8aeSGaetan Rivet * the callback at the source of the current thread context. 588598fb8aeSGaetan Rivet */ 589598fb8aeSGaetan Rivet sdev->remove = 1; 590fa7bb47aSRaslan Darawsheh fs_unlock(fs_dev(sdev), 0); 591ebea83f8SGaetan Rivet return 0; 592ebea83f8SGaetan Rivet } 593ad7d6a35SGaetan Rivet 594ad7d6a35SGaetan Rivet int 595f8244c63SZhiyong Yang failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused, 596ad7d6a35SGaetan Rivet enum rte_eth_event_type event __rte_unused, 597ad7d6a35SGaetan Rivet void *cb_arg, void *out __rte_unused) 598ad7d6a35SGaetan Rivet { 599ad7d6a35SGaetan Rivet struct rte_eth_dev *dev = cb_arg; 600ad7d6a35SGaetan Rivet int ret; 601ad7d6a35SGaetan Rivet 602ad7d6a35SGaetan Rivet ret = dev->dev_ops->link_update(dev, 0); 603ad7d6a35SGaetan Rivet /* We must pass on the LSC event */ 604ad7d6a35SGaetan Rivet if (ret) 605ad7d6a35SGaetan Rivet return _rte_eth_dev_callback_process(dev, 606ad7d6a35SGaetan Rivet RTE_ETH_EVENT_INTR_LSC, 607cebe3d7bSThomas Monjalon NULL); 608ad7d6a35SGaetan Rivet else 609ad7d6a35SGaetan Rivet return 0; 610ad7d6a35SGaetan Rivet } 6117fda13d3SMatan Azrad 6127fda13d3SMatan Azrad /* Take sub-device ownership before it becomes exposed to the application. */ 6137fda13d3SMatan Azrad int 6147fda13d3SMatan Azrad failsafe_eth_new_event_callback(uint16_t port_id, 6157fda13d3SMatan Azrad enum rte_eth_event_type event __rte_unused, 6167fda13d3SMatan Azrad void *cb_arg, void *out __rte_unused) 6177fda13d3SMatan Azrad { 6187fda13d3SMatan Azrad struct rte_eth_dev *fs_dev = cb_arg; 6197fda13d3SMatan Azrad struct sub_device *sdev; 6207fda13d3SMatan Azrad struct rte_eth_dev *dev = &rte_eth_devices[port_id]; 6217fda13d3SMatan Azrad uint8_t i; 6227fda13d3SMatan Azrad 6237fda13d3SMatan Azrad FOREACH_SUBDEV_STATE(sdev, i, fs_dev, DEV_PARSED) { 6247fda13d3SMatan Azrad if (sdev->state >= DEV_PROBED) 6257fda13d3SMatan Azrad continue; 62694a6f2deSGaetan Rivet if (dev->device == NULL) { 62794a6f2deSGaetan Rivet WARN("Trying to probe malformed device %s.\n", 62894a6f2deSGaetan Rivet sdev->devargs.name); 62994a6f2deSGaetan Rivet continue; 63094a6f2deSGaetan Rivet } 6317fda13d3SMatan Azrad if (strcmp(sdev->devargs.name, dev->device->name) != 0) 6327fda13d3SMatan Azrad continue; 6337fda13d3SMatan Azrad rte_eth_dev_owner_set(port_id, &PRIV(fs_dev)->my_owner); 6347fda13d3SMatan Azrad /* The actual owner will be checked after the port probing. */ 6357fda13d3SMatan Azrad break; 6367fda13d3SMatan Azrad } 6377fda13d3SMatan Azrad return 0; 6387fda13d3SMatan Azrad } 639