Commit | Line | Data |
---|---|---|
96de2506 JK |
1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
2 | /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ | |
7ac9ebd5 | 3 | |
4c7787ba | 4 | #include <linux/bug.h> |
e1740fb6 JK |
5 | #include <linux/lockdep.h> |
6 | #include <linux/rcupdate.h> | |
02082701 | 7 | #include <linux/skbuff.h> |
7ac9ebd5 JK |
8 | #include <linux/slab.h> |
9 | ||
8aa0cb00 | 10 | #include "nfpcore/nfp_cpp.h" |
76abc0f6 | 11 | #include "nfpcore/nfp_nffw.h" |
7ac9ebd5 JK |
12 | #include "nfp_app.h" |
13 | #include "nfp_main.h" | |
9e4c2cfc | 14 | #include "nfp_net.h" |
5de73ee4 | 15 | #include "nfp_net_repr.h" |
21f31bc0 | 16 | #include "nfp_port.h" |
7ac9ebd5 | 17 | |
8aa0cb00 | 18 | static const struct nfp_app_type *apps[] = { |
2c4197a0 | 19 | [NFP_APP_CORE_NIC] = &app_nic, |
43b45245 | 20 | #ifdef CONFIG_BPF_SYSCALL |
2c4197a0 | 21 | [NFP_APP_BPF_NIC] = &app_bpf, |
43b45245 JK |
22 | #else |
23 | [NFP_APP_BPF_NIC] = &app_nic, | |
24 | #endif | |
57ae676e | 25 | #ifdef CONFIG_NFP_APP_FLOWER |
2c4197a0 | 26 | [NFP_APP_FLOWER_NIC] = &app_flower, |
57ae676e | 27 | #endif |
c4c8f39a JK |
28 | #ifdef CONFIG_NFP_APP_ABM_NIC |
29 | [NFP_APP_ACTIVE_BUFFER_MGMT_NIC] = &app_abm, | |
30 | #endif | |
8aa0cb00 JK |
31 | }; |
32 | ||
c01d0efa PJV |
33 | void nfp_check_rhashtable_empty(void *ptr, void *arg) |
34 | { | |
35 | WARN_ON_ONCE(1); | |
36 | } | |
37 | ||
9e4c2cfc JK |
38 | struct nfp_app *nfp_app_from_netdev(struct net_device *netdev) |
39 | { | |
40 | if (nfp_netdev_is_nfp_net(netdev)) { | |
41 | struct nfp_net *nn = netdev_priv(netdev); | |
42 | ||
43 | return nn->app; | |
44 | } | |
45 | ||
46 | if (nfp_netdev_is_nfp_repr(netdev)) { | |
47 | struct nfp_repr *repr = netdev_priv(netdev); | |
48 | ||
49 | return repr->app; | |
50 | } | |
51 | ||
52 | WARN(1, "Unknown netdev type for nfp_app\n"); | |
53 | ||
54 | return NULL; | |
55 | } | |
56 | ||
76abc0f6 JK |
57 | const char *nfp_app_mip_name(struct nfp_app *app) |
58 | { | |
59 | if (!app || !app->pf->mip) | |
60 | return ""; | |
61 | return nfp_mip_name(app->pf->mip); | |
62 | } | |
63 | ||
4612bebf JK |
64 | int nfp_app_ndo_init(struct net_device *netdev) |
65 | { | |
66 | struct nfp_app *app = nfp_app_from_netdev(netdev); | |
67 | ||
68 | if (!app || !app->type->ndo_init) | |
69 | return 0; | |
70 | return app->type->ndo_init(app, netdev); | |
71 | } | |
72 | ||
73 | void nfp_app_ndo_uninit(struct net_device *netdev) | |
74 | { | |
75 | struct nfp_app *app = nfp_app_from_netdev(netdev); | |
76 | ||
77 | if (app && app->type->ndo_uninit) | |
78 | app->type->ndo_uninit(app, netdev); | |
79 | } | |
80 | ||
21f31bc0 JK |
81 | u64 *nfp_app_port_get_stats(struct nfp_port *port, u64 *data) |
82 | { | |
83 | if (!port || !port->app || !port->app->type->port_get_stats) | |
84 | return data; | |
85 | return port->app->type->port_get_stats(port->app, port, data); | |
86 | } | |
87 | ||
88 | int nfp_app_port_get_stats_count(struct nfp_port *port) | |
89 | { | |
90 | if (!port || !port->app || !port->app->type->port_get_stats_count) | |
91 | return 0; | |
92 | return port->app->type->port_get_stats_count(port->app, port); | |
93 | } | |
94 | ||
95 | u8 *nfp_app_port_get_stats_strings(struct nfp_port *port, u8 *data) | |
96 | { | |
97 | if (!port || !port->app || !port->app->type->port_get_stats_strings) | |
98 | return data; | |
99 | return port->app->type->port_get_stats_strings(port->app, port, data); | |
100 | } | |
101 | ||
948faa46 SH |
102 | struct sk_buff * |
103 | nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size, gfp_t priority) | |
02082701 JK |
104 | { |
105 | struct sk_buff *skb; | |
106 | ||
107 | if (nfp_app_ctrl_has_meta(app)) | |
108 | size += 8; | |
109 | ||
948faa46 | 110 | skb = alloc_skb(size, priority); |
02082701 JK |
111 | if (!skb) |
112 | return NULL; | |
113 | ||
114 | if (nfp_app_ctrl_has_meta(app)) | |
115 | skb_reserve(skb, 8); | |
116 | ||
117 | return skb; | |
118 | } | |
119 | ||
e1740fb6 JK |
120 | struct nfp_reprs * |
121 | nfp_reprs_get_locked(struct nfp_app *app, enum nfp_repr_type type) | |
122 | { | |
123 | return rcu_dereference_protected(app->reprs[type], | |
8a38f2cc | 124 | nfp_app_is_locked(app)); |
e1740fb6 JK |
125 | } |
126 | ||
5de73ee4 SH |
127 | struct nfp_reprs * |
128 | nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type, | |
129 | struct nfp_reprs *reprs) | |
130 | { | |
131 | struct nfp_reprs *old; | |
132 | ||
e1740fb6 | 133 | old = nfp_reprs_get_locked(app, type); |
71844fac | 134 | rtnl_lock(); |
5de73ee4 | 135 | rcu_assign_pointer(app->reprs[type], reprs); |
71844fac | 136 | rtnl_unlock(); |
5de73ee4 | 137 | |
5de73ee4 SH |
138 | return old; |
139 | } | |
140 | ||
51a6588e JK |
141 | static void |
142 | nfp_app_netdev_feat_change(struct nfp_app *app, struct net_device *netdev) | |
143 | { | |
144 | struct nfp_net *nn; | |
145 | unsigned int type; | |
146 | ||
147 | if (!nfp_netdev_is_nfp_net(netdev)) | |
148 | return; | |
149 | nn = netdev_priv(netdev); | |
150 | if (nn->app != app) | |
151 | return; | |
152 | ||
153 | for (type = 0; type < __NFP_REPR_TYPE_MAX; type++) { | |
154 | struct nfp_reprs *reprs; | |
155 | unsigned int i; | |
156 | ||
157 | reprs = rtnl_dereference(app->reprs[type]); | |
158 | if (!reprs) | |
159 | continue; | |
160 | ||
161 | for (i = 0; i < reprs->num_reprs; i++) { | |
162 | struct net_device *repr; | |
163 | ||
164 | repr = rtnl_dereference(reprs->reprs[i]); | |
165 | if (!repr) | |
166 | continue; | |
167 | ||
168 | nfp_repr_transfer_features(repr, netdev); | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
3e333590 JK |
173 | static int |
174 | nfp_app_netdev_event(struct notifier_block *nb, unsigned long event, void *ptr) | |
175 | { | |
176 | struct net_device *netdev; | |
177 | struct nfp_app *app; | |
178 | ||
179 | netdev = netdev_notifier_info_to_dev(ptr); | |
180 | app = container_of(nb, struct nfp_app, netdev_nb); | |
181 | ||
51a6588e JK |
182 | /* Handle events common code is interested in */ |
183 | switch (event) { | |
184 | case NETDEV_FEAT_CHANGE: | |
185 | nfp_app_netdev_feat_change(app, netdev); | |
186 | break; | |
187 | } | |
188 | ||
189 | /* Call offload specific handlers */ | |
3e333590 JK |
190 | if (app->type->netdev_event) |
191 | return app->type->netdev_event(app, netdev, event, ptr); | |
192 | return NOTIFY_DONE; | |
193 | } | |
194 | ||
195 | int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl) | |
196 | { | |
197 | int err; | |
198 | ||
199 | app->ctrl = ctrl; | |
200 | ||
201 | if (app->type->start) { | |
202 | err = app->type->start(app); | |
203 | if (err) | |
204 | return err; | |
205 | } | |
206 | ||
207 | app->netdev_nb.notifier_call = nfp_app_netdev_event; | |
208 | err = register_netdevice_notifier(&app->netdev_nb); | |
209 | if (err) | |
210 | goto err_app_stop; | |
211 | ||
212 | return 0; | |
213 | ||
214 | err_app_stop: | |
215 | if (app->type->stop) | |
216 | app->type->stop(app); | |
217 | return err; | |
218 | } | |
219 | ||
220 | void nfp_app_stop(struct nfp_app *app) | |
221 | { | |
222 | unregister_netdevice_notifier(&app->netdev_nb); | |
223 | ||
224 | if (app->type->stop) | |
225 | app->type->stop(app); | |
226 | } | |
227 | ||
8aa0cb00 | 228 | struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) |
7ac9ebd5 JK |
229 | { |
230 | struct nfp_app *app; | |
8aa0cb00 | 231 | |
2c4197a0 | 232 | if (id >= ARRAY_SIZE(apps) || !apps[id]) { |
ef2a95db | 233 | nfp_err(pf->cpp, "unknown FW app ID 0x%02x, driver too old or support for FW not built in\n", id); |
8aa0cb00 JK |
234 | return ERR_PTR(-EINVAL); |
235 | } | |
236 | ||
2c4197a0 | 237 | if (WARN_ON(!apps[id]->name || !apps[id]->vnic_alloc)) |
8aa0cb00 | 238 | return ERR_PTR(-EINVAL); |
79ca38e8 JK |
239 | if (WARN_ON(!apps[id]->ctrl_msg_rx && apps[id]->ctrl_msg_rx_raw)) |
240 | return ERR_PTR(-EINVAL); | |
7ac9ebd5 JK |
241 | |
242 | app = kzalloc(sizeof(*app), GFP_KERNEL); | |
243 | if (!app) | |
244 | return ERR_PTR(-ENOMEM); | |
245 | ||
246 | app->pf = pf; | |
247 | app->cpp = pf->cpp; | |
248 | app->pdev = pf->pdev; | |
2c4197a0 | 249 | app->type = apps[id]; |
7ac9ebd5 JK |
250 | |
251 | return app; | |
252 | } | |
253 | ||
254 | void nfp_app_free(struct nfp_app *app) | |
255 | { | |
256 | kfree(app); | |
257 | } |