1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
2 | /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ |
3 | |
4 | #include <linux/lockdep.h> |
5 | #include <linux/netdevice.h> |
6 | |
7 | #include "nfpcore/nfp_cpp.h" |
8 | #include "nfpcore/nfp_nsp.h" |
9 | #include "nfp_app.h" |
10 | #include "nfp_main.h" |
11 | #include "nfp_net.h" |
12 | #include "nfp_port.h" |
13 | |
14 | struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) |
15 | { |
16 | if (nfp_netdev_is_nfp_net(netdev)) { |
17 | struct nfp_net *nn = netdev_priv(dev: netdev); |
18 | |
19 | return nn->port; |
20 | } |
21 | |
22 | if (nfp_netdev_is_nfp_repr(netdev)) { |
23 | struct nfp_repr *repr = netdev_priv(dev: netdev); |
24 | |
25 | return repr->port; |
26 | } |
27 | |
28 | WARN(1, "Unknown netdev type for nfp_port\n" ); |
29 | |
30 | return NULL; |
31 | } |
32 | |
33 | int nfp_port_get_port_parent_id(struct net_device *netdev, |
34 | struct netdev_phys_item_id *ppid) |
35 | { |
36 | struct nfp_port *port; |
37 | const u8 *serial; |
38 | |
39 | port = nfp_port_from_netdev(netdev); |
40 | if (!port) |
41 | return -EOPNOTSUPP; |
42 | |
43 | ppid->id_len = nfp_cpp_serial(cpp: port->app->cpp, serial: &serial); |
44 | memcpy(&ppid->id, serial, ppid->id_len); |
45 | |
46 | return 0; |
47 | } |
48 | |
49 | int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type, |
50 | void *type_data) |
51 | { |
52 | struct nfp_port *port; |
53 | |
54 | port = nfp_port_from_netdev(netdev); |
55 | if (!port) |
56 | return -EOPNOTSUPP; |
57 | |
58 | return nfp_app_setup_tc(app: port->app, netdev, type, type_data); |
59 | } |
60 | |
61 | int nfp_port_set_features(struct net_device *netdev, netdev_features_t features) |
62 | { |
63 | struct nfp_port *port; |
64 | |
65 | port = nfp_port_from_netdev(netdev); |
66 | if (!port) |
67 | return 0; |
68 | |
69 | if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && |
70 | port->tc_offload_cnt) { |
71 | netdev_err(dev: netdev, format: "Cannot disable HW TC offload while offloads active\n" ); |
72 | return -EBUSY; |
73 | } |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) |
79 | { |
80 | if (!port) |
81 | return NULL; |
82 | if (port->type != NFP_PORT_PHYS_PORT) |
83 | return NULL; |
84 | |
85 | return port->eth_port; |
86 | } |
87 | |
88 | struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port) |
89 | { |
90 | if (!__nfp_port_get_eth_port(port)) |
91 | return NULL; |
92 | |
93 | if (test_bit(NFP_PORT_CHANGED, &port->flags)) |
94 | if (nfp_net_refresh_eth_port(port)) |
95 | return NULL; |
96 | |
97 | return __nfp_port_get_eth_port(port); |
98 | } |
99 | |
100 | int |
101 | nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) |
102 | { |
103 | struct nfp_eth_table_port *eth_port; |
104 | struct nfp_port *port; |
105 | int n; |
106 | |
107 | port = nfp_port_from_netdev(netdev); |
108 | if (!port) |
109 | return -EOPNOTSUPP; |
110 | |
111 | switch (port->type) { |
112 | case NFP_PORT_PHYS_PORT: |
113 | eth_port = __nfp_port_get_eth_port(port); |
114 | if (!eth_port) |
115 | return -EOPNOTSUPP; |
116 | |
117 | if (!eth_port->is_split) |
118 | n = snprintf(buf: name, size: len, fmt: "p%d" , eth_port->label_port); |
119 | else |
120 | n = snprintf(buf: name, size: len, fmt: "p%ds%d" , eth_port->label_port, |
121 | eth_port->label_subport); |
122 | break; |
123 | case NFP_PORT_PF_PORT: |
124 | if (!port->pf_split) |
125 | n = snprintf(buf: name, size: len, fmt: "pf%d" , port->pf_id); |
126 | else |
127 | n = snprintf(buf: name, size: len, fmt: "pf%ds%d" , port->pf_id, |
128 | port->pf_split_id); |
129 | break; |
130 | case NFP_PORT_VF_PORT: |
131 | n = snprintf(buf: name, size: len, fmt: "pf%dvf%d" , port->pf_id, port->vf_id); |
132 | break; |
133 | default: |
134 | return -EOPNOTSUPP; |
135 | } |
136 | |
137 | if (n >= len) |
138 | return -EINVAL; |
139 | |
140 | return 0; |
141 | } |
142 | |
143 | /** |
144 | * nfp_port_configure() - helper to set the interface configured bit |
145 | * @netdev: net_device instance |
146 | * @configed: Desired state |
147 | * |
148 | * Helper to set the ifup/ifdown state on the PHY only if there is a physical |
149 | * interface associated with the netdev. |
150 | * |
151 | * Return: |
152 | * 0 - configuration successful (or no change); |
153 | * -ERRNO - configuration failed. |
154 | */ |
155 | int nfp_port_configure(struct net_device *netdev, bool configed) |
156 | { |
157 | struct nfp_eth_table_port *eth_port; |
158 | struct nfp_port *port; |
159 | int err; |
160 | |
161 | port = nfp_port_from_netdev(netdev); |
162 | eth_port = __nfp_port_get_eth_port(port); |
163 | if (!eth_port) |
164 | return 0; |
165 | if (port->eth_forced) |
166 | return 0; |
167 | |
168 | err = nfp_eth_set_configured(cpp: port->app->cpp, idx: eth_port->index, configed); |
169 | return err < 0 && err != -EOPNOTSUPP ? err : 0; |
170 | } |
171 | |
172 | int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, |
173 | struct nfp_port *port, unsigned int id) |
174 | { |
175 | /* Check if vNIC has external port associated and cfg is OK */ |
176 | if (!pf->eth_tbl || id >= pf->eth_tbl->count) { |
177 | nfp_err(app->cpp, |
178 | "NSP port entries don't match vNICs (no entry %d)\n" , |
179 | id); |
180 | return -EINVAL; |
181 | } |
182 | if (pf->eth_tbl->ports[id].override_changed) { |
183 | nfp_warn(app->cpp, |
184 | "Config changed for port #%d, reboot required before port will be operational\n" , |
185 | pf->eth_tbl->ports[id].index); |
186 | port->type = NFP_PORT_INVALID; |
187 | return 0; |
188 | } |
189 | |
190 | port->eth_port = &pf->eth_tbl->ports[id]; |
191 | port->eth_id = pf->eth_tbl->ports[id].index; |
192 | port->netdev->dev_port = id; |
193 | if (pf->mac_stats_mem) |
194 | port->eth_stats = |
195 | pf->mac_stats_mem + port->eth_id * NFP_MAC_STATS_SIZE; |
196 | |
197 | return 0; |
198 | } |
199 | |
200 | struct nfp_port * |
201 | nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, |
202 | struct net_device *netdev) |
203 | { |
204 | struct nfp_port *port; |
205 | |
206 | port = kzalloc(size: sizeof(*port), GFP_KERNEL); |
207 | if (!port) |
208 | return ERR_PTR(error: -ENOMEM); |
209 | |
210 | port->netdev = netdev; |
211 | port->type = type; |
212 | port->app = app; |
213 | |
214 | list_add_tail(new: &port->port_list, head: &app->pf->ports); |
215 | |
216 | return port; |
217 | } |
218 | |
219 | void nfp_port_free(struct nfp_port *port) |
220 | { |
221 | if (!port) |
222 | return; |
223 | list_del(entry: &port->port_list); |
224 | kfree(objp: port); |
225 | } |
226 | |