| .. | .. |
|---|
| 1 | | -// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
|---|
| 2 | | -/* |
|---|
| 3 | | - * Copyright (C) 2018 Netronome Systems, Inc. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This software is dual licensed under the GNU General License Version 2, |
|---|
| 6 | | - * June 1991 as shown in the file COPYING in the top-level directory of this |
|---|
| 7 | | - * source tree or the BSD 2-Clause License provided below. You have the |
|---|
| 8 | | - * option to license this software under the complete terms of either license. |
|---|
| 9 | | - * |
|---|
| 10 | | - * The BSD 2-Clause License: |
|---|
| 11 | | - * |
|---|
| 12 | | - * Redistribution and use in source and binary forms, with or |
|---|
| 13 | | - * without modification, are permitted provided that the following |
|---|
| 14 | | - * conditions are met: |
|---|
| 15 | | - * |
|---|
| 16 | | - * 1. Redistributions of source code must retain the above |
|---|
| 17 | | - * copyright notice, this list of conditions and the following |
|---|
| 18 | | - * disclaimer. |
|---|
| 19 | | - * |
|---|
| 20 | | - * 2. Redistributions in binary form must reproduce the above |
|---|
| 21 | | - * copyright notice, this list of conditions and the following |
|---|
| 22 | | - * disclaimer in the documentation and/or other materials |
|---|
| 23 | | - * provided with the distribution. |
|---|
| 24 | | - * |
|---|
| 25 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| 26 | | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|---|
| 27 | | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| 28 | | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
|---|
| 29 | | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|---|
| 30 | | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|---|
| 31 | | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 32 | | - * SOFTWARE. |
|---|
| 33 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
|---|
| 2 | +/* Copyright (C) 2018 Netronome Systems, Inc. */ |
|---|
| 34 | 3 | |
|---|
| 35 | 4 | #include <linux/bitfield.h> |
|---|
| 5 | +#include <linux/bitmap.h> |
|---|
| 36 | 6 | #include <linux/etherdevice.h> |
|---|
| 37 | 7 | #include <linux/lockdep.h> |
|---|
| 38 | 8 | #include <linux/netdevice.h> |
|---|
| 39 | 9 | #include <linux/rcupdate.h> |
|---|
| 10 | +#include <linux/rtnetlink.h> |
|---|
| 40 | 11 | #include <linux/slab.h> |
|---|
| 41 | | -#include <net/pkt_cls.h> |
|---|
| 42 | | -#include <net/pkt_sched.h> |
|---|
| 43 | | -#include <net/red.h> |
|---|
| 44 | 12 | |
|---|
| 45 | 13 | #include "../nfpcore/nfp.h" |
|---|
| 46 | 14 | #include "../nfpcore/nfp_cpp.h" |
|---|
| .. | .. |
|---|
| 59 | 27 | } |
|---|
| 60 | 28 | |
|---|
| 61 | 29 | static int |
|---|
| 62 | | -__nfp_abm_reset_root(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 63 | | - u32 handle, unsigned int qs, u32 init_val) |
|---|
| 64 | | -{ |
|---|
| 65 | | - struct nfp_port *port = nfp_port_from_netdev(netdev); |
|---|
| 66 | | - int ret; |
|---|
| 67 | | - |
|---|
| 68 | | - ret = nfp_abm_ctrl_set_all_q_lvls(alink, init_val); |
|---|
| 69 | | - memset(alink->qdiscs, 0, sizeof(*alink->qdiscs) * alink->num_qdiscs); |
|---|
| 70 | | - |
|---|
| 71 | | - alink->parent = handle; |
|---|
| 72 | | - alink->num_qdiscs = qs; |
|---|
| 73 | | - port->tc_offload_cnt = qs; |
|---|
| 74 | | - |
|---|
| 75 | | - return ret; |
|---|
| 76 | | -} |
|---|
| 77 | | - |
|---|
| 78 | | -static void |
|---|
| 79 | | -nfp_abm_reset_root(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 80 | | - u32 handle, unsigned int qs) |
|---|
| 81 | | -{ |
|---|
| 82 | | - __nfp_abm_reset_root(netdev, alink, handle, qs, ~0); |
|---|
| 83 | | -} |
|---|
| 84 | | - |
|---|
| 85 | | -static int |
|---|
| 86 | | -nfp_abm_red_find(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) |
|---|
| 87 | | -{ |
|---|
| 88 | | - unsigned int i = TC_H_MIN(opt->parent) - 1; |
|---|
| 89 | | - |
|---|
| 90 | | - if (opt->parent == TC_H_ROOT) |
|---|
| 91 | | - i = 0; |
|---|
| 92 | | - else if (TC_H_MAJ(alink->parent) == TC_H_MAJ(opt->parent)) |
|---|
| 93 | | - i = TC_H_MIN(opt->parent) - 1; |
|---|
| 94 | | - else |
|---|
| 95 | | - return -EOPNOTSUPP; |
|---|
| 96 | | - |
|---|
| 97 | | - if (i >= alink->num_qdiscs || opt->handle != alink->qdiscs[i].handle) |
|---|
| 98 | | - return -EOPNOTSUPP; |
|---|
| 99 | | - |
|---|
| 100 | | - return i; |
|---|
| 101 | | -} |
|---|
| 102 | | - |
|---|
| 103 | | -static void |
|---|
| 104 | | -nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 105 | | - u32 handle) |
|---|
| 106 | | -{ |
|---|
| 107 | | - unsigned int i; |
|---|
| 108 | | - |
|---|
| 109 | | - for (i = 0; i < alink->num_qdiscs; i++) |
|---|
| 110 | | - if (handle == alink->qdiscs[i].handle) |
|---|
| 111 | | - break; |
|---|
| 112 | | - if (i == alink->num_qdiscs) |
|---|
| 113 | | - return; |
|---|
| 114 | | - |
|---|
| 115 | | - if (alink->parent == TC_H_ROOT) { |
|---|
| 116 | | - nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 0); |
|---|
| 117 | | - } else { |
|---|
| 118 | | - nfp_abm_ctrl_set_q_lvl(alink, i, ~0); |
|---|
| 119 | | - memset(&alink->qdiscs[i], 0, sizeof(*alink->qdiscs)); |
|---|
| 120 | | - } |
|---|
| 121 | | -} |
|---|
| 122 | | - |
|---|
| 123 | | -static int |
|---|
| 124 | | -nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 125 | | - struct tc_red_qopt_offload *opt) |
|---|
| 126 | | -{ |
|---|
| 127 | | - bool existing; |
|---|
| 128 | | - int i, err; |
|---|
| 129 | | - |
|---|
| 130 | | - i = nfp_abm_red_find(alink, opt); |
|---|
| 131 | | - existing = i >= 0; |
|---|
| 132 | | - |
|---|
| 133 | | - if (opt->set.min != opt->set.max || !opt->set.is_ecn) { |
|---|
| 134 | | - nfp_warn(alink->abm->app->cpp, |
|---|
| 135 | | - "RED offload failed - unsupported parameters\n"); |
|---|
| 136 | | - err = -EINVAL; |
|---|
| 137 | | - goto err_destroy; |
|---|
| 138 | | - } |
|---|
| 139 | | - |
|---|
| 140 | | - if (existing) { |
|---|
| 141 | | - if (alink->parent == TC_H_ROOT) |
|---|
| 142 | | - err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min); |
|---|
| 143 | | - else |
|---|
| 144 | | - err = nfp_abm_ctrl_set_q_lvl(alink, i, opt->set.min); |
|---|
| 145 | | - if (err) |
|---|
| 146 | | - goto err_destroy; |
|---|
| 147 | | - return 0; |
|---|
| 148 | | - } |
|---|
| 149 | | - |
|---|
| 150 | | - if (opt->parent == TC_H_ROOT) { |
|---|
| 151 | | - i = 0; |
|---|
| 152 | | - err = __nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 1, |
|---|
| 153 | | - opt->set.min); |
|---|
| 154 | | - } else if (TC_H_MAJ(alink->parent) == TC_H_MAJ(opt->parent)) { |
|---|
| 155 | | - i = TC_H_MIN(opt->parent) - 1; |
|---|
| 156 | | - err = nfp_abm_ctrl_set_q_lvl(alink, i, opt->set.min); |
|---|
| 157 | | - } else { |
|---|
| 158 | | - return -EINVAL; |
|---|
| 159 | | - } |
|---|
| 160 | | - /* Set the handle to try full clean up, in case IO failed */ |
|---|
| 161 | | - alink->qdiscs[i].handle = opt->handle; |
|---|
| 162 | | - if (err) |
|---|
| 163 | | - goto err_destroy; |
|---|
| 164 | | - |
|---|
| 165 | | - if (opt->parent == TC_H_ROOT) |
|---|
| 166 | | - err = nfp_abm_ctrl_read_stats(alink, &alink->qdiscs[i].stats); |
|---|
| 167 | | - else |
|---|
| 168 | | - err = nfp_abm_ctrl_read_q_stats(alink, i, |
|---|
| 169 | | - &alink->qdiscs[i].stats); |
|---|
| 170 | | - if (err) |
|---|
| 171 | | - goto err_destroy; |
|---|
| 172 | | - |
|---|
| 173 | | - if (opt->parent == TC_H_ROOT) |
|---|
| 174 | | - err = nfp_abm_ctrl_read_xstats(alink, |
|---|
| 175 | | - &alink->qdiscs[i].xstats); |
|---|
| 176 | | - else |
|---|
| 177 | | - err = nfp_abm_ctrl_read_q_xstats(alink, i, |
|---|
| 178 | | - &alink->qdiscs[i].xstats); |
|---|
| 179 | | - if (err) |
|---|
| 180 | | - goto err_destroy; |
|---|
| 181 | | - |
|---|
| 182 | | - alink->qdiscs[i].stats.backlog_pkts = 0; |
|---|
| 183 | | - alink->qdiscs[i].stats.backlog_bytes = 0; |
|---|
| 184 | | - |
|---|
| 185 | | - return 0; |
|---|
| 186 | | -err_destroy: |
|---|
| 187 | | - /* If the qdisc keeps on living, but we can't offload undo changes */ |
|---|
| 188 | | - if (existing) { |
|---|
| 189 | | - opt->set.qstats->qlen -= alink->qdiscs[i].stats.backlog_pkts; |
|---|
| 190 | | - opt->set.qstats->backlog -= |
|---|
| 191 | | - alink->qdiscs[i].stats.backlog_bytes; |
|---|
| 192 | | - } |
|---|
| 193 | | - nfp_abm_red_destroy(netdev, alink, opt->handle); |
|---|
| 194 | | - |
|---|
| 195 | | - return err; |
|---|
| 196 | | -} |
|---|
| 197 | | - |
|---|
| 198 | | -static void |
|---|
| 199 | | -nfp_abm_update_stats(struct nfp_alink_stats *new, struct nfp_alink_stats *old, |
|---|
| 200 | | - struct tc_qopt_offload_stats *stats) |
|---|
| 201 | | -{ |
|---|
| 202 | | - _bstats_update(stats->bstats, new->tx_bytes - old->tx_bytes, |
|---|
| 203 | | - new->tx_pkts - old->tx_pkts); |
|---|
| 204 | | - stats->qstats->qlen += new->backlog_pkts - old->backlog_pkts; |
|---|
| 205 | | - stats->qstats->backlog += new->backlog_bytes - old->backlog_bytes; |
|---|
| 206 | | - stats->qstats->overlimits += new->overlimits - old->overlimits; |
|---|
| 207 | | - stats->qstats->drops += new->drops - old->drops; |
|---|
| 208 | | -} |
|---|
| 209 | | - |
|---|
| 210 | | -static int |
|---|
| 211 | | -nfp_abm_red_stats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) |
|---|
| 212 | | -{ |
|---|
| 213 | | - struct nfp_alink_stats *prev_stats; |
|---|
| 214 | | - struct nfp_alink_stats stats; |
|---|
| 215 | | - int i, err; |
|---|
| 216 | | - |
|---|
| 217 | | - i = nfp_abm_red_find(alink, opt); |
|---|
| 218 | | - if (i < 0) |
|---|
| 219 | | - return i; |
|---|
| 220 | | - prev_stats = &alink->qdiscs[i].stats; |
|---|
| 221 | | - |
|---|
| 222 | | - if (alink->parent == TC_H_ROOT) |
|---|
| 223 | | - err = nfp_abm_ctrl_read_stats(alink, &stats); |
|---|
| 224 | | - else |
|---|
| 225 | | - err = nfp_abm_ctrl_read_q_stats(alink, i, &stats); |
|---|
| 226 | | - if (err) |
|---|
| 227 | | - return err; |
|---|
| 228 | | - |
|---|
| 229 | | - nfp_abm_update_stats(&stats, prev_stats, &opt->stats); |
|---|
| 230 | | - |
|---|
| 231 | | - *prev_stats = stats; |
|---|
| 232 | | - |
|---|
| 233 | | - return 0; |
|---|
| 234 | | -} |
|---|
| 235 | | - |
|---|
| 236 | | -static int |
|---|
| 237 | | -nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) |
|---|
| 238 | | -{ |
|---|
| 239 | | - struct nfp_alink_xstats *prev_xstats; |
|---|
| 240 | | - struct nfp_alink_xstats xstats; |
|---|
| 241 | | - int i, err; |
|---|
| 242 | | - |
|---|
| 243 | | - i = nfp_abm_red_find(alink, opt); |
|---|
| 244 | | - if (i < 0) |
|---|
| 245 | | - return i; |
|---|
| 246 | | - prev_xstats = &alink->qdiscs[i].xstats; |
|---|
| 247 | | - |
|---|
| 248 | | - if (alink->parent == TC_H_ROOT) |
|---|
| 249 | | - err = nfp_abm_ctrl_read_xstats(alink, &xstats); |
|---|
| 250 | | - else |
|---|
| 251 | | - err = nfp_abm_ctrl_read_q_xstats(alink, i, &xstats); |
|---|
| 252 | | - if (err) |
|---|
| 253 | | - return err; |
|---|
| 254 | | - |
|---|
| 255 | | - opt->xstats->forced_mark += xstats.ecn_marked - prev_xstats->ecn_marked; |
|---|
| 256 | | - opt->xstats->pdrop += xstats.pdrop - prev_xstats->pdrop; |
|---|
| 257 | | - |
|---|
| 258 | | - *prev_xstats = xstats; |
|---|
| 259 | | - |
|---|
| 260 | | - return 0; |
|---|
| 261 | | -} |
|---|
| 262 | | - |
|---|
| 263 | | -static int |
|---|
| 264 | | -nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 265 | | - struct tc_red_qopt_offload *opt) |
|---|
| 266 | | -{ |
|---|
| 267 | | - switch (opt->command) { |
|---|
| 268 | | - case TC_RED_REPLACE: |
|---|
| 269 | | - return nfp_abm_red_replace(netdev, alink, opt); |
|---|
| 270 | | - case TC_RED_DESTROY: |
|---|
| 271 | | - nfp_abm_red_destroy(netdev, alink, opt->handle); |
|---|
| 272 | | - return 0; |
|---|
| 273 | | - case TC_RED_STATS: |
|---|
| 274 | | - return nfp_abm_red_stats(alink, opt); |
|---|
| 275 | | - case TC_RED_XSTATS: |
|---|
| 276 | | - return nfp_abm_red_xstats(alink, opt); |
|---|
| 277 | | - default: |
|---|
| 278 | | - return -EOPNOTSUPP; |
|---|
| 279 | | - } |
|---|
| 280 | | -} |
|---|
| 281 | | - |
|---|
| 282 | | -static int |
|---|
| 283 | | -nfp_abm_mq_stats(struct nfp_abm_link *alink, struct tc_mq_qopt_offload *opt) |
|---|
| 284 | | -{ |
|---|
| 285 | | - struct nfp_alink_stats stats; |
|---|
| 286 | | - unsigned int i; |
|---|
| 287 | | - int err; |
|---|
| 288 | | - |
|---|
| 289 | | - for (i = 0; i < alink->num_qdiscs; i++) { |
|---|
| 290 | | - if (alink->qdiscs[i].handle == TC_H_UNSPEC) |
|---|
| 291 | | - continue; |
|---|
| 292 | | - |
|---|
| 293 | | - err = nfp_abm_ctrl_read_q_stats(alink, i, &stats); |
|---|
| 294 | | - if (err) |
|---|
| 295 | | - return err; |
|---|
| 296 | | - |
|---|
| 297 | | - nfp_abm_update_stats(&stats, &alink->qdiscs[i].stats, |
|---|
| 298 | | - &opt->stats); |
|---|
| 299 | | - } |
|---|
| 300 | | - |
|---|
| 301 | | - return 0; |
|---|
| 302 | | -} |
|---|
| 303 | | - |
|---|
| 304 | | -static int |
|---|
| 305 | | -nfp_abm_setup_tc_mq(struct net_device *netdev, struct nfp_abm_link *alink, |
|---|
| 306 | | - struct tc_mq_qopt_offload *opt) |
|---|
| 307 | | -{ |
|---|
| 308 | | - switch (opt->command) { |
|---|
| 309 | | - case TC_MQ_CREATE: |
|---|
| 310 | | - nfp_abm_reset_root(netdev, alink, opt->handle, |
|---|
| 311 | | - alink->total_queues); |
|---|
| 312 | | - return 0; |
|---|
| 313 | | - case TC_MQ_DESTROY: |
|---|
| 314 | | - if (opt->handle == alink->parent) |
|---|
| 315 | | - nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 0); |
|---|
| 316 | | - return 0; |
|---|
| 317 | | - case TC_MQ_STATS: |
|---|
| 318 | | - return nfp_abm_mq_stats(alink, opt); |
|---|
| 319 | | - default: |
|---|
| 320 | | - return -EOPNOTSUPP; |
|---|
| 321 | | - } |
|---|
| 322 | | -} |
|---|
| 323 | | - |
|---|
| 324 | | -static int |
|---|
| 325 | 30 | nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev, |
|---|
| 326 | 31 | enum tc_setup_type type, void *type_data) |
|---|
| 327 | 32 | { |
|---|
| .. | .. |
|---|
| 333 | 38 | return -EOPNOTSUPP; |
|---|
| 334 | 39 | |
|---|
| 335 | 40 | switch (type) { |
|---|
| 41 | + case TC_SETUP_ROOT_QDISC: |
|---|
| 42 | + return nfp_abm_setup_root(netdev, repr->app_priv, type_data); |
|---|
| 336 | 43 | case TC_SETUP_QDISC_MQ: |
|---|
| 337 | 44 | return nfp_abm_setup_tc_mq(netdev, repr->app_priv, type_data); |
|---|
| 338 | 45 | case TC_SETUP_QDISC_RED: |
|---|
| 339 | 46 | return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data); |
|---|
| 47 | + case TC_SETUP_QDISC_GRED: |
|---|
| 48 | + return nfp_abm_setup_tc_gred(netdev, repr->app_priv, type_data); |
|---|
| 49 | + case TC_SETUP_BLOCK: |
|---|
| 50 | + return nfp_abm_setup_cls_block(netdev, repr, type_data); |
|---|
| 340 | 51 | default: |
|---|
| 341 | 52 | return -EOPNOTSUPP; |
|---|
| 342 | 53 | } |
|---|
| 343 | 54 | } |
|---|
| 344 | 55 | |
|---|
| 345 | | -static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id) |
|---|
| 56 | +static struct net_device * |
|---|
| 57 | +nfp_abm_repr_get(struct nfp_app *app, u32 port_id, bool *redir_egress) |
|---|
| 346 | 58 | { |
|---|
| 347 | 59 | enum nfp_repr_type rtype; |
|---|
| 348 | 60 | struct nfp_reprs *reprs; |
|---|
| .. | .. |
|---|
| 415 | 127 | |
|---|
| 416 | 128 | reprs = nfp_reprs_get_locked(app, rtype); |
|---|
| 417 | 129 | WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr"); |
|---|
| 130 | + rtnl_lock(); |
|---|
| 418 | 131 | rcu_assign_pointer(reprs->reprs[alink->id], netdev); |
|---|
| 132 | + rtnl_unlock(); |
|---|
| 419 | 133 | |
|---|
| 420 | 134 | nfp_info(app->cpp, "%s Port %d Representor(%s) created\n", |
|---|
| 421 | 135 | ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys", |
|---|
| .. | .. |
|---|
| 441 | 155 | netdev = nfp_repr_get_locked(app, reprs, alink->id); |
|---|
| 442 | 156 | if (!netdev) |
|---|
| 443 | 157 | return; |
|---|
| 158 | + rtnl_lock(); |
|---|
| 444 | 159 | rcu_assign_pointer(reprs->reprs[alink->id], NULL); |
|---|
| 160 | + rtnl_unlock(); |
|---|
| 445 | 161 | synchronize_rcu(); |
|---|
| 446 | 162 | /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */ |
|---|
| 447 | 163 | nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev)); |
|---|
| .. | .. |
|---|
| 492 | 208 | struct nfp_net *nn; |
|---|
| 493 | 209 | int err; |
|---|
| 494 | 210 | |
|---|
| 211 | + if (!abm->red_support) |
|---|
| 212 | + return -EOPNOTSUPP; |
|---|
| 213 | + |
|---|
| 495 | 214 | err = nfp_abm_ctrl_qm_enable(abm); |
|---|
| 496 | 215 | if (err) |
|---|
| 497 | 216 | return err; |
|---|
| .. | .. |
|---|
| 540 | 259 | { |
|---|
| 541 | 260 | struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id]; |
|---|
| 542 | 261 | u8 mac_addr[ETH_ALEN]; |
|---|
| 543 | | - const char *mac_str; |
|---|
| 544 | | - char name[32]; |
|---|
| 262 | + struct nfp_nsp *nsp; |
|---|
| 263 | + char hwinfo[32]; |
|---|
| 264 | + int err; |
|---|
| 545 | 265 | |
|---|
| 546 | 266 | if (id > pf->eth_tbl->count) { |
|---|
| 547 | 267 | nfp_warn(pf->cpp, "No entry for persistent MAC address\n"); |
|---|
| .. | .. |
|---|
| 549 | 269 | return; |
|---|
| 550 | 270 | } |
|---|
| 551 | 271 | |
|---|
| 552 | | - snprintf(name, sizeof(name), "eth%u.mac.pf%u", |
|---|
| 272 | + snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac.pf%u", |
|---|
| 553 | 273 | eth_port->eth_index, abm->pf_id); |
|---|
| 554 | 274 | |
|---|
| 555 | | - mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); |
|---|
| 556 | | - if (!mac_str) { |
|---|
| 557 | | - nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n", |
|---|
| 558 | | - name); |
|---|
| 275 | + nsp = nfp_nsp_open(pf->cpp); |
|---|
| 276 | + if (IS_ERR(nsp)) { |
|---|
| 277 | + nfp_warn(pf->cpp, "Failed to access the NSP for persistent MAC address: %ld\n", |
|---|
| 278 | + PTR_ERR(nsp)); |
|---|
| 559 | 279 | eth_hw_addr_random(nn->dp.netdev); |
|---|
| 560 | 280 | return; |
|---|
| 561 | 281 | } |
|---|
| 562 | 282 | |
|---|
| 563 | | - if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", |
|---|
| 283 | + if (!nfp_nsp_has_hwinfo_lookup(nsp)) { |
|---|
| 284 | + nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n"); |
|---|
| 285 | + eth_hw_addr_random(nn->dp.netdev); |
|---|
| 286 | + nfp_nsp_close(nsp); |
|---|
| 287 | + return; |
|---|
| 288 | + } |
|---|
| 289 | + |
|---|
| 290 | + err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo)); |
|---|
| 291 | + nfp_nsp_close(nsp); |
|---|
| 292 | + if (err) { |
|---|
| 293 | + nfp_warn(pf->cpp, "Reading persistent MAC address failed: %d\n", |
|---|
| 294 | + err); |
|---|
| 295 | + eth_hw_addr_random(nn->dp.netdev); |
|---|
| 296 | + return; |
|---|
| 297 | + } |
|---|
| 298 | + |
|---|
| 299 | + if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", |
|---|
| 564 | 300 | &mac_addr[0], &mac_addr[1], &mac_addr[2], |
|---|
| 565 | 301 | &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { |
|---|
| 566 | 302 | nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n", |
|---|
| 567 | | - mac_str); |
|---|
| 303 | + hwinfo); |
|---|
| 568 | 304 | eth_hw_addr_random(nn->dp.netdev); |
|---|
| 569 | 305 | return; |
|---|
| 570 | 306 | } |
|---|
| .. | .. |
|---|
| 588 | 324 | alink->abm = abm; |
|---|
| 589 | 325 | alink->vnic = nn; |
|---|
| 590 | 326 | alink->id = id; |
|---|
| 591 | | - alink->parent = TC_H_ROOT; |
|---|
| 592 | 327 | alink->total_queues = alink->vnic->max_rx_rings; |
|---|
| 593 | | - alink->qdiscs = kvcalloc(alink->total_queues, sizeof(*alink->qdiscs), |
|---|
| 594 | | - GFP_KERNEL); |
|---|
| 595 | | - if (!alink->qdiscs) { |
|---|
| 328 | + |
|---|
| 329 | + INIT_LIST_HEAD(&alink->dscp_map); |
|---|
| 330 | + |
|---|
| 331 | + err = nfp_abm_ctrl_read_params(alink); |
|---|
| 332 | + if (err) |
|---|
| 333 | + goto err_free_alink; |
|---|
| 334 | + |
|---|
| 335 | + alink->prio_map = kzalloc(abm->prio_map_len, GFP_KERNEL); |
|---|
| 336 | + if (!alink->prio_map) { |
|---|
| 596 | 337 | err = -ENOMEM; |
|---|
| 597 | 338 | goto err_free_alink; |
|---|
| 598 | 339 | } |
|---|
| .. | .. |
|---|
| 602 | 343 | */ |
|---|
| 603 | 344 | err = nfp_eth_set_configured(app->cpp, eth_port->index, true); |
|---|
| 604 | 345 | if (err < 0) |
|---|
| 605 | | - goto err_free_qdiscs; |
|---|
| 346 | + goto err_free_priomap; |
|---|
| 606 | 347 | |
|---|
| 607 | 348 | netif_keep_dst(nn->dp.netdev); |
|---|
| 608 | 349 | |
|---|
| 609 | 350 | nfp_abm_vnic_set_mac(app->pf, abm, nn, id); |
|---|
| 610 | | - nfp_abm_ctrl_read_params(alink); |
|---|
| 351 | + INIT_RADIX_TREE(&alink->qdiscs, GFP_KERNEL); |
|---|
| 611 | 352 | |
|---|
| 612 | 353 | return 0; |
|---|
| 613 | 354 | |
|---|
| 614 | | -err_free_qdiscs: |
|---|
| 615 | | - kvfree(alink->qdiscs); |
|---|
| 355 | +err_free_priomap: |
|---|
| 356 | + kfree(alink->prio_map); |
|---|
| 616 | 357 | err_free_alink: |
|---|
| 617 | 358 | kfree(alink); |
|---|
| 618 | 359 | return err; |
|---|
| .. | .. |
|---|
| 623 | 364 | struct nfp_abm_link *alink = nn->app_priv; |
|---|
| 624 | 365 | |
|---|
| 625 | 366 | nfp_abm_kill_reprs(alink->abm, alink); |
|---|
| 626 | | - kvfree(alink->qdiscs); |
|---|
| 367 | + WARN(!radix_tree_empty(&alink->qdiscs), "left over qdiscs\n"); |
|---|
| 368 | + kfree(alink->prio_map); |
|---|
| 627 | 369 | kfree(alink); |
|---|
| 370 | +} |
|---|
| 371 | + |
|---|
| 372 | +static int nfp_abm_vnic_init(struct nfp_app *app, struct nfp_net *nn) |
|---|
| 373 | +{ |
|---|
| 374 | + struct nfp_abm_link *alink = nn->app_priv; |
|---|
| 375 | + |
|---|
| 376 | + if (nfp_abm_has_prio(alink->abm)) |
|---|
| 377 | + return nfp_abm_ctrl_prio_map_update(alink, alink->prio_map); |
|---|
| 378 | + return 0; |
|---|
| 628 | 379 | } |
|---|
| 629 | 380 | |
|---|
| 630 | 381 | static u64 * |
|---|
| .. | .. |
|---|
| 674 | 425 | return data; |
|---|
| 675 | 426 | } |
|---|
| 676 | 427 | |
|---|
| 428 | +static int nfp_abm_fw_init_reset(struct nfp_abm *abm) |
|---|
| 429 | +{ |
|---|
| 430 | + unsigned int i; |
|---|
| 431 | + |
|---|
| 432 | + if (!abm->red_support) |
|---|
| 433 | + return 0; |
|---|
| 434 | + |
|---|
| 435 | + for (i = 0; i < abm->num_bands * NFP_NET_MAX_RX_RINGS; i++) { |
|---|
| 436 | + __nfp_abm_ctrl_set_q_lvl(abm, i, NFP_ABM_LVL_INFINITY); |
|---|
| 437 | + __nfp_abm_ctrl_set_q_act(abm, i, NFP_ABM_ACT_DROP); |
|---|
| 438 | + } |
|---|
| 439 | + |
|---|
| 440 | + return nfp_abm_ctrl_qm_disable(abm); |
|---|
| 441 | +} |
|---|
| 442 | + |
|---|
| 677 | 443 | static int nfp_abm_init(struct nfp_app *app) |
|---|
| 678 | 444 | { |
|---|
| 679 | 445 | struct nfp_pf *pf = app->pf; |
|---|
| .. | .. |
|---|
| 705 | 471 | if (err) |
|---|
| 706 | 472 | goto err_free_abm; |
|---|
| 707 | 473 | |
|---|
| 708 | | - /* We start in legacy mode, make sure advanced queuing is disabled */ |
|---|
| 709 | | - err = nfp_abm_ctrl_qm_disable(abm); |
|---|
| 710 | | - if (err) |
|---|
| 474 | + err = -ENOMEM; |
|---|
| 475 | + abm->num_thresholds = array_size(abm->num_bands, NFP_NET_MAX_RX_RINGS); |
|---|
| 476 | + abm->threshold_undef = bitmap_zalloc(abm->num_thresholds, GFP_KERNEL); |
|---|
| 477 | + if (!abm->threshold_undef) |
|---|
| 711 | 478 | goto err_free_abm; |
|---|
| 479 | + |
|---|
| 480 | + abm->thresholds = kvcalloc(abm->num_thresholds, |
|---|
| 481 | + sizeof(*abm->thresholds), GFP_KERNEL); |
|---|
| 482 | + if (!abm->thresholds) |
|---|
| 483 | + goto err_free_thresh_umap; |
|---|
| 484 | + |
|---|
| 485 | + abm->actions = kvcalloc(abm->num_thresholds, sizeof(*abm->actions), |
|---|
| 486 | + GFP_KERNEL); |
|---|
| 487 | + if (!abm->actions) |
|---|
| 488 | + goto err_free_thresh; |
|---|
| 489 | + |
|---|
| 490 | + /* We start in legacy mode, make sure advanced queuing is disabled */ |
|---|
| 491 | + err = nfp_abm_fw_init_reset(abm); |
|---|
| 492 | + if (err) |
|---|
| 493 | + goto err_free_act; |
|---|
| 712 | 494 | |
|---|
| 713 | 495 | err = -ENOMEM; |
|---|
| 714 | 496 | reprs = nfp_reprs_alloc(pf->max_data_vnics); |
|---|
| 715 | 497 | if (!reprs) |
|---|
| 716 | | - goto err_free_abm; |
|---|
| 498 | + goto err_free_act; |
|---|
| 717 | 499 | RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs); |
|---|
| 718 | 500 | |
|---|
| 719 | 501 | reprs = nfp_reprs_alloc(pf->max_data_vnics); |
|---|
| .. | .. |
|---|
| 725 | 507 | |
|---|
| 726 | 508 | err_free_phys: |
|---|
| 727 | 509 | nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); |
|---|
| 510 | +err_free_act: |
|---|
| 511 | + kvfree(abm->actions); |
|---|
| 512 | +err_free_thresh: |
|---|
| 513 | + kvfree(abm->thresholds); |
|---|
| 514 | +err_free_thresh_umap: |
|---|
| 515 | + bitmap_free(abm->threshold_undef); |
|---|
| 728 | 516 | err_free_abm: |
|---|
| 729 | 517 | kfree(abm); |
|---|
| 730 | 518 | app->priv = NULL; |
|---|
| .. | .. |
|---|
| 738 | 526 | nfp_abm_eswitch_clean_up(abm); |
|---|
| 739 | 527 | nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); |
|---|
| 740 | 528 | nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); |
|---|
| 529 | + bitmap_free(abm->threshold_undef); |
|---|
| 530 | + kvfree(abm->actions); |
|---|
| 531 | + kvfree(abm->thresholds); |
|---|
| 741 | 532 | kfree(abm); |
|---|
| 742 | 533 | app->priv = NULL; |
|---|
| 743 | 534 | } |
|---|
| .. | .. |
|---|
| 751 | 542 | |
|---|
| 752 | 543 | .vnic_alloc = nfp_abm_vnic_alloc, |
|---|
| 753 | 544 | .vnic_free = nfp_abm_vnic_free, |
|---|
| 545 | + .vnic_init = nfp_abm_vnic_init, |
|---|
| 754 | 546 | |
|---|
| 755 | 547 | .port_get_stats = nfp_abm_port_get_stats, |
|---|
| 756 | 548 | .port_get_stats_count = nfp_abm_port_get_stats_count, |
|---|
| .. | .. |
|---|
| 761 | 553 | .eswitch_mode_get = nfp_abm_eswitch_mode_get, |
|---|
| 762 | 554 | .eswitch_mode_set = nfp_abm_eswitch_mode_set, |
|---|
| 763 | 555 | |
|---|
| 764 | | - .repr_get = nfp_abm_repr_get, |
|---|
| 556 | + .dev_get = nfp_abm_repr_get, |
|---|
| 765 | 557 | }; |
|---|