| .. | .. |
|---|
| 1 | | -/* |
|---|
| 2 | | - * Copyright (C) 2017 Netronome Systems, Inc. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This software is dual licensed under the GNU General License Version 2, |
|---|
| 5 | | - * June 1991 as shown in the file COPYING in the top-level directory of this |
|---|
| 6 | | - * source tree or the BSD 2-Clause License provided below. You have the |
|---|
| 7 | | - * option to license this software under the complete terms of either license. |
|---|
| 8 | | - * |
|---|
| 9 | | - * The BSD 2-Clause License: |
|---|
| 10 | | - * |
|---|
| 11 | | - * Redistribution and use in source and binary forms, with or |
|---|
| 12 | | - * without modification, are permitted provided that the following |
|---|
| 13 | | - * conditions are met: |
|---|
| 14 | | - * |
|---|
| 15 | | - * 1. Redistributions of source code must retain the above |
|---|
| 16 | | - * copyright notice, this list of conditions and the following |
|---|
| 17 | | - * disclaimer. |
|---|
| 18 | | - * |
|---|
| 19 | | - * 2. Redistributions in binary form must reproduce the above |
|---|
| 20 | | - * copyright notice, this list of conditions and the following |
|---|
| 21 | | - * disclaimer in the documentation and/or other materials |
|---|
| 22 | | - * provided with the distribution. |
|---|
| 23 | | - * |
|---|
| 24 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| 25 | | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|---|
| 26 | | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| 27 | | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
|---|
| 28 | | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|---|
| 29 | | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|---|
| 30 | | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 31 | | - * SOFTWARE. |
|---|
| 32 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
|---|
| 2 | +/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ |
|---|
| 33 | 3 | |
|---|
| 34 | 4 | #include <linux/etherdevice.h> |
|---|
| 35 | 5 | #include <linux/lockdep.h> |
|---|
| .. | .. |
|---|
| 52 | 22 | |
|---|
| 53 | 23 | #define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL |
|---|
| 54 | 24 | |
|---|
| 25 | +#define NFP_MIN_INT_PORT_ID 1 |
|---|
| 26 | +#define NFP_MAX_INT_PORT_ID 256 |
|---|
| 27 | + |
|---|
| 55 | 28 | static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) |
|---|
| 56 | 29 | { |
|---|
| 57 | 30 | return "FLOWER"; |
|---|
| .. | .. |
|---|
| 60 | 33 | static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app) |
|---|
| 61 | 34 | { |
|---|
| 62 | 35 | return DEVLINK_ESWITCH_MODE_SWITCHDEV; |
|---|
| 36 | +} |
|---|
| 37 | + |
|---|
| 38 | +static int |
|---|
| 39 | +nfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv, |
|---|
| 40 | + struct net_device *netdev) |
|---|
| 41 | +{ |
|---|
| 42 | + struct net_device *entry; |
|---|
| 43 | + int i, id = 0; |
|---|
| 44 | + |
|---|
| 45 | + rcu_read_lock(); |
|---|
| 46 | + idr_for_each_entry(&priv->internal_ports.port_ids, entry, i) |
|---|
| 47 | + if (entry == netdev) { |
|---|
| 48 | + id = i; |
|---|
| 49 | + break; |
|---|
| 50 | + } |
|---|
| 51 | + rcu_read_unlock(); |
|---|
| 52 | + |
|---|
| 53 | + return id; |
|---|
| 54 | +} |
|---|
| 55 | + |
|---|
| 56 | +static int |
|---|
| 57 | +nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev) |
|---|
| 58 | +{ |
|---|
| 59 | + struct nfp_flower_priv *priv = app->priv; |
|---|
| 60 | + int id; |
|---|
| 61 | + |
|---|
| 62 | + id = nfp_flower_lookup_internal_port_id(priv, netdev); |
|---|
| 63 | + if (id > 0) |
|---|
| 64 | + return id; |
|---|
| 65 | + |
|---|
| 66 | + idr_preload(GFP_ATOMIC); |
|---|
| 67 | + spin_lock_bh(&priv->internal_ports.lock); |
|---|
| 68 | + id = idr_alloc(&priv->internal_ports.port_ids, netdev, |
|---|
| 69 | + NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC); |
|---|
| 70 | + spin_unlock_bh(&priv->internal_ports.lock); |
|---|
| 71 | + idr_preload_end(); |
|---|
| 72 | + |
|---|
| 73 | + return id; |
|---|
| 74 | +} |
|---|
| 75 | + |
|---|
| 76 | +u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app, |
|---|
| 77 | + struct net_device *netdev) |
|---|
| 78 | +{ |
|---|
| 79 | + int ext_port; |
|---|
| 80 | + |
|---|
| 81 | + if (nfp_netdev_is_nfp_repr(netdev)) { |
|---|
| 82 | + return nfp_repr_get_port_id(netdev); |
|---|
| 83 | + } else if (nfp_flower_internal_port_can_offload(app, netdev)) { |
|---|
| 84 | + ext_port = nfp_flower_get_internal_port_id(app, netdev); |
|---|
| 85 | + if (ext_port < 0) |
|---|
| 86 | + return 0; |
|---|
| 87 | + |
|---|
| 88 | + return nfp_flower_internal_port_get_port_id(ext_port); |
|---|
| 89 | + } |
|---|
| 90 | + |
|---|
| 91 | + return 0; |
|---|
| 92 | +} |
|---|
| 93 | + |
|---|
| 94 | +static struct net_device * |
|---|
| 95 | +nfp_flower_get_netdev_from_internal_port_id(struct nfp_app *app, int port_id) |
|---|
| 96 | +{ |
|---|
| 97 | + struct nfp_flower_priv *priv = app->priv; |
|---|
| 98 | + struct net_device *netdev; |
|---|
| 99 | + |
|---|
| 100 | + rcu_read_lock(); |
|---|
| 101 | + netdev = idr_find(&priv->internal_ports.port_ids, port_id); |
|---|
| 102 | + rcu_read_unlock(); |
|---|
| 103 | + |
|---|
| 104 | + return netdev; |
|---|
| 105 | +} |
|---|
| 106 | + |
|---|
| 107 | +static void |
|---|
| 108 | +nfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev) |
|---|
| 109 | +{ |
|---|
| 110 | + struct nfp_flower_priv *priv = app->priv; |
|---|
| 111 | + int id; |
|---|
| 112 | + |
|---|
| 113 | + id = nfp_flower_lookup_internal_port_id(priv, netdev); |
|---|
| 114 | + if (!id) |
|---|
| 115 | + return; |
|---|
| 116 | + |
|---|
| 117 | + spin_lock_bh(&priv->internal_ports.lock); |
|---|
| 118 | + idr_remove(&priv->internal_ports.port_ids, id); |
|---|
| 119 | + spin_unlock_bh(&priv->internal_ports.lock); |
|---|
| 120 | +} |
|---|
| 121 | + |
|---|
| 122 | +static int |
|---|
| 123 | +nfp_flower_internal_port_event_handler(struct nfp_app *app, |
|---|
| 124 | + struct net_device *netdev, |
|---|
| 125 | + unsigned long event) |
|---|
| 126 | +{ |
|---|
| 127 | + if (event == NETDEV_UNREGISTER && |
|---|
| 128 | + nfp_flower_internal_port_can_offload(app, netdev)) |
|---|
| 129 | + nfp_flower_free_internal_port_id(app, netdev); |
|---|
| 130 | + |
|---|
| 131 | + return NOTIFY_OK; |
|---|
| 132 | +} |
|---|
| 133 | + |
|---|
| 134 | +static void nfp_flower_internal_port_init(struct nfp_flower_priv *priv) |
|---|
| 135 | +{ |
|---|
| 136 | + spin_lock_init(&priv->internal_ports.lock); |
|---|
| 137 | + idr_init(&priv->internal_ports.port_ids); |
|---|
| 138 | +} |
|---|
| 139 | + |
|---|
| 140 | +static void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv) |
|---|
| 141 | +{ |
|---|
| 142 | + idr_destroy(&priv->internal_ports.port_ids); |
|---|
| 143 | +} |
|---|
| 144 | + |
|---|
| 145 | +static struct nfp_flower_non_repr_priv * |
|---|
| 146 | +nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev) |
|---|
| 147 | +{ |
|---|
| 148 | + struct nfp_flower_priv *priv = app->priv; |
|---|
| 149 | + struct nfp_flower_non_repr_priv *entry; |
|---|
| 150 | + |
|---|
| 151 | + ASSERT_RTNL(); |
|---|
| 152 | + |
|---|
| 153 | + list_for_each_entry(entry, &priv->non_repr_priv, list) |
|---|
| 154 | + if (entry->netdev == netdev) |
|---|
| 155 | + return entry; |
|---|
| 156 | + |
|---|
| 157 | + return NULL; |
|---|
| 158 | +} |
|---|
| 159 | + |
|---|
| 160 | +void |
|---|
| 161 | +__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv) |
|---|
| 162 | +{ |
|---|
| 163 | + non_repr_priv->ref_count++; |
|---|
| 164 | +} |
|---|
| 165 | + |
|---|
| 166 | +struct nfp_flower_non_repr_priv * |
|---|
| 167 | +nfp_flower_non_repr_priv_get(struct nfp_app *app, struct net_device *netdev) |
|---|
| 168 | +{ |
|---|
| 169 | + struct nfp_flower_priv *priv = app->priv; |
|---|
| 170 | + struct nfp_flower_non_repr_priv *entry; |
|---|
| 171 | + |
|---|
| 172 | + entry = nfp_flower_non_repr_priv_lookup(app, netdev); |
|---|
| 173 | + if (entry) |
|---|
| 174 | + goto inc_ref; |
|---|
| 175 | + |
|---|
| 176 | + entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
|---|
| 177 | + if (!entry) |
|---|
| 178 | + return NULL; |
|---|
| 179 | + |
|---|
| 180 | + entry->netdev = netdev; |
|---|
| 181 | + list_add(&entry->list, &priv->non_repr_priv); |
|---|
| 182 | + |
|---|
| 183 | +inc_ref: |
|---|
| 184 | + __nfp_flower_non_repr_priv_get(entry); |
|---|
| 185 | + return entry; |
|---|
| 186 | +} |
|---|
| 187 | + |
|---|
| 188 | +void |
|---|
| 189 | +__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv) |
|---|
| 190 | +{ |
|---|
| 191 | + if (--non_repr_priv->ref_count) |
|---|
| 192 | + return; |
|---|
| 193 | + |
|---|
| 194 | + list_del(&non_repr_priv->list); |
|---|
| 195 | + kfree(non_repr_priv); |
|---|
| 196 | +} |
|---|
| 197 | + |
|---|
| 198 | +void |
|---|
| 199 | +nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev) |
|---|
| 200 | +{ |
|---|
| 201 | + struct nfp_flower_non_repr_priv *entry; |
|---|
| 202 | + |
|---|
| 203 | + entry = nfp_flower_non_repr_priv_lookup(app, netdev); |
|---|
| 204 | + if (!entry) |
|---|
| 205 | + return; |
|---|
| 206 | + |
|---|
| 207 | + __nfp_flower_non_repr_priv_put(entry); |
|---|
| 63 | 208 | } |
|---|
| 64 | 209 | |
|---|
| 65 | 210 | static enum nfp_repr_type |
|---|
| .. | .. |
|---|
| 84 | 229 | } |
|---|
| 85 | 230 | |
|---|
| 86 | 231 | static struct net_device * |
|---|
| 87 | | -nfp_flower_repr_get(struct nfp_app *app, u32 port_id) |
|---|
| 232 | +nfp_flower_dev_get(struct nfp_app *app, u32 port_id, bool *redir_egress) |
|---|
| 88 | 233 | { |
|---|
| 89 | 234 | enum nfp_repr_type repr_type; |
|---|
| 90 | 235 | struct nfp_reprs *reprs; |
|---|
| 91 | 236 | u8 port = 0; |
|---|
| 237 | + |
|---|
| 238 | + /* Check if the port is internal. */ |
|---|
| 239 | + if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id) == |
|---|
| 240 | + NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT) { |
|---|
| 241 | + if (redir_egress) |
|---|
| 242 | + *redir_egress = true; |
|---|
| 243 | + port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, port_id); |
|---|
| 244 | + return nfp_flower_get_netdev_from_internal_port_id(app, port); |
|---|
| 245 | + } |
|---|
| 92 | 246 | |
|---|
| 93 | 247 | repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port); |
|---|
| 94 | 248 | if (repr_type > NFP_REPR_TYPE_MAX) |
|---|
| .. | .. |
|---|
| 137 | 291 | nfp_flower_wait_repr_reify(struct nfp_app *app, atomic_t *replies, int tot_repl) |
|---|
| 138 | 292 | { |
|---|
| 139 | 293 | struct nfp_flower_priv *priv = app->priv; |
|---|
| 140 | | - int err; |
|---|
| 141 | 294 | |
|---|
| 142 | 295 | if (!tot_repl) |
|---|
| 143 | 296 | return 0; |
|---|
| 144 | 297 | |
|---|
| 145 | 298 | lockdep_assert_held(&app->pf->lock); |
|---|
| 146 | | - err = wait_event_interruptible_timeout(priv->reify_wait_queue, |
|---|
| 147 | | - atomic_read(replies) >= tot_repl, |
|---|
| 148 | | - msecs_to_jiffies(10)); |
|---|
| 149 | | - if (err <= 0) { |
|---|
| 299 | + if (!wait_event_timeout(priv->reify_wait_queue, |
|---|
| 300 | + atomic_read(replies) >= tot_repl, |
|---|
| 301 | + NFP_FL_REPLY_TIMEOUT)) { |
|---|
| 150 | 302 | nfp_warn(app->cpp, "Not all reprs responded to reify\n"); |
|---|
| 151 | 303 | return -EIO; |
|---|
| 152 | 304 | } |
|---|
| .. | .. |
|---|
| 176 | 328 | return nfp_flower_cmsg_portmod(repr, false, repr->netdev->mtu, false); |
|---|
| 177 | 329 | } |
|---|
| 178 | 330 | |
|---|
| 179 | | -static int |
|---|
| 180 | | -nfp_flower_repr_netdev_init(struct nfp_app *app, struct net_device *netdev) |
|---|
| 181 | | -{ |
|---|
| 182 | | - return tc_setup_cb_egdev_register(netdev, |
|---|
| 183 | | - nfp_flower_setup_tc_egress_cb, |
|---|
| 184 | | - netdev_priv(netdev)); |
|---|
| 185 | | -} |
|---|
| 186 | | - |
|---|
| 187 | 331 | static void |
|---|
| 188 | 332 | nfp_flower_repr_netdev_clean(struct nfp_app *app, struct net_device *netdev) |
|---|
| 189 | 333 | { |
|---|
| 190 | 334 | struct nfp_repr *repr = netdev_priv(netdev); |
|---|
| 191 | 335 | |
|---|
| 192 | 336 | kfree(repr->app_priv); |
|---|
| 193 | | - |
|---|
| 194 | | - tc_setup_cb_egdev_unregister(netdev, nfp_flower_setup_tc_egress_cb, |
|---|
| 195 | | - netdev_priv(netdev)); |
|---|
| 196 | 337 | } |
|---|
| 197 | 338 | |
|---|
| 198 | 339 | static void |
|---|
| .. | .. |
|---|
| 265 | 406 | |
|---|
| 266 | 407 | nfp_repr = netdev_priv(repr); |
|---|
| 267 | 408 | nfp_repr->app_priv = repr_priv; |
|---|
| 409 | + repr_priv->nfp_repr = nfp_repr; |
|---|
| 268 | 410 | |
|---|
| 269 | 411 | /* For now we only support 1 PF */ |
|---|
| 270 | 412 | WARN_ON(repr_type == NFP_REPR_TYPE_PF && i); |
|---|
| .. | .. |
|---|
| 382 | 524 | |
|---|
| 383 | 525 | nfp_repr = netdev_priv(repr); |
|---|
| 384 | 526 | nfp_repr->app_priv = repr_priv; |
|---|
| 527 | + repr_priv->nfp_repr = nfp_repr; |
|---|
| 385 | 528 | |
|---|
| 386 | 529 | port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, repr); |
|---|
| 387 | 530 | if (IS_ERR(port)) { |
|---|
| .. | .. |
|---|
| 522 | 665 | return err; |
|---|
| 523 | 666 | } |
|---|
| 524 | 667 | |
|---|
| 668 | +static void nfp_flower_wait_host_bit(struct nfp_app *app) |
|---|
| 669 | +{ |
|---|
| 670 | + unsigned long err_at; |
|---|
| 671 | + u64 feat; |
|---|
| 672 | + int err; |
|---|
| 673 | + |
|---|
| 674 | + /* Wait for HOST_ACK flag bit to propagate */ |
|---|
| 675 | + err_at = jiffies + msecs_to_jiffies(100); |
|---|
| 676 | + do { |
|---|
| 677 | + feat = nfp_rtsym_read_le(app->pf->rtbl, |
|---|
| 678 | + "_abi_flower_combined_features_global", |
|---|
| 679 | + &err); |
|---|
| 680 | + if (time_is_before_eq_jiffies(err_at)) { |
|---|
| 681 | + nfp_warn(app->cpp, |
|---|
| 682 | + "HOST_ACK bit not propagated in FW.\n"); |
|---|
| 683 | + break; |
|---|
| 684 | + } |
|---|
| 685 | + usleep_range(1000, 2000); |
|---|
| 686 | + } while (!err && !(feat & NFP_FL_FEATS_HOST_ACK)); |
|---|
| 687 | + |
|---|
| 688 | + if (err) |
|---|
| 689 | + nfp_warn(app->cpp, |
|---|
| 690 | + "Could not read global features entry from FW\n"); |
|---|
| 691 | +} |
|---|
| 692 | + |
|---|
| 693 | +static int nfp_flower_sync_feature_bits(struct nfp_app *app) |
|---|
| 694 | +{ |
|---|
| 695 | + struct nfp_flower_priv *app_priv = app->priv; |
|---|
| 696 | + int err; |
|---|
| 697 | + |
|---|
| 698 | + /* Tell the firmware of the host supported features. */ |
|---|
| 699 | + err = nfp_rtsym_write_le(app->pf->rtbl, "_abi_flower_host_mask", |
|---|
| 700 | + app_priv->flower_ext_feats | |
|---|
| 701 | + NFP_FL_FEATS_HOST_ACK); |
|---|
| 702 | + if (!err) |
|---|
| 703 | + nfp_flower_wait_host_bit(app); |
|---|
| 704 | + else if (err != -ENOENT) |
|---|
| 705 | + return err; |
|---|
| 706 | + |
|---|
| 707 | + /* Tell the firmware that the driver supports lag. */ |
|---|
| 708 | + err = nfp_rtsym_write_le(app->pf->rtbl, |
|---|
| 709 | + "_abi_flower_balance_sync_enable", 1); |
|---|
| 710 | + if (!err) { |
|---|
| 711 | + app_priv->flower_en_feats |= NFP_FL_ENABLE_LAG; |
|---|
| 712 | + nfp_flower_lag_init(&app_priv->nfp_lag); |
|---|
| 713 | + } else if (err == -ENOENT) { |
|---|
| 714 | + nfp_warn(app->cpp, "LAG not supported by FW.\n"); |
|---|
| 715 | + } else { |
|---|
| 716 | + return err; |
|---|
| 717 | + } |
|---|
| 718 | + |
|---|
| 719 | + if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MOD) { |
|---|
| 720 | + /* Tell the firmware that the driver supports flow merging. */ |
|---|
| 721 | + err = nfp_rtsym_write_le(app->pf->rtbl, |
|---|
| 722 | + "_abi_flower_merge_hint_enable", 1); |
|---|
| 723 | + if (!err) { |
|---|
| 724 | + app_priv->flower_en_feats |= NFP_FL_ENABLE_FLOW_MERGE; |
|---|
| 725 | + nfp_flower_internal_port_init(app_priv); |
|---|
| 726 | + } else if (err == -ENOENT) { |
|---|
| 727 | + nfp_warn(app->cpp, |
|---|
| 728 | + "Flow merge not supported by FW.\n"); |
|---|
| 729 | + } else { |
|---|
| 730 | + return err; |
|---|
| 731 | + } |
|---|
| 732 | + } else { |
|---|
| 733 | + nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n"); |
|---|
| 734 | + } |
|---|
| 735 | + |
|---|
| 736 | + return 0; |
|---|
| 737 | +} |
|---|
| 738 | + |
|---|
| 525 | 739 | static int nfp_flower_init(struct nfp_app *app) |
|---|
| 526 | 740 | { |
|---|
| 741 | + u64 version, features, ctx_count, num_mems; |
|---|
| 527 | 742 | const struct nfp_pf *pf = app->pf; |
|---|
| 528 | 743 | struct nfp_flower_priv *app_priv; |
|---|
| 529 | | - u64 version, features; |
|---|
| 530 | 744 | int err; |
|---|
| 531 | 745 | |
|---|
| 532 | 746 | if (!pf->eth_tbl) { |
|---|
| .. | .. |
|---|
| 550 | 764 | return err; |
|---|
| 551 | 765 | } |
|---|
| 552 | 766 | |
|---|
| 767 | + num_mems = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_SPLIT", |
|---|
| 768 | + &err); |
|---|
| 769 | + if (err) { |
|---|
| 770 | + nfp_warn(app->cpp, |
|---|
| 771 | + "FlowerNIC: unsupported host context memory: %d\n", |
|---|
| 772 | + err); |
|---|
| 773 | + err = 0; |
|---|
| 774 | + num_mems = 1; |
|---|
| 775 | + } |
|---|
| 776 | + |
|---|
| 777 | + if (!FIELD_FIT(NFP_FL_STAT_ID_MU_NUM, num_mems) || !num_mems) { |
|---|
| 778 | + nfp_warn(app->cpp, |
|---|
| 779 | + "FlowerNIC: invalid host context memory: %llu\n", |
|---|
| 780 | + num_mems); |
|---|
| 781 | + return -EINVAL; |
|---|
| 782 | + } |
|---|
| 783 | + |
|---|
| 784 | + ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT", |
|---|
| 785 | + &err); |
|---|
| 786 | + if (err) { |
|---|
| 787 | + nfp_warn(app->cpp, |
|---|
| 788 | + "FlowerNIC: unsupported host context count: %d\n", |
|---|
| 789 | + err); |
|---|
| 790 | + err = 0; |
|---|
| 791 | + ctx_count = BIT(17); |
|---|
| 792 | + } |
|---|
| 793 | + |
|---|
| 553 | 794 | /* We need to ensure hardware has enough flower capabilities. */ |
|---|
| 554 | 795 | if (version != NFP_FLOWER_ALLOWED_VER) { |
|---|
| 555 | 796 | nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n"); |
|---|
| .. | .. |
|---|
| 560 | 801 | if (!app_priv) |
|---|
| 561 | 802 | return -ENOMEM; |
|---|
| 562 | 803 | |
|---|
| 804 | + app_priv->total_mem_units = num_mems; |
|---|
| 805 | + app_priv->active_mem_unit = 0; |
|---|
| 806 | + app_priv->stats_ring_size = roundup_pow_of_two(ctx_count); |
|---|
| 563 | 807 | app->priv = app_priv; |
|---|
| 564 | 808 | app_priv->app = app; |
|---|
| 565 | 809 | skb_queue_head_init(&app_priv->cmsg_skbs_high); |
|---|
| .. | .. |
|---|
| 570 | 814 | init_waitqueue_head(&app_priv->mtu_conf.wait_q); |
|---|
| 571 | 815 | spin_lock_init(&app_priv->mtu_conf.lock); |
|---|
| 572 | 816 | |
|---|
| 573 | | - err = nfp_flower_metadata_init(app); |
|---|
| 817 | + err = nfp_flower_metadata_init(app, ctx_count, num_mems); |
|---|
| 574 | 818 | if (err) |
|---|
| 575 | 819 | goto err_free_app_priv; |
|---|
| 576 | 820 | |
|---|
| .. | .. |
|---|
| 580 | 824 | if (err) |
|---|
| 581 | 825 | app_priv->flower_ext_feats = 0; |
|---|
| 582 | 826 | else |
|---|
| 583 | | - app_priv->flower_ext_feats = features; |
|---|
| 827 | + app_priv->flower_ext_feats = features & NFP_FL_FEATS_HOST; |
|---|
| 584 | 828 | |
|---|
| 585 | | - /* Tell the firmware that the driver supports lag. */ |
|---|
| 586 | | - err = nfp_rtsym_write_le(app->pf->rtbl, |
|---|
| 587 | | - "_abi_flower_balance_sync_enable", 1); |
|---|
| 588 | | - if (!err) { |
|---|
| 589 | | - app_priv->flower_ext_feats |= NFP_FL_FEATS_LAG; |
|---|
| 590 | | - nfp_flower_lag_init(&app_priv->nfp_lag); |
|---|
| 591 | | - } else if (err == -ENOENT) { |
|---|
| 592 | | - nfp_warn(app->cpp, "LAG not supported by FW.\n"); |
|---|
| 593 | | - } else { |
|---|
| 594 | | - goto err_cleanup_metadata; |
|---|
| 595 | | - } |
|---|
| 829 | + err = nfp_flower_sync_feature_bits(app); |
|---|
| 830 | + if (err) |
|---|
| 831 | + goto err_cleanup; |
|---|
| 832 | + |
|---|
| 833 | + if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM) |
|---|
| 834 | + nfp_flower_qos_init(app); |
|---|
| 835 | + |
|---|
| 836 | + INIT_LIST_HEAD(&app_priv->indr_block_cb_priv); |
|---|
| 837 | + INIT_LIST_HEAD(&app_priv->non_repr_priv); |
|---|
| 838 | + app_priv->pre_tun_rule_cnt = 0; |
|---|
| 596 | 839 | |
|---|
| 597 | 840 | return 0; |
|---|
| 598 | 841 | |
|---|
| 599 | | -err_cleanup_metadata: |
|---|
| 842 | +err_cleanup: |
|---|
| 843 | + if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) |
|---|
| 844 | + nfp_flower_lag_cleanup(&app_priv->nfp_lag); |
|---|
| 600 | 845 | nfp_flower_metadata_cleanup(app); |
|---|
| 601 | 846 | err_free_app_priv: |
|---|
| 602 | 847 | vfree(app->priv); |
|---|
| .. | .. |
|---|
| 611 | 856 | skb_queue_purge(&app_priv->cmsg_skbs_low); |
|---|
| 612 | 857 | flush_work(&app_priv->cmsg_work); |
|---|
| 613 | 858 | |
|---|
| 614 | | - if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) |
|---|
| 859 | + if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM) |
|---|
| 860 | + nfp_flower_qos_cleanup(app); |
|---|
| 861 | + |
|---|
| 862 | + if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) |
|---|
| 615 | 863 | nfp_flower_lag_cleanup(&app_priv->nfp_lag); |
|---|
| 864 | + |
|---|
| 865 | + if (app_priv->flower_en_feats & NFP_FL_ENABLE_FLOW_MERGE) |
|---|
| 866 | + nfp_flower_internal_port_cleanup(app_priv); |
|---|
| 616 | 867 | |
|---|
| 617 | 868 | nfp_flower_metadata_cleanup(app); |
|---|
| 618 | 869 | vfree(app->priv); |
|---|
| .. | .. |
|---|
| 636 | 887 | { |
|---|
| 637 | 888 | struct nfp_flower_priv *app_priv = app->priv; |
|---|
| 638 | 889 | struct nfp_repr *repr = netdev_priv(netdev); |
|---|
| 639 | | - int err, ack; |
|---|
| 890 | + int err; |
|---|
| 640 | 891 | |
|---|
| 641 | 892 | /* Only need to config FW for physical port MTU change. */ |
|---|
| 642 | 893 | if (repr->port->type != NFP_PORT_PHYS_PORT) |
|---|
| .. | .. |
|---|
| 663 | 914 | } |
|---|
| 664 | 915 | |
|---|
| 665 | 916 | /* Wait for fw to ack the change. */ |
|---|
| 666 | | - ack = wait_event_timeout(app_priv->mtu_conf.wait_q, |
|---|
| 667 | | - nfp_flower_check_ack(app_priv), |
|---|
| 668 | | - msecs_to_jiffies(10)); |
|---|
| 669 | | - |
|---|
| 670 | | - if (!ack) { |
|---|
| 917 | + if (!wait_event_timeout(app_priv->mtu_conf.wait_q, |
|---|
| 918 | + nfp_flower_check_ack(app_priv), |
|---|
| 919 | + NFP_FL_REPLY_TIMEOUT)) { |
|---|
| 671 | 920 | spin_lock_bh(&app_priv->mtu_conf.lock); |
|---|
| 672 | 921 | app_priv->mtu_conf.requested_val = 0; |
|---|
| 673 | 922 | spin_unlock_bh(&app_priv->mtu_conf.lock); |
|---|
| .. | .. |
|---|
| 683 | 932 | struct nfp_flower_priv *app_priv = app->priv; |
|---|
| 684 | 933 | int err; |
|---|
| 685 | 934 | |
|---|
| 686 | | - if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) { |
|---|
| 935 | + if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) { |
|---|
| 687 | 936 | err = nfp_flower_lag_reset(&app_priv->nfp_lag); |
|---|
| 688 | | - if (err) |
|---|
| 689 | | - return err; |
|---|
| 690 | | - |
|---|
| 691 | | - err = register_netdevice_notifier(&app_priv->nfp_lag.lag_nb); |
|---|
| 692 | 937 | if (err) |
|---|
| 693 | 938 | return err; |
|---|
| 694 | 939 | } |
|---|
| 695 | 940 | |
|---|
| 696 | | - return nfp_tunnel_config_start(app); |
|---|
| 941 | + err = flow_indr_dev_register(nfp_flower_indr_setup_tc_cb, app); |
|---|
| 942 | + if (err) |
|---|
| 943 | + return err; |
|---|
| 944 | + |
|---|
| 945 | + err = nfp_tunnel_config_start(app); |
|---|
| 946 | + if (err) |
|---|
| 947 | + goto err_tunnel_config; |
|---|
| 948 | + |
|---|
| 949 | + return 0; |
|---|
| 950 | + |
|---|
| 951 | +err_tunnel_config: |
|---|
| 952 | + flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app, |
|---|
| 953 | + nfp_flower_setup_indr_tc_release); |
|---|
| 954 | + return err; |
|---|
| 697 | 955 | } |
|---|
| 698 | 956 | |
|---|
| 699 | 957 | static void nfp_flower_stop(struct nfp_app *app) |
|---|
| 700 | 958 | { |
|---|
| 701 | | - struct nfp_flower_priv *app_priv = app->priv; |
|---|
| 702 | | - |
|---|
| 703 | | - if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG) |
|---|
| 704 | | - unregister_netdevice_notifier(&app_priv->nfp_lag.lag_nb); |
|---|
| 705 | | - |
|---|
| 706 | 959 | nfp_tunnel_config_stop(app); |
|---|
| 960 | + |
|---|
| 961 | + flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app, |
|---|
| 962 | + nfp_flower_setup_indr_tc_release); |
|---|
| 963 | +} |
|---|
| 964 | + |
|---|
| 965 | +static int |
|---|
| 966 | +nfp_flower_netdev_event(struct nfp_app *app, struct net_device *netdev, |
|---|
| 967 | + unsigned long event, void *ptr) |
|---|
| 968 | +{ |
|---|
| 969 | + struct nfp_flower_priv *app_priv = app->priv; |
|---|
| 970 | + int ret; |
|---|
| 971 | + |
|---|
| 972 | + if (app_priv->flower_en_feats & NFP_FL_ENABLE_LAG) { |
|---|
| 973 | + ret = nfp_flower_lag_netdev_event(app_priv, netdev, event, ptr); |
|---|
| 974 | + if (ret & NOTIFY_STOP_MASK) |
|---|
| 975 | + return ret; |
|---|
| 976 | + } |
|---|
| 977 | + |
|---|
| 978 | + ret = nfp_flower_internal_port_event_handler(app, netdev, event); |
|---|
| 979 | + if (ret & NOTIFY_STOP_MASK) |
|---|
| 980 | + return ret; |
|---|
| 981 | + |
|---|
| 982 | + return nfp_tunnel_mac_event_handler(app, netdev, event, ptr); |
|---|
| 707 | 983 | } |
|---|
| 708 | 984 | |
|---|
| 709 | 985 | const struct nfp_app_type app_flower = { |
|---|
| .. | .. |
|---|
| 724 | 1000 | .vnic_init = nfp_flower_vnic_init, |
|---|
| 725 | 1001 | .vnic_clean = nfp_flower_vnic_clean, |
|---|
| 726 | 1002 | |
|---|
| 727 | | - .repr_init = nfp_flower_repr_netdev_init, |
|---|
| 728 | 1003 | .repr_preclean = nfp_flower_repr_netdev_preclean, |
|---|
| 729 | 1004 | .repr_clean = nfp_flower_repr_netdev_clean, |
|---|
| 730 | 1005 | |
|---|
| .. | .. |
|---|
| 734 | 1009 | .start = nfp_flower_start, |
|---|
| 735 | 1010 | .stop = nfp_flower_stop, |
|---|
| 736 | 1011 | |
|---|
| 1012 | + .netdev_event = nfp_flower_netdev_event, |
|---|
| 1013 | + |
|---|
| 737 | 1014 | .ctrl_msg_rx = nfp_flower_cmsg_rx, |
|---|
| 738 | 1015 | |
|---|
| 739 | 1016 | .sriov_enable = nfp_flower_sriov_enable, |
|---|
| 740 | 1017 | .sriov_disable = nfp_flower_sriov_disable, |
|---|
| 741 | 1018 | |
|---|
| 742 | 1019 | .eswitch_mode_get = eswitch_mode_get, |
|---|
| 743 | | - .repr_get = nfp_flower_repr_get, |
|---|
| 1020 | + .dev_get = nfp_flower_dev_get, |
|---|
| 744 | 1021 | |
|---|
| 745 | 1022 | .setup_tc = nfp_flower_setup_tc, |
|---|
| 746 | 1023 | }; |
|---|