.. | .. |
---|
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 | }; |
---|