]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
nfp: turn NSP port entry into a union
[mirror_ubuntu-artful-kernel.git] / drivers / net / ethernet / netronome / nfp / nfpcore / nfp_nsp_eth.c
1 /*
2 * Copyright (C) 2015-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 */
33
34 /* Authors: David Brunecz <david.brunecz@netronome.com>
35 * Jakub Kicinski <jakub.kicinski@netronome.com>
36 * Jason Mcmullan <jason.mcmullan@netronome.com>
37 */
38
39 #include <linux/bitfield.h>
40 #include <linux/ethtool.h>
41 #include <linux/if_ether.h>
42 #include <linux/kernel.h>
43 #include <linux/module.h>
44
45 #include "nfp.h"
46 #include "nfp_nsp.h"
47 #include "nfp6000/nfp6000.h"
48
49 #define NSP_ETH_NBI_PORT_COUNT 24
50 #define NSP_ETH_MAX_COUNT (2 * NSP_ETH_NBI_PORT_COUNT)
51 #define NSP_ETH_TABLE_SIZE (NSP_ETH_MAX_COUNT * \
52 sizeof(union eth_table_entry))
53
54 #define NSP_ETH_PORT_LANES GENMASK_ULL(3, 0)
55 #define NSP_ETH_PORT_INDEX GENMASK_ULL(15, 8)
56 #define NSP_ETH_PORT_LABEL GENMASK_ULL(53, 48)
57 #define NSP_ETH_PORT_PHYLABEL GENMASK_ULL(59, 54)
58
59 #define NSP_ETH_PORT_LANES_MASK cpu_to_le64(NSP_ETH_PORT_LANES)
60
61 #define NSP_ETH_STATE_ENABLED BIT_ULL(1)
62 #define NSP_ETH_STATE_TX_ENABLED BIT_ULL(2)
63 #define NSP_ETH_STATE_RX_ENABLED BIT_ULL(3)
64 #define NSP_ETH_STATE_RATE GENMASK_ULL(11, 8)
65 #define NSP_ETH_STATE_INTERFACE GENMASK_ULL(19, 12)
66 #define NSP_ETH_STATE_MEDIA GENMASK_ULL(21, 20)
67 #define NSP_ETH_STATE_OVRD_CHNG BIT_ULL(22)
68 #define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23)
69
70 #define NSP_ETH_CTRL_ENABLED BIT_ULL(1)
71 #define NSP_ETH_CTRL_TX_ENABLED BIT_ULL(2)
72 #define NSP_ETH_CTRL_RX_ENABLED BIT_ULL(3)
73
74 enum nfp_eth_raw {
75 NSP_ETH_RAW_PORT = 0,
76 NSP_ETH_RAW_STATE,
77 NSP_ETH_RAW_MAC,
78 NSP_ETH_RAW_CONTROL,
79
80 NSP_ETH_NUM_RAW
81 };
82
83 enum nfp_eth_rate {
84 RATE_INVALID = 0,
85 RATE_10M,
86 RATE_100M,
87 RATE_1G,
88 RATE_10G,
89 RATE_25G,
90 };
91
92 union eth_table_entry {
93 struct {
94 __le64 port;
95 __le64 state;
96 u8 mac_addr[6];
97 u8 resv[2];
98 __le64 control;
99 };
100 __le64 raw[NSP_ETH_NUM_RAW];
101 };
102
103 static unsigned int nfp_eth_rate(enum nfp_eth_rate rate)
104 {
105 unsigned int rate_xlate[] = {
106 [RATE_INVALID] = 0,
107 [RATE_10M] = SPEED_10,
108 [RATE_100M] = SPEED_100,
109 [RATE_1G] = SPEED_1000,
110 [RATE_10G] = SPEED_10000,
111 [RATE_25G] = SPEED_25000,
112 };
113
114 if (rate >= ARRAY_SIZE(rate_xlate))
115 return 0;
116
117 return rate_xlate[rate];
118 }
119
120 static void nfp_eth_copy_mac_reverse(u8 *dst, const u8 *src)
121 {
122 int i;
123
124 for (i = 0; i < ETH_ALEN; i++)
125 dst[ETH_ALEN - i - 1] = src[i];
126 }
127
128 static void
129 nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
130 unsigned int index, struct nfp_eth_table_port *dst)
131 {
132 unsigned int rate;
133 u64 port, state;
134
135 port = le64_to_cpu(src->port);
136 state = le64_to_cpu(src->state);
137
138 dst->eth_index = FIELD_GET(NSP_ETH_PORT_INDEX, port);
139 dst->index = index;
140 dst->nbi = index / NSP_ETH_NBI_PORT_COUNT;
141 dst->base = index % NSP_ETH_NBI_PORT_COUNT;
142 dst->lanes = FIELD_GET(NSP_ETH_PORT_LANES, port);
143
144 dst->enabled = FIELD_GET(NSP_ETH_STATE_ENABLED, state);
145 dst->tx_enabled = FIELD_GET(NSP_ETH_STATE_TX_ENABLED, state);
146 dst->rx_enabled = FIELD_GET(NSP_ETH_STATE_RX_ENABLED, state);
147
148 rate = nfp_eth_rate(FIELD_GET(NSP_ETH_STATE_RATE, state));
149 dst->speed = dst->lanes * rate;
150
151 dst->interface = FIELD_GET(NSP_ETH_STATE_INTERFACE, state);
152 dst->media = FIELD_GET(NSP_ETH_STATE_MEDIA, state);
153
154 nfp_eth_copy_mac_reverse(dst->mac_addr, src->mac_addr);
155
156 dst->label_port = FIELD_GET(NSP_ETH_PORT_PHYLABEL, port);
157 dst->label_subport = FIELD_GET(NSP_ETH_PORT_LABEL, port);
158
159 if (nfp_nsp_get_abi_ver_minor(nsp) < 17)
160 return;
161
162 dst->override_changed = FIELD_GET(NSP_ETH_STATE_OVRD_CHNG, state);
163 dst->aneg = FIELD_GET(NSP_ETH_STATE_ANEG, state);
164 }
165
166 static void
167 nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table)
168 {
169 unsigned int i, j;
170
171 for (i = 0; i < table->count; i++)
172 for (j = 0; j < table->count; j++) {
173 if (i == j)
174 continue;
175 if (table->ports[i].label_port !=
176 table->ports[j].label_port)
177 continue;
178 if (table->ports[i].label_subport ==
179 table->ports[j].label_subport)
180 nfp_warn(cpp,
181 "Port %d subport %d is a duplicate\n",
182 table->ports[i].label_port,
183 table->ports[i].label_subport);
184
185 table->ports[i].is_split = true;
186 break;
187 }
188 }
189
190 static void
191 nfp_eth_calc_port_type(struct nfp_cpp *cpp, struct nfp_eth_table_port *entry)
192 {
193 if (entry->interface == NFP_INTERFACE_NONE) {
194 entry->port_type = PORT_NONE;
195 return;
196 }
197
198 if (entry->media == NFP_MEDIA_FIBRE)
199 entry->port_type = PORT_FIBRE;
200 else
201 entry->port_type = PORT_DA;
202 }
203
204 /**
205 * nfp_eth_read_ports() - retrieve port information
206 * @cpp: NFP CPP handle
207 *
208 * Read the port information from the device. Returned structure should
209 * be freed with kfree() once no longer needed.
210 *
211 * Return: populated ETH table or NULL on error.
212 */
213 struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp)
214 {
215 struct nfp_eth_table *ret;
216 struct nfp_nsp *nsp;
217
218 nsp = nfp_nsp_open(cpp);
219 if (IS_ERR(nsp))
220 return NULL;
221
222 ret = __nfp_eth_read_ports(cpp, nsp);
223 nfp_nsp_close(nsp);
224
225 return ret;
226 }
227
228 struct nfp_eth_table *
229 __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp)
230 {
231 union eth_table_entry *entries;
232 struct nfp_eth_table *table;
233 int i, j, ret, cnt = 0;
234
235 entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
236 if (!entries)
237 return NULL;
238
239 ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
240 if (ret < 0) {
241 nfp_err(cpp, "reading port table failed %d\n", ret);
242 goto err;
243 }
244
245 for (i = 0; i < NSP_ETH_MAX_COUNT; i++)
246 if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
247 cnt++;
248
249 /* Some versions of flash will give us 0 instead of port count.
250 * For those that give a port count, verify it against the value
251 * calculated above.
252 */
253 if (ret && ret != cnt) {
254 nfp_err(cpp, "table entry count reported (%d) does not match entries present (%d)\n",
255 ret, cnt);
256 goto err;
257 }
258
259 table = kzalloc(sizeof(*table) +
260 sizeof(struct nfp_eth_table_port) * cnt, GFP_KERNEL);
261 if (!table)
262 goto err;
263
264 table->count = cnt;
265 for (i = 0, j = 0; i < NSP_ETH_MAX_COUNT; i++)
266 if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
267 nfp_eth_port_translate(nsp, &entries[i], i,
268 &table->ports[j++]);
269
270 nfp_eth_mark_split_ports(cpp, table);
271 for (i = 0; i < table->count; i++)
272 nfp_eth_calc_port_type(cpp, &table->ports[i]);
273
274 kfree(entries);
275
276 return table;
277
278 err:
279 kfree(entries);
280 return NULL;
281 }
282
283 struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx)
284 {
285 union eth_table_entry *entries;
286 struct nfp_nsp *nsp;
287 int ret;
288
289 entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
290 if (!entries)
291 return ERR_PTR(-ENOMEM);
292
293 nsp = nfp_nsp_open(cpp);
294 if (IS_ERR(nsp)) {
295 kfree(entries);
296 return nsp;
297 }
298
299 ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
300 if (ret < 0) {
301 nfp_err(cpp, "reading port table failed %d\n", ret);
302 goto err;
303 }
304
305 if (!(entries[idx].port & NSP_ETH_PORT_LANES_MASK)) {
306 nfp_warn(cpp, "trying to set port state on disabled port %d\n",
307 idx);
308 goto err;
309 }
310
311 nfp_nsp_config_set_state(nsp, entries, idx);
312 return nsp;
313
314 err:
315 nfp_nsp_close(nsp);
316 kfree(entries);
317 return ERR_PTR(-EIO);
318 }
319
320 void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp)
321 {
322 union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
323
324 nfp_nsp_config_set_modified(nsp, false);
325 nfp_nsp_config_clear_state(nsp);
326 nfp_nsp_close(nsp);
327 kfree(entries);
328 }
329
330 /**
331 * nfp_eth_config_commit_end() - perform recorded configuration changes
332 * @nsp: NFP NSP handle returned from nfp_eth_config_start()
333 *
334 * Perform the configuration which was requested with __nfp_eth_set_*()
335 * helpers and recorded in @nsp state. If device was already configured
336 * as requested or no __nfp_eth_set_*() operations were made no NSP command
337 * will be performed.
338 *
339 * Return:
340 * 0 - configuration successful;
341 * 1 - no changes were needed;
342 * -ERRNO - configuration failed.
343 */
344 int nfp_eth_config_commit_end(struct nfp_nsp *nsp)
345 {
346 union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
347 int ret = 1;
348
349 if (nfp_nsp_config_modified(nsp)) {
350 ret = nfp_nsp_write_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
351 ret = ret < 0 ? ret : 0;
352 }
353
354 nfp_eth_config_cleanup_end(nsp);
355
356 return ret;
357 }
358
359 /**
360 * nfp_eth_set_mod_enable() - set PHY module enable control bit
361 * @cpp: NFP CPP handle
362 * @idx: NFP chip-wide port index
363 * @enable: Desired state
364 *
365 * Enable or disable PHY module (this usually means setting the TX lanes
366 * disable bits).
367 *
368 * Return: 0 or -ERRNO.
369 */
370 int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
371 {
372 union eth_table_entry *entries;
373 struct nfp_nsp *nsp;
374 u64 reg;
375
376 nsp = nfp_eth_config_start(cpp, idx);
377 if (IS_ERR(nsp))
378 return PTR_ERR(nsp);
379
380 entries = nfp_nsp_config_entries(nsp);
381
382 /* Check if we are already in requested state */
383 reg = le64_to_cpu(entries[idx].state);
384 if (enable != FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) {
385 reg = le64_to_cpu(entries[idx].control);
386 reg &= ~NSP_ETH_CTRL_ENABLED;
387 reg |= FIELD_PREP(NSP_ETH_CTRL_ENABLED, enable);
388 entries[idx].control = cpu_to_le64(reg);
389
390 nfp_nsp_config_set_modified(nsp, true);
391 }
392
393 return nfp_eth_config_commit_end(nsp);
394 }