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) 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: 2630545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(sdev); 264598fb8aeSGaetan Rivet rte_eth_dev_close(PORT_ID(sdev)); 265598fb8aeSGaetan Rivet sdev->state = DEV_PROBED; 266598fb8aeSGaetan Rivet /* fallthrough */ 267598fb8aeSGaetan Rivet case DEV_PROBED: 268598fb8aeSGaetan Rivet ret = rte_eal_hotplug_remove(sdev->bus->name, 269598fb8aeSGaetan Rivet sdev->dev->name); 270598fb8aeSGaetan Rivet if (ret) { 271598fb8aeSGaetan Rivet ERROR("Bus detach failed for sub_device %u", 272598fb8aeSGaetan Rivet SUB_ID(sdev)); 273598fb8aeSGaetan Rivet } else { 274fac0ae54SMatan Azrad rte_eth_dev_release_port(ETH(sdev)); 275598fb8aeSGaetan Rivet } 276598fb8aeSGaetan Rivet sdev->state = DEV_PARSED; 277598fb8aeSGaetan Rivet /* fallthrough */ 278598fb8aeSGaetan Rivet case DEV_PARSED: 279598fb8aeSGaetan Rivet case DEV_UNDEFINED: 280598fb8aeSGaetan Rivet sdev->state = DEV_UNDEFINED; 281598fb8aeSGaetan Rivet /* the end */ 282598fb8aeSGaetan Rivet break; 283598fb8aeSGaetan Rivet } 28482bae1eaSMatan Azrad sdev->remove = 0; 285598fb8aeSGaetan Rivet failsafe_hotplug_alarm_install(sdev->fs_dev); 286598fb8aeSGaetan Rivet } 287598fb8aeSGaetan Rivet 2886265ab51SMatan Azrad static void 2896265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev) 2906265ab51SMatan Azrad { 291321809bbSMatan Azrad struct rte_eth_stats stats; 292321809bbSMatan Azrad int err; 293321809bbSMatan Azrad 294321809bbSMatan Azrad /* Attempt to read current stats. */ 295321809bbSMatan Azrad err = rte_eth_stats_get(PORT_ID(sdev), &stats); 2969dda3e33SMatan Azrad if (err) { 2979dda3e33SMatan Azrad uint64_t timestamp = sdev->stats_snapshot.timestamp; 2989dda3e33SMatan Azrad 2999dda3e33SMatan Azrad WARN("Could not access latest statistics from sub-device %d.\n", 3009dda3e33SMatan Azrad SUB_ID(sdev)); 3019dda3e33SMatan Azrad if (timestamp != 0) 3029dda3e33SMatan Azrad WARN("Using latest snapshot taken before %"PRIu64" seconds.\n", 3039dda3e33SMatan Azrad (rte_rdtsc() - timestamp) / rte_get_tsc_hz()); 3049dda3e33SMatan Azrad } 3056265ab51SMatan Azrad failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator, 3069dda3e33SMatan Azrad err ? &sdev->stats_snapshot.stats : &stats); 3079dda3e33SMatan Azrad memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot)); 3086265ab51SMatan Azrad } 3096265ab51SMatan Azrad 310598fb8aeSGaetan Rivet static inline int 311598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev) 312598fb8aeSGaetan Rivet { 313598fb8aeSGaetan Rivet uint16_t i; 314598fb8aeSGaetan Rivet 315598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++) 316598fb8aeSGaetan Rivet if (FS_ATOMIC_RX(sdev, i)) 317598fb8aeSGaetan Rivet return 0; 318598fb8aeSGaetan Rivet for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++) 319598fb8aeSGaetan Rivet if (FS_ATOMIC_TX(sdev, i)) 320598fb8aeSGaetan Rivet return 0; 321598fb8aeSGaetan Rivet return 1; 322598fb8aeSGaetan Rivet } 323598fb8aeSGaetan Rivet 324598fb8aeSGaetan Rivet void 3250545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev) 3260545c580SMatan Azrad { 3270545c580SMatan Azrad int ret; 3280545c580SMatan Azrad 3290545c580SMatan Azrad if (sdev == NULL) 3300545c580SMatan Azrad return; 3310545c580SMatan Azrad if (sdev->rmv_callback) { 3320545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3330545c580SMatan Azrad RTE_ETH_EVENT_INTR_RMV, 3340545c580SMatan Azrad failsafe_eth_rmv_event_callback, 3350545c580SMatan Azrad sdev); 3360545c580SMatan Azrad if (ret) 3370545c580SMatan Azrad WARN("Failed to unregister RMV callback for sub_device" 3380545c580SMatan Azrad " %d", SUB_ID(sdev)); 3390545c580SMatan Azrad sdev->rmv_callback = 0; 3400545c580SMatan Azrad } 3410545c580SMatan Azrad if (sdev->lsc_callback) { 3420545c580SMatan Azrad ret = rte_eth_dev_callback_unregister(PORT_ID(sdev), 3430545c580SMatan Azrad RTE_ETH_EVENT_INTR_LSC, 3440545c580SMatan Azrad failsafe_eth_lsc_event_callback, 3450545c580SMatan Azrad sdev); 3460545c580SMatan Azrad if (ret) 3470545c580SMatan Azrad WARN("Failed to unregister LSC callback for sub_device" 3480545c580SMatan Azrad " %d", SUB_ID(sdev)); 3490545c580SMatan Azrad sdev->lsc_callback = 0; 3500545c580SMatan Azrad } 3510545c580SMatan Azrad } 3520545c580SMatan Azrad 3530545c580SMatan Azrad void 354598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev) 355598fb8aeSGaetan Rivet { 356598fb8aeSGaetan Rivet struct sub_device *sdev; 357598fb8aeSGaetan Rivet uint8_t i; 358598fb8aeSGaetan Rivet 359598fb8aeSGaetan Rivet FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) 3606265ab51SMatan Azrad if (sdev->remove && fs_rxtx_clean(sdev)) { 361655fcd68SMatan Azrad if (fs_lock(dev, 1) != 0) 362655fcd68SMatan Azrad return; 3636265ab51SMatan Azrad fs_dev_stats_save(sdev); 364598fb8aeSGaetan Rivet fs_dev_remove(sdev); 365655fcd68SMatan Azrad fs_unlock(dev, 1); 366598fb8aeSGaetan Rivet } 3676265ab51SMatan Azrad } 368598fb8aeSGaetan Rivet 3693db7001eSIan Dolzhansky static int 3703db7001eSIan Dolzhansky failsafe_eth_dev_rx_queues_sync(struct rte_eth_dev *dev) 3713db7001eSIan Dolzhansky { 3723db7001eSIan Dolzhansky struct rxq *rxq; 3733db7001eSIan Dolzhansky int ret; 3743db7001eSIan Dolzhansky uint16_t i; 3753db7001eSIan Dolzhansky 3763db7001eSIan Dolzhansky for (i = 0; i < dev->data->nb_rx_queues; i++) { 3773db7001eSIan Dolzhansky rxq = dev->data->rx_queues[i]; 3783db7001eSIan Dolzhansky 3793db7001eSIan Dolzhansky if (rxq->info.conf.rx_deferred_start && 3803db7001eSIan Dolzhansky dev->data->rx_queue_state[i] == 3813db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 3823db7001eSIan Dolzhansky /* 3833db7001eSIan Dolzhansky * The subdevice Rx queue does not launch on device 3843db7001eSIan Dolzhansky * start if deferred start flag is set. It needs to be 3853db7001eSIan Dolzhansky * started manually in case an appropriate failsafe Rx 3863db7001eSIan Dolzhansky * queue has been started earlier. 3873db7001eSIan Dolzhansky */ 3883db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_start(dev, i); 3893db7001eSIan Dolzhansky if (ret) { 3903db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 3913db7001eSIan Dolzhansky return ret; 3923db7001eSIan Dolzhansky } 3933db7001eSIan Dolzhansky } else if (dev->data->rx_queue_state[i] == 3943db7001eSIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 3953db7001eSIan Dolzhansky /* 3963db7001eSIan Dolzhansky * The subdevice Rx queue needs to be stopped manually 3973db7001eSIan Dolzhansky * in case an appropriate failsafe Rx queue has been 3983db7001eSIan Dolzhansky * stopped earlier. 3993db7001eSIan Dolzhansky */ 4003db7001eSIan Dolzhansky ret = dev->dev_ops->rx_queue_stop(dev, i); 4013db7001eSIan Dolzhansky if (ret) { 4023db7001eSIan Dolzhansky ERROR("Could not synchronize Rx queue %d", i); 4033db7001eSIan Dolzhansky return ret; 4043db7001eSIan Dolzhansky } 4053db7001eSIan Dolzhansky } 4063db7001eSIan Dolzhansky } 4073db7001eSIan Dolzhansky return 0; 4083db7001eSIan Dolzhansky } 4093db7001eSIan Dolzhansky 410*b32c9075SIan Dolzhansky static int 411*b32c9075SIan Dolzhansky failsafe_eth_dev_tx_queues_sync(struct rte_eth_dev *dev) 412*b32c9075SIan Dolzhansky { 413*b32c9075SIan Dolzhansky struct txq *txq; 414*b32c9075SIan Dolzhansky int ret; 415*b32c9075SIan Dolzhansky uint16_t i; 416*b32c9075SIan Dolzhansky 417*b32c9075SIan Dolzhansky for (i = 0; i < dev->data->nb_tx_queues; i++) { 418*b32c9075SIan Dolzhansky txq = dev->data->tx_queues[i]; 419*b32c9075SIan Dolzhansky 420*b32c9075SIan Dolzhansky if (txq->info.conf.tx_deferred_start && 421*b32c9075SIan Dolzhansky dev->data->tx_queue_state[i] == 422*b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STARTED) { 423*b32c9075SIan Dolzhansky /* 424*b32c9075SIan Dolzhansky * The subdevice Tx queue does not launch on device 425*b32c9075SIan Dolzhansky * start if deferred start flag is set. It needs to be 426*b32c9075SIan Dolzhansky * started manually in case an appropriate failsafe Tx 427*b32c9075SIan Dolzhansky * queue has been started earlier. 428*b32c9075SIan Dolzhansky */ 429*b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_start(dev, i); 430*b32c9075SIan Dolzhansky if (ret) { 431*b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 432*b32c9075SIan Dolzhansky return ret; 433*b32c9075SIan Dolzhansky } 434*b32c9075SIan Dolzhansky } else if (dev->data->tx_queue_state[i] == 435*b32c9075SIan Dolzhansky RTE_ETH_QUEUE_STATE_STOPPED) { 436*b32c9075SIan Dolzhansky /* 437*b32c9075SIan Dolzhansky * The subdevice Tx queue needs to be stopped manually 438*b32c9075SIan Dolzhansky * in case an appropriate failsafe Tx queue has been 439*b32c9075SIan Dolzhansky * stopped earlier. 440*b32c9075SIan Dolzhansky */ 441*b32c9075SIan Dolzhansky ret = dev->dev_ops->tx_queue_stop(dev, i); 442*b32c9075SIan Dolzhansky if (ret) { 443*b32c9075SIan Dolzhansky ERROR("Could not synchronize Tx queue %d", i); 444*b32c9075SIan Dolzhansky return ret; 445*b32c9075SIan Dolzhansky } 446*b32c9075SIan Dolzhansky } 447*b32c9075SIan Dolzhansky } 448*b32c9075SIan Dolzhansky return 0; 449*b32c9075SIan Dolzhansky } 450*b32c9075SIan Dolzhansky 451ebea83f8SGaetan Rivet int 452ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev) 453ebea83f8SGaetan Rivet { 454ebea83f8SGaetan Rivet struct sub_device *sdev; 455ebea83f8SGaetan Rivet uint32_t inactive; 456ebea83f8SGaetan Rivet int ret; 457ebea83f8SGaetan Rivet uint8_t i; 458ebea83f8SGaetan Rivet 459a0194d82SGaetan Rivet if (PRIV(dev)->state < DEV_PARSED) 460a0194d82SGaetan Rivet return 0; 461a0194d82SGaetan Rivet 462a0194d82SGaetan Rivet ret = failsafe_args_parse_subs(dev); 463a0194d82SGaetan Rivet if (ret) 464598fb8aeSGaetan Rivet goto err_remove; 465a0194d82SGaetan Rivet 466ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_PROBED) 467ebea83f8SGaetan Rivet return 0; 468ebea83f8SGaetan Rivet ret = failsafe_eal_init(dev); 469ebea83f8SGaetan Rivet if (ret) 470598fb8aeSGaetan Rivet goto err_remove; 471ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_ACTIVE) 472ebea83f8SGaetan Rivet return 0; 473ebea83f8SGaetan Rivet inactive = 0; 4742cc52cd7SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 4752cc52cd7SGaetan Rivet if (sdev->state == DEV_PROBED) { 476ebea83f8SGaetan Rivet inactive |= UINT32_C(1) << i; 4772cc52cd7SGaetan Rivet ret = eth_dev_flow_isolate_set(dev, sdev); 4782cc52cd7SGaetan Rivet if (ret) { 4792cc52cd7SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 4802cc52cd7SGaetan Rivet i); 4812cc52cd7SGaetan Rivet goto err_remove; 4822cc52cd7SGaetan Rivet } 4832cc52cd7SGaetan Rivet } 4842cc52cd7SGaetan Rivet } 485ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_configure(dev); 486ebea83f8SGaetan Rivet if (ret) 487598fb8aeSGaetan Rivet goto err_remove; 488ebea83f8SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 489ebea83f8SGaetan Rivet if (inactive & (UINT32_C(1) << i)) { 490ebea83f8SGaetan Rivet ret = fs_eth_dev_conf_apply(dev, sdev); 491ebea83f8SGaetan Rivet if (ret) { 492ebea83f8SGaetan Rivet ERROR("Could not apply configuration to sub_device %d", 493ebea83f8SGaetan Rivet i); 494598fb8aeSGaetan Rivet goto err_remove; 495ebea83f8SGaetan Rivet } 496ebea83f8SGaetan Rivet } 497ebea83f8SGaetan Rivet } 498ebea83f8SGaetan Rivet /* 499ebea83f8SGaetan Rivet * If new devices have been configured, check if 500ebea83f8SGaetan Rivet * the link state has changed. 501ebea83f8SGaetan Rivet */ 502ebea83f8SGaetan Rivet if (inactive) 503ebea83f8SGaetan Rivet dev->dev_ops->link_update(dev, 1); 504ebea83f8SGaetan Rivet if (PRIV(dev)->state < DEV_STARTED) 505ebea83f8SGaetan Rivet return 0; 506ebea83f8SGaetan Rivet ret = dev->dev_ops->dev_start(dev); 507ebea83f8SGaetan Rivet if (ret) 508598fb8aeSGaetan Rivet goto err_remove; 5093db7001eSIan Dolzhansky ret = failsafe_eth_dev_rx_queues_sync(dev); 5103db7001eSIan Dolzhansky if (ret) 5113db7001eSIan Dolzhansky goto err_remove; 512*b32c9075SIan Dolzhansky ret = failsafe_eth_dev_tx_queues_sync(dev); 513*b32c9075SIan Dolzhansky if (ret) 514*b32c9075SIan Dolzhansky goto err_remove; 515598fb8aeSGaetan Rivet return 0; 516598fb8aeSGaetan Rivet err_remove: 517598fb8aeSGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) 518598fb8aeSGaetan Rivet if (sdev->state != PRIV(dev)->state) 519598fb8aeSGaetan Rivet sdev->remove = 1; 520ebea83f8SGaetan Rivet return ret; 521598fb8aeSGaetan Rivet } 522598fb8aeSGaetan Rivet 5236265ab51SMatan Azrad void 5246265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from) 5256265ab51SMatan Azrad { 5266265ab51SMatan Azrad uint32_t i; 5276265ab51SMatan Azrad 5286265ab51SMatan Azrad RTE_ASSERT(to != NULL && from != NULL); 5296265ab51SMatan Azrad to->ipackets += from->ipackets; 5306265ab51SMatan Azrad to->opackets += from->opackets; 5316265ab51SMatan Azrad to->ibytes += from->ibytes; 5326265ab51SMatan Azrad to->obytes += from->obytes; 5336265ab51SMatan Azrad to->imissed += from->imissed; 5346265ab51SMatan Azrad to->ierrors += from->ierrors; 5356265ab51SMatan Azrad to->oerrors += from->oerrors; 5366265ab51SMatan Azrad to->rx_nombuf += from->rx_nombuf; 5376265ab51SMatan Azrad for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { 5386265ab51SMatan Azrad to->q_ipackets[i] += from->q_ipackets[i]; 5396265ab51SMatan Azrad to->q_opackets[i] += from->q_opackets[i]; 5406265ab51SMatan Azrad to->q_ibytes[i] += from->q_ibytes[i]; 5416265ab51SMatan Azrad to->q_obytes[i] += from->q_obytes[i]; 5426265ab51SMatan Azrad to->q_errors[i] += from->q_errors[i]; 5436265ab51SMatan Azrad } 5446265ab51SMatan Azrad } 5456265ab51SMatan Azrad 546598fb8aeSGaetan Rivet int 547f8244c63SZhiyong Yang failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused, 548598fb8aeSGaetan Rivet enum rte_eth_event_type event __rte_unused, 549598fb8aeSGaetan Rivet void *cb_arg, void *out __rte_unused) 550598fb8aeSGaetan Rivet { 551598fb8aeSGaetan Rivet struct sub_device *sdev = cb_arg; 552598fb8aeSGaetan Rivet 553655fcd68SMatan Azrad fs_lock(sdev->fs_dev, 0); 554598fb8aeSGaetan Rivet /* Switch as soon as possible tx_dev. */ 555598fb8aeSGaetan Rivet fs_switch_dev(sdev->fs_dev, sdev); 556598fb8aeSGaetan Rivet /* Use safe bursts in any case. */ 557598fb8aeSGaetan Rivet set_burst_fn(sdev->fs_dev, 1); 558598fb8aeSGaetan Rivet /* 559598fb8aeSGaetan Rivet * Async removal, the sub-PMD will try to unregister 560598fb8aeSGaetan Rivet * the callback at the source of the current thread context. 561598fb8aeSGaetan Rivet */ 562598fb8aeSGaetan Rivet sdev->remove = 1; 563655fcd68SMatan Azrad fs_unlock(sdev->fs_dev, 0); 564ebea83f8SGaetan Rivet return 0; 565ebea83f8SGaetan Rivet } 566ad7d6a35SGaetan Rivet 567ad7d6a35SGaetan Rivet int 568f8244c63SZhiyong Yang failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused, 569ad7d6a35SGaetan Rivet enum rte_eth_event_type event __rte_unused, 570ad7d6a35SGaetan Rivet void *cb_arg, void *out __rte_unused) 571ad7d6a35SGaetan Rivet { 572ad7d6a35SGaetan Rivet struct rte_eth_dev *dev = cb_arg; 573ad7d6a35SGaetan Rivet int ret; 574ad7d6a35SGaetan Rivet 575ad7d6a35SGaetan Rivet ret = dev->dev_ops->link_update(dev, 0); 576ad7d6a35SGaetan Rivet /* We must pass on the LSC event */ 577ad7d6a35SGaetan Rivet if (ret) 578ad7d6a35SGaetan Rivet return _rte_eth_dev_callback_process(dev, 579ad7d6a35SGaetan Rivet RTE_ETH_EVENT_INTR_LSC, 580cebe3d7bSThomas Monjalon NULL); 581ad7d6a35SGaetan Rivet else 582ad7d6a35SGaetan Rivet return 0; 583ad7d6a35SGaetan Rivet } 5847fda13d3SMatan Azrad 5857fda13d3SMatan Azrad /* Take sub-device ownership before it becomes exposed to the application. */ 5867fda13d3SMatan Azrad int 5877fda13d3SMatan Azrad failsafe_eth_new_event_callback(uint16_t port_id, 5887fda13d3SMatan Azrad enum rte_eth_event_type event __rte_unused, 5897fda13d3SMatan Azrad void *cb_arg, void *out __rte_unused) 5907fda13d3SMatan Azrad { 5917fda13d3SMatan Azrad struct rte_eth_dev *fs_dev = cb_arg; 5927fda13d3SMatan Azrad struct sub_device *sdev; 5937fda13d3SMatan Azrad struct rte_eth_dev *dev = &rte_eth_devices[port_id]; 5947fda13d3SMatan Azrad uint8_t i; 5957fda13d3SMatan Azrad 5967fda13d3SMatan Azrad FOREACH_SUBDEV_STATE(sdev, i, fs_dev, DEV_PARSED) { 5977fda13d3SMatan Azrad if (sdev->state >= DEV_PROBED) 5987fda13d3SMatan Azrad continue; 5997fda13d3SMatan Azrad if (strcmp(sdev->devargs.name, dev->device->name) != 0) 6007fda13d3SMatan Azrad continue; 6017fda13d3SMatan Azrad rte_eth_dev_owner_set(port_id, &PRIV(fs_dev)->my_owner); 6027fda13d3SMatan Azrad /* The actual owner will be checked after the port probing. */ 6037fda13d3SMatan Azrad break; 6047fda13d3SMatan Azrad } 6057fda13d3SMatan Azrad return 0; 6067fda13d3SMatan Azrad } 607