.. | .. |
---|
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 | | - */ |
---|
| 1 | +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
---|
| 2 | +/* Copyright (C) 2015-2018 Netronome Systems, Inc. */ |
---|
33 | 3 | |
---|
34 | 4 | /* |
---|
35 | 5 | * nfp_nsp.c |
---|
.. | .. |
---|
37 | 7 | * Jason McMullan <jason.mcmullan@netronome.com> |
---|
38 | 8 | */ |
---|
39 | 9 | |
---|
| 10 | +#include <asm/unaligned.h> |
---|
40 | 11 | #include <linux/bitfield.h> |
---|
41 | 12 | #include <linux/delay.h> |
---|
42 | 13 | #include <linux/firmware.h> |
---|
43 | 14 | #include <linux/kernel.h> |
---|
44 | 15 | #include <linux/kthread.h> |
---|
| 16 | +#include <linux/overflow.h> |
---|
45 | 17 | #include <linux/sizes.h> |
---|
46 | 18 | #include <linux/slab.h> |
---|
47 | 19 | |
---|
.. | .. |
---|
66 | 38 | #define NSP_COMMAND 0x08 |
---|
67 | 39 | #define NSP_COMMAND_OPTION GENMASK_ULL(63, 32) |
---|
68 | 40 | #define NSP_COMMAND_CODE GENMASK_ULL(31, 16) |
---|
| 41 | +#define NSP_COMMAND_DMA_BUF BIT_ULL(1) |
---|
69 | 42 | #define NSP_COMMAND_START BIT_ULL(0) |
---|
70 | 43 | |
---|
71 | 44 | /* CPP address to retrieve the data from */ |
---|
.. | .. |
---|
78 | 51 | #define NSP_DFLT_BUFFER_ADDRESS GENMASK_ULL(39, 0) |
---|
79 | 52 | |
---|
80 | 53 | #define NSP_DFLT_BUFFER_CONFIG 0x20 |
---|
| 54 | +#define NSP_DFLT_BUFFER_DMA_CHUNK_ORDER GENMASK_ULL(63, 58) |
---|
| 55 | +#define NSP_DFLT_BUFFER_SIZE_4KB GENMASK_ULL(15, 8) |
---|
81 | 56 | #define NSP_DFLT_BUFFER_SIZE_MB GENMASK_ULL(7, 0) |
---|
| 57 | + |
---|
| 58 | +#define NFP_CAP_CMD_DMA_SG 0x28 |
---|
82 | 59 | |
---|
83 | 60 | #define NSP_MAGIC 0xab10 |
---|
84 | 61 | #define NSP_MAJOR 0 |
---|
.. | .. |
---|
86 | 63 | |
---|
87 | 64 | #define NSP_CODE_MAJOR GENMASK(15, 12) |
---|
88 | 65 | #define NSP_CODE_MINOR GENMASK(11, 0) |
---|
| 66 | + |
---|
| 67 | +#define NFP_FW_LOAD_RET_MAJOR GENMASK(15, 8) |
---|
| 68 | +#define NFP_FW_LOAD_RET_MINOR GENMASK(23, 16) |
---|
| 69 | + |
---|
| 70 | +#define NFP_HWINFO_LOOKUP_SIZE GENMASK(11, 0) |
---|
| 71 | + |
---|
| 72 | +#define NFP_VERSIONS_SIZE GENMASK(11, 0) |
---|
| 73 | +#define NFP_VERSIONS_CNT_OFF 0 |
---|
| 74 | +#define NFP_VERSIONS_BSP_OFF 2 |
---|
| 75 | +#define NFP_VERSIONS_CPLD_OFF 6 |
---|
| 76 | +#define NFP_VERSIONS_APP_OFF 10 |
---|
| 77 | +#define NFP_VERSIONS_BUNDLE_OFF 14 |
---|
| 78 | +#define NFP_VERSIONS_UNDI_OFF 18 |
---|
| 79 | +#define NFP_VERSIONS_NCSI_OFF 22 |
---|
| 80 | +#define NFP_VERSIONS_CFGR_OFF 26 |
---|
| 81 | + |
---|
| 82 | +#define NSP_SFF_EEPROM_BLOCK_LEN 8 |
---|
89 | 83 | |
---|
90 | 84 | enum nfp_nsp_cmd { |
---|
91 | 85 | SPCODE_NOOP = 0, /* No operation */ |
---|
.. | .. |
---|
100 | 94 | SPCODE_NSP_WRITE_FLASH = 11, /* Load and flash image from buffer */ |
---|
101 | 95 | SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */ |
---|
102 | 96 | SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */ |
---|
| 97 | + SPCODE_FW_STORED = 16, /* If no FW loaded, load flash app FW */ |
---|
| 98 | + SPCODE_HWINFO_LOOKUP = 17, /* Lookup HWinfo with overwrites etc. */ |
---|
| 99 | + SPCODE_HWINFO_SET = 18, /* Set HWinfo entry */ |
---|
| 100 | + SPCODE_FW_LOADED = 19, /* Is application firmware loaded */ |
---|
| 101 | + SPCODE_VERSIONS = 21, /* Report FW versions */ |
---|
| 102 | + SPCODE_READ_SFF_EEPROM = 22, /* Read module EEPROM */ |
---|
| 103 | +}; |
---|
| 104 | + |
---|
| 105 | +struct nfp_nsp_dma_buf { |
---|
| 106 | + __le32 chunk_cnt; |
---|
| 107 | + __le32 reserved[3]; |
---|
| 108 | + struct { |
---|
| 109 | + __le32 size; |
---|
| 110 | + __le32 reserved; |
---|
| 111 | + __le64 addr; |
---|
| 112 | + } descs[]; |
---|
103 | 113 | }; |
---|
104 | 114 | |
---|
105 | 115 | static const struct { |
---|
.. | .. |
---|
125 | 135 | bool modified; |
---|
126 | 136 | unsigned int idx; |
---|
127 | 137 | void *entries; |
---|
| 138 | +}; |
---|
| 139 | + |
---|
| 140 | +/** |
---|
| 141 | + * struct nfp_nsp_command_arg - NFP command argument structure |
---|
| 142 | + * @code: NFP SP Command Code |
---|
| 143 | + * @dma: @buf points to a host buffer, not NSP buffer |
---|
| 144 | + * @timeout_sec:Timeout value to wait for completion in seconds |
---|
| 145 | + * @option: NFP SP Command Argument |
---|
| 146 | + * @buf: NFP SP Buffer Address |
---|
| 147 | + * @error_cb: Callback for interpreting option if error occurred |
---|
| 148 | + * @error_quiet:Don't print command error/warning. Protocol errors are still |
---|
| 149 | + * logged. |
---|
| 150 | + */ |
---|
| 151 | +struct nfp_nsp_command_arg { |
---|
| 152 | + u16 code; |
---|
| 153 | + bool dma; |
---|
| 154 | + unsigned int timeout_sec; |
---|
| 155 | + u32 option; |
---|
| 156 | + u64 buf; |
---|
| 157 | + void (*error_cb)(struct nfp_nsp *state, u32 ret_val); |
---|
| 158 | + bool error_quiet; |
---|
| 159 | +}; |
---|
| 160 | + |
---|
| 161 | +/** |
---|
| 162 | + * struct nfp_nsp_command_buf_arg - NFP command with buffer argument structure |
---|
| 163 | + * @arg: NFP command argument structure |
---|
| 164 | + * @in_buf: Buffer with data for input |
---|
| 165 | + * @in_size: Size of @in_buf |
---|
| 166 | + * @out_buf: Buffer for output data |
---|
| 167 | + * @out_size: Size of @out_buf |
---|
| 168 | + */ |
---|
| 169 | +struct nfp_nsp_command_buf_arg { |
---|
| 170 | + struct nfp_nsp_command_arg arg; |
---|
| 171 | + const void *in_buf; |
---|
| 172 | + unsigned int in_size; |
---|
| 173 | + void *out_buf; |
---|
| 174 | + unsigned int out_size; |
---|
128 | 175 | }; |
---|
129 | 176 | |
---|
130 | 177 | struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state) |
---|
.. | .. |
---|
199 | 246 | state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg); |
---|
200 | 247 | state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg); |
---|
201 | 248 | |
---|
202 | | - if (state->ver.major != NSP_MAJOR || state->ver.minor < NSP_MINOR) { |
---|
| 249 | + if (state->ver.major != NSP_MAJOR) { |
---|
203 | 250 | nfp_err(cpp, "Unsupported ABI %hu.%hu\n", |
---|
204 | 251 | state->ver.major, state->ver.minor); |
---|
| 252 | + return -EINVAL; |
---|
| 253 | + } |
---|
| 254 | + if (state->ver.minor < NSP_MINOR) { |
---|
| 255 | + nfp_err(cpp, "ABI too old to support NIC operation (%u.%hu < %u.%u), please update the management FW on the flash\n", |
---|
| 256 | + NSP_MAJOR, state->ver.minor, NSP_MAJOR, NSP_MINOR); |
---|
205 | 257 | return -EINVAL; |
---|
206 | 258 | } |
---|
207 | 259 | |
---|
.. | .. |
---|
291 | 343 | /** |
---|
292 | 344 | * __nfp_nsp_command() - Execute a command on the NFP Service Processor |
---|
293 | 345 | * @state: NFP SP state |
---|
294 | | - * @code: NFP SP Command Code |
---|
295 | | - * @option: NFP SP Command Argument |
---|
296 | | - * @buff_cpp: NFP SP Buffer CPP Address info |
---|
297 | | - * @buff_addr: NFP SP Buffer Host address |
---|
298 | | - * @timeout_sec:Timeout value to wait for completion in seconds |
---|
| 346 | + * @arg: NFP command argument structure |
---|
299 | 347 | * |
---|
300 | 348 | * Return: 0 for success with no result |
---|
301 | 349 | * |
---|
.. | .. |
---|
308 | 356 | * -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete |
---|
309 | 357 | */ |
---|
310 | 358 | static int |
---|
311 | | -__nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, |
---|
312 | | - u64 buff_addr, u32 timeout_sec) |
---|
| 359 | +__nfp_nsp_command(struct nfp_nsp *state, const struct nfp_nsp_command_arg *arg) |
---|
313 | 360 | { |
---|
314 | 361 | u64 reg, ret_val, nsp_base, nsp_buffer, nsp_status, nsp_command; |
---|
315 | 362 | struct nfp_cpp *cpp = state->cpp; |
---|
.. | .. |
---|
326 | 373 | if (err) |
---|
327 | 374 | return err; |
---|
328 | 375 | |
---|
329 | | - if (!FIELD_FIT(NSP_BUFFER_CPP, buff_cpp >> 8) || |
---|
330 | | - !FIELD_FIT(NSP_BUFFER_ADDRESS, buff_addr)) { |
---|
331 | | - nfp_err(cpp, "Host buffer out of reach %08x %016llx\n", |
---|
332 | | - buff_cpp, buff_addr); |
---|
333 | | - return -EINVAL; |
---|
334 | | - } |
---|
335 | | - |
---|
336 | | - err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, |
---|
337 | | - FIELD_PREP(NSP_BUFFER_CPP, buff_cpp >> 8) | |
---|
338 | | - FIELD_PREP(NSP_BUFFER_ADDRESS, buff_addr)); |
---|
| 376 | + err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, arg->buf); |
---|
339 | 377 | if (err < 0) |
---|
340 | 378 | return err; |
---|
341 | 379 | |
---|
342 | 380 | err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command, |
---|
343 | | - FIELD_PREP(NSP_COMMAND_OPTION, option) | |
---|
344 | | - FIELD_PREP(NSP_COMMAND_CODE, code) | |
---|
| 381 | + FIELD_PREP(NSP_COMMAND_OPTION, arg->option) | |
---|
| 382 | + FIELD_PREP(NSP_COMMAND_CODE, arg->code) | |
---|
| 383 | + FIELD_PREP(NSP_COMMAND_DMA_BUF, arg->dma) | |
---|
345 | 384 | FIELD_PREP(NSP_COMMAND_START, 1)); |
---|
346 | 385 | if (err < 0) |
---|
347 | 386 | return err; |
---|
.. | .. |
---|
351 | 390 | NSP_COMMAND_START, 0, NFP_NSP_TIMEOUT_DEFAULT); |
---|
352 | 391 | if (err) { |
---|
353 | 392 | nfp_err(cpp, "Error %d waiting for code 0x%04x to start\n", |
---|
354 | | - err, code); |
---|
| 393 | + err, arg->code); |
---|
355 | 394 | return err; |
---|
356 | 395 | } |
---|
357 | 396 | |
---|
358 | 397 | /* Wait for NSP_STATUS_BUSY to go to 0 */ |
---|
359 | 398 | err = nfp_nsp_wait_reg(cpp, ®, nsp_cpp, nsp_status, NSP_STATUS_BUSY, |
---|
360 | | - 0, timeout_sec); |
---|
| 399 | + 0, arg->timeout_sec ?: NFP_NSP_TIMEOUT_DEFAULT); |
---|
361 | 400 | if (err) { |
---|
362 | 401 | nfp_err(cpp, "Error %d waiting for code 0x%04x to complete\n", |
---|
363 | | - err, code); |
---|
| 402 | + err, arg->code); |
---|
364 | 403 | return err; |
---|
365 | 404 | } |
---|
366 | 405 | |
---|
.. | .. |
---|
371 | 410 | |
---|
372 | 411 | err = FIELD_GET(NSP_STATUS_RESULT, reg); |
---|
373 | 412 | if (err) { |
---|
374 | | - nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n", |
---|
375 | | - -err, (int)ret_val, code); |
---|
376 | | - nfp_nsp_print_extended_error(state, ret_val); |
---|
| 413 | + if (!arg->error_quiet) |
---|
| 414 | + nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n", |
---|
| 415 | + -err, (int)ret_val, arg->code); |
---|
| 416 | + |
---|
| 417 | + if (arg->error_cb) |
---|
| 418 | + arg->error_cb(state, ret_val); |
---|
| 419 | + else |
---|
| 420 | + nfp_nsp_print_extended_error(state, ret_val); |
---|
377 | 421 | return -err; |
---|
378 | 422 | } |
---|
379 | 423 | |
---|
380 | 424 | return ret_val; |
---|
381 | 425 | } |
---|
382 | 426 | |
---|
383 | | -static int |
---|
384 | | -nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp, |
---|
385 | | - u64 buff_addr) |
---|
| 427 | +static int nfp_nsp_command(struct nfp_nsp *state, u16 code) |
---|
386 | 428 | { |
---|
387 | | - return __nfp_nsp_command(state, code, option, buff_cpp, buff_addr, |
---|
388 | | - NFP_NSP_TIMEOUT_DEFAULT); |
---|
| 429 | + const struct nfp_nsp_command_arg arg = { |
---|
| 430 | + .code = code, |
---|
| 431 | + }; |
---|
| 432 | + |
---|
| 433 | + return __nfp_nsp_command(state, &arg); |
---|
389 | 434 | } |
---|
390 | 435 | |
---|
391 | 436 | static int |
---|
392 | | -__nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, |
---|
393 | | - const void *in_buf, unsigned int in_size, void *out_buf, |
---|
394 | | - unsigned int out_size, u32 timeout_sec) |
---|
| 437 | +nfp_nsp_command_buf_def(struct nfp_nsp *nsp, |
---|
| 438 | + struct nfp_nsp_command_buf_arg *arg) |
---|
395 | 439 | { |
---|
396 | 440 | struct nfp_cpp *cpp = nsp->cpp; |
---|
397 | | - unsigned int max_size; |
---|
398 | 441 | u64 reg, cpp_buf; |
---|
399 | | - int ret, err; |
---|
| 442 | + int err, ret; |
---|
400 | 443 | u32 cpp_id; |
---|
401 | | - |
---|
402 | | - if (nsp->ver.minor < 13) { |
---|
403 | | - nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %hu.%hu)\n", |
---|
404 | | - code, nsp->ver.major, nsp->ver.minor); |
---|
405 | | - return -EOPNOTSUPP; |
---|
406 | | - } |
---|
407 | | - |
---|
408 | | - err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res), |
---|
409 | | - nfp_resource_address(nsp->res) + |
---|
410 | | - NSP_DFLT_BUFFER_CONFIG, |
---|
411 | | - ®); |
---|
412 | | - if (err < 0) |
---|
413 | | - return err; |
---|
414 | | - |
---|
415 | | - max_size = max(in_size, out_size); |
---|
416 | | - if (FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M < max_size) { |
---|
417 | | - nfp_err(cpp, "NSP: default buffer too small for command 0x%04x (%llu < %u)\n", |
---|
418 | | - code, FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M, |
---|
419 | | - max_size); |
---|
420 | | - return -EINVAL; |
---|
421 | | - } |
---|
422 | 444 | |
---|
423 | 445 | err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res), |
---|
424 | 446 | nfp_resource_address(nsp->res) + |
---|
.. | .. |
---|
430 | 452 | cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8; |
---|
431 | 453 | cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg); |
---|
432 | 454 | |
---|
433 | | - if (in_buf && in_size) { |
---|
434 | | - err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size); |
---|
| 455 | + if (arg->in_buf && arg->in_size) { |
---|
| 456 | + err = nfp_cpp_write(cpp, cpp_id, cpp_buf, |
---|
| 457 | + arg->in_buf, arg->in_size); |
---|
435 | 458 | if (err < 0) |
---|
436 | 459 | return err; |
---|
437 | 460 | } |
---|
438 | 461 | /* Zero out remaining part of the buffer */ |
---|
439 | | - if (out_buf && out_size && out_size > in_size) { |
---|
440 | | - memset(out_buf, 0, out_size - in_size); |
---|
441 | | - err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size, |
---|
442 | | - out_buf, out_size - in_size); |
---|
| 462 | + if (arg->out_buf && arg->out_size && arg->out_size > arg->in_size) { |
---|
| 463 | + err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size, |
---|
| 464 | + arg->out_buf, arg->out_size - arg->in_size); |
---|
443 | 465 | if (err < 0) |
---|
444 | 466 | return err; |
---|
445 | 467 | } |
---|
446 | 468 | |
---|
447 | | - ret = __nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf, |
---|
448 | | - timeout_sec); |
---|
| 469 | + if (!FIELD_FIT(NSP_BUFFER_CPP, cpp_id >> 8) || |
---|
| 470 | + !FIELD_FIT(NSP_BUFFER_ADDRESS, cpp_buf)) { |
---|
| 471 | + nfp_err(cpp, "Buffer out of reach %08x %016llx\n", |
---|
| 472 | + cpp_id, cpp_buf); |
---|
| 473 | + return -EINVAL; |
---|
| 474 | + } |
---|
| 475 | + |
---|
| 476 | + arg->arg.buf = FIELD_PREP(NSP_BUFFER_CPP, cpp_id >> 8) | |
---|
| 477 | + FIELD_PREP(NSP_BUFFER_ADDRESS, cpp_buf); |
---|
| 478 | + ret = __nfp_nsp_command(nsp, &arg->arg); |
---|
449 | 479 | if (ret < 0) |
---|
450 | 480 | return ret; |
---|
451 | 481 | |
---|
452 | | - if (out_buf && out_size) { |
---|
453 | | - err = nfp_cpp_read(cpp, cpp_id, cpp_buf, out_buf, out_size); |
---|
| 482 | + if (arg->out_buf && arg->out_size) { |
---|
| 483 | + err = nfp_cpp_read(cpp, cpp_id, cpp_buf, |
---|
| 484 | + arg->out_buf, arg->out_size); |
---|
454 | 485 | if (err < 0) |
---|
455 | 486 | return err; |
---|
456 | 487 | } |
---|
.. | .. |
---|
459 | 490 | } |
---|
460 | 491 | |
---|
461 | 492 | static int |
---|
462 | | -nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, |
---|
463 | | - const void *in_buf, unsigned int in_size, void *out_buf, |
---|
464 | | - unsigned int out_size) |
---|
| 493 | +nfp_nsp_command_buf_dma_sg(struct nfp_nsp *nsp, |
---|
| 494 | + struct nfp_nsp_command_buf_arg *arg, |
---|
| 495 | + unsigned int max_size, unsigned int chunk_order, |
---|
| 496 | + unsigned int dma_order) |
---|
465 | 497 | { |
---|
466 | | - return __nfp_nsp_command_buf(nsp, code, option, in_buf, in_size, |
---|
467 | | - out_buf, out_size, |
---|
468 | | - NFP_NSP_TIMEOUT_DEFAULT); |
---|
| 498 | + struct nfp_cpp *cpp = nsp->cpp; |
---|
| 499 | + struct nfp_nsp_dma_buf *desc; |
---|
| 500 | + struct { |
---|
| 501 | + dma_addr_t dma_addr; |
---|
| 502 | + unsigned long len; |
---|
| 503 | + void *chunk; |
---|
| 504 | + } *chunks; |
---|
| 505 | + size_t chunk_size, dma_size; |
---|
| 506 | + dma_addr_t dma_desc; |
---|
| 507 | + struct device *dev; |
---|
| 508 | + unsigned long off; |
---|
| 509 | + int i, ret, nseg; |
---|
| 510 | + size_t desc_sz; |
---|
| 511 | + |
---|
| 512 | + chunk_size = BIT_ULL(chunk_order); |
---|
| 513 | + dma_size = BIT_ULL(dma_order); |
---|
| 514 | + nseg = DIV_ROUND_UP(max_size, chunk_size); |
---|
| 515 | + |
---|
| 516 | + chunks = kzalloc(array_size(sizeof(*chunks), nseg), GFP_KERNEL); |
---|
| 517 | + if (!chunks) |
---|
| 518 | + return -ENOMEM; |
---|
| 519 | + |
---|
| 520 | + off = 0; |
---|
| 521 | + ret = -ENOMEM; |
---|
| 522 | + for (i = 0; i < nseg; i++) { |
---|
| 523 | + unsigned long coff; |
---|
| 524 | + |
---|
| 525 | + chunks[i].chunk = kmalloc(chunk_size, |
---|
| 526 | + GFP_KERNEL | __GFP_NOWARN); |
---|
| 527 | + if (!chunks[i].chunk) |
---|
| 528 | + goto exit_free_prev; |
---|
| 529 | + |
---|
| 530 | + chunks[i].len = min_t(u64, chunk_size, max_size - off); |
---|
| 531 | + |
---|
| 532 | + coff = 0; |
---|
| 533 | + if (arg->in_size > off) { |
---|
| 534 | + coff = min_t(u64, arg->in_size - off, chunk_size); |
---|
| 535 | + memcpy(chunks[i].chunk, arg->in_buf + off, coff); |
---|
| 536 | + } |
---|
| 537 | + memset(chunks[i].chunk + coff, 0, chunk_size - coff); |
---|
| 538 | + |
---|
| 539 | + off += chunks[i].len; |
---|
| 540 | + } |
---|
| 541 | + |
---|
| 542 | + dev = nfp_cpp_device(cpp)->parent; |
---|
| 543 | + |
---|
| 544 | + for (i = 0; i < nseg; i++) { |
---|
| 545 | + dma_addr_t addr; |
---|
| 546 | + |
---|
| 547 | + addr = dma_map_single(dev, chunks[i].chunk, chunks[i].len, |
---|
| 548 | + DMA_BIDIRECTIONAL); |
---|
| 549 | + chunks[i].dma_addr = addr; |
---|
| 550 | + |
---|
| 551 | + ret = dma_mapping_error(dev, addr); |
---|
| 552 | + if (ret) |
---|
| 553 | + goto exit_unmap_prev; |
---|
| 554 | + |
---|
| 555 | + if (WARN_ONCE(round_down(addr, dma_size) != |
---|
| 556 | + round_down(addr + chunks[i].len - 1, dma_size), |
---|
| 557 | + "unaligned DMA address: %pad %lu %zd\n", |
---|
| 558 | + &addr, chunks[i].len, dma_size)) { |
---|
| 559 | + ret = -EFAULT; |
---|
| 560 | + i++; |
---|
| 561 | + goto exit_unmap_prev; |
---|
| 562 | + } |
---|
| 563 | + } |
---|
| 564 | + |
---|
| 565 | + desc_sz = struct_size(desc, descs, nseg); |
---|
| 566 | + desc = kmalloc(desc_sz, GFP_KERNEL); |
---|
| 567 | + if (!desc) { |
---|
| 568 | + ret = -ENOMEM; |
---|
| 569 | + goto exit_unmap_all; |
---|
| 570 | + } |
---|
| 571 | + |
---|
| 572 | + desc->chunk_cnt = cpu_to_le32(nseg); |
---|
| 573 | + for (i = 0; i < nseg; i++) { |
---|
| 574 | + desc->descs[i].size = cpu_to_le32(chunks[i].len); |
---|
| 575 | + desc->descs[i].addr = cpu_to_le64(chunks[i].dma_addr); |
---|
| 576 | + } |
---|
| 577 | + |
---|
| 578 | + dma_desc = dma_map_single(dev, desc, desc_sz, DMA_TO_DEVICE); |
---|
| 579 | + ret = dma_mapping_error(dev, dma_desc); |
---|
| 580 | + if (ret) |
---|
| 581 | + goto exit_free_desc; |
---|
| 582 | + |
---|
| 583 | + arg->arg.dma = true; |
---|
| 584 | + arg->arg.buf = dma_desc; |
---|
| 585 | + ret = __nfp_nsp_command(nsp, &arg->arg); |
---|
| 586 | + if (ret < 0) |
---|
| 587 | + goto exit_unmap_desc; |
---|
| 588 | + |
---|
| 589 | + i = 0; |
---|
| 590 | + off = 0; |
---|
| 591 | + while (off < arg->out_size) { |
---|
| 592 | + unsigned int len; |
---|
| 593 | + |
---|
| 594 | + len = min_t(u64, chunks[i].len, arg->out_size - off); |
---|
| 595 | + memcpy(arg->out_buf + off, chunks[i].chunk, len); |
---|
| 596 | + off += len; |
---|
| 597 | + i++; |
---|
| 598 | + } |
---|
| 599 | + |
---|
| 600 | +exit_unmap_desc: |
---|
| 601 | + dma_unmap_single(dev, dma_desc, desc_sz, DMA_TO_DEVICE); |
---|
| 602 | +exit_free_desc: |
---|
| 603 | + kfree(desc); |
---|
| 604 | +exit_unmap_all: |
---|
| 605 | + i = nseg; |
---|
| 606 | +exit_unmap_prev: |
---|
| 607 | + while (--i >= 0) |
---|
| 608 | + dma_unmap_single(dev, chunks[i].dma_addr, chunks[i].len, |
---|
| 609 | + DMA_BIDIRECTIONAL); |
---|
| 610 | + i = nseg; |
---|
| 611 | +exit_free_prev: |
---|
| 612 | + while (--i >= 0) |
---|
| 613 | + kfree(chunks[i].chunk); |
---|
| 614 | + kfree(chunks); |
---|
| 615 | + if (ret < 0) |
---|
| 616 | + nfp_err(cpp, "NSP: SG DMA failed for command 0x%04x: %d (sz:%d cord:%d)\n", |
---|
| 617 | + arg->arg.code, ret, max_size, chunk_order); |
---|
| 618 | + return ret; |
---|
| 619 | +} |
---|
| 620 | + |
---|
| 621 | +static int |
---|
| 622 | +nfp_nsp_command_buf_dma(struct nfp_nsp *nsp, |
---|
| 623 | + struct nfp_nsp_command_buf_arg *arg, |
---|
| 624 | + unsigned int max_size, unsigned int dma_order) |
---|
| 625 | +{ |
---|
| 626 | + unsigned int chunk_order, buf_order; |
---|
| 627 | + struct nfp_cpp *cpp = nsp->cpp; |
---|
| 628 | + bool sg_ok; |
---|
| 629 | + u64 reg; |
---|
| 630 | + int err; |
---|
| 631 | + |
---|
| 632 | + buf_order = order_base_2(roundup_pow_of_two(max_size)); |
---|
| 633 | + |
---|
| 634 | + err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res), |
---|
| 635 | + nfp_resource_address(nsp->res) + NFP_CAP_CMD_DMA_SG, |
---|
| 636 | + ®); |
---|
| 637 | + if (err < 0) |
---|
| 638 | + return err; |
---|
| 639 | + sg_ok = reg & BIT_ULL(arg->arg.code - 1); |
---|
| 640 | + |
---|
| 641 | + if (!sg_ok) { |
---|
| 642 | + if (buf_order > dma_order) { |
---|
| 643 | + nfp_err(cpp, "NSP: can't service non-SG DMA for command 0x%04x\n", |
---|
| 644 | + arg->arg.code); |
---|
| 645 | + return -ENOMEM; |
---|
| 646 | + } |
---|
| 647 | + chunk_order = buf_order; |
---|
| 648 | + } else { |
---|
| 649 | + chunk_order = min_t(unsigned int, dma_order, PAGE_SHIFT); |
---|
| 650 | + } |
---|
| 651 | + |
---|
| 652 | + return nfp_nsp_command_buf_dma_sg(nsp, arg, max_size, chunk_order, |
---|
| 653 | + dma_order); |
---|
| 654 | +} |
---|
| 655 | + |
---|
| 656 | +static int |
---|
| 657 | +nfp_nsp_command_buf(struct nfp_nsp *nsp, struct nfp_nsp_command_buf_arg *arg) |
---|
| 658 | +{ |
---|
| 659 | + unsigned int dma_order, def_size, max_size; |
---|
| 660 | + struct nfp_cpp *cpp = nsp->cpp; |
---|
| 661 | + u64 reg; |
---|
| 662 | + int err; |
---|
| 663 | + |
---|
| 664 | + if (nsp->ver.minor < 13) { |
---|
| 665 | + nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %hu.%hu)\n", |
---|
| 666 | + arg->arg.code, nsp->ver.major, nsp->ver.minor); |
---|
| 667 | + return -EOPNOTSUPP; |
---|
| 668 | + } |
---|
| 669 | + |
---|
| 670 | + err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res), |
---|
| 671 | + nfp_resource_address(nsp->res) + |
---|
| 672 | + NSP_DFLT_BUFFER_CONFIG, |
---|
| 673 | + ®); |
---|
| 674 | + if (err < 0) |
---|
| 675 | + return err; |
---|
| 676 | + |
---|
| 677 | + /* Zero out undefined part of the out buffer */ |
---|
| 678 | + if (arg->out_buf && arg->out_size && arg->out_size > arg->in_size) |
---|
| 679 | + memset(arg->out_buf, 0, arg->out_size - arg->in_size); |
---|
| 680 | + |
---|
| 681 | + max_size = max(arg->in_size, arg->out_size); |
---|
| 682 | + def_size = FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M + |
---|
| 683 | + FIELD_GET(NSP_DFLT_BUFFER_SIZE_4KB, reg) * SZ_4K; |
---|
| 684 | + dma_order = FIELD_GET(NSP_DFLT_BUFFER_DMA_CHUNK_ORDER, reg); |
---|
| 685 | + if (def_size >= max_size) { |
---|
| 686 | + return nfp_nsp_command_buf_def(nsp, arg); |
---|
| 687 | + } else if (!dma_order) { |
---|
| 688 | + nfp_err(cpp, "NSP: default buffer too small for command 0x%04x (%u < %u)\n", |
---|
| 689 | + arg->arg.code, def_size, max_size); |
---|
| 690 | + return -EINVAL; |
---|
| 691 | + } |
---|
| 692 | + |
---|
| 693 | + return nfp_nsp_command_buf_dma(nsp, arg, max_size, dma_order); |
---|
469 | 694 | } |
---|
470 | 695 | |
---|
471 | 696 | int nfp_nsp_wait(struct nfp_nsp *state) |
---|
.. | .. |
---|
479 | 704 | for (;;) { |
---|
480 | 705 | const unsigned long start_time = jiffies; |
---|
481 | 706 | |
---|
482 | | - err = nfp_nsp_command(state, SPCODE_NOOP, 0, 0, 0); |
---|
| 707 | + err = nfp_nsp_command(state, SPCODE_NOOP); |
---|
483 | 708 | if (err != -EAGAIN) |
---|
484 | 709 | break; |
---|
485 | 710 | |
---|
.. | .. |
---|
501 | 726 | |
---|
502 | 727 | int nfp_nsp_device_soft_reset(struct nfp_nsp *state) |
---|
503 | 728 | { |
---|
504 | | - return nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0); |
---|
| 729 | + return nfp_nsp_command(state, SPCODE_SOFT_RESET); |
---|
505 | 730 | } |
---|
506 | 731 | |
---|
507 | 732 | int nfp_nsp_mac_reinit(struct nfp_nsp *state) |
---|
508 | 733 | { |
---|
509 | | - return nfp_nsp_command(state, SPCODE_MAC_INIT, 0, 0, 0); |
---|
| 734 | + return nfp_nsp_command(state, SPCODE_MAC_INIT); |
---|
| 735 | +} |
---|
| 736 | + |
---|
| 737 | +static void nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state, u32 ret_val) |
---|
| 738 | +{ |
---|
| 739 | + static const char * const major_msg[] = { |
---|
| 740 | + /* 0 */ "Firmware from driver loaded", |
---|
| 741 | + /* 1 */ "Firmware from flash loaded", |
---|
| 742 | + /* 2 */ "Firmware loading failure", |
---|
| 743 | + }; |
---|
| 744 | + static const char * const minor_msg[] = { |
---|
| 745 | + /* 0 */ "", |
---|
| 746 | + /* 1 */ "no named partition on flash", |
---|
| 747 | + /* 2 */ "error reading from flash", |
---|
| 748 | + /* 3 */ "can not deflate", |
---|
| 749 | + /* 4 */ "not a trusted file", |
---|
| 750 | + /* 5 */ "can not parse FW file", |
---|
| 751 | + /* 6 */ "MIP not found in FW file", |
---|
| 752 | + /* 7 */ "null firmware name in MIP", |
---|
| 753 | + /* 8 */ "FW version none", |
---|
| 754 | + /* 9 */ "FW build number none", |
---|
| 755 | + /* 10 */ "no FW selection policy HWInfo key found", |
---|
| 756 | + /* 11 */ "static FW selection policy", |
---|
| 757 | + /* 12 */ "FW version has precedence", |
---|
| 758 | + /* 13 */ "different FW application load requested", |
---|
| 759 | + /* 14 */ "development build", |
---|
| 760 | + }; |
---|
| 761 | + unsigned int major, minor; |
---|
| 762 | + const char *level; |
---|
| 763 | + |
---|
| 764 | + major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val); |
---|
| 765 | + minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val); |
---|
| 766 | + |
---|
| 767 | + if (!nfp_nsp_has_stored_fw_load(state)) |
---|
| 768 | + return; |
---|
| 769 | + |
---|
| 770 | + /* Lower the message level in legacy case */ |
---|
| 771 | + if (major == 0 && (minor == 0 || minor == 10)) |
---|
| 772 | + level = KERN_DEBUG; |
---|
| 773 | + else if (major == 2) |
---|
| 774 | + level = KERN_ERR; |
---|
| 775 | + else |
---|
| 776 | + level = KERN_INFO; |
---|
| 777 | + |
---|
| 778 | + if (major >= ARRAY_SIZE(major_msg)) |
---|
| 779 | + nfp_printk(level, state->cpp, "FW loading status: %x\n", |
---|
| 780 | + ret_val); |
---|
| 781 | + else if (minor >= ARRAY_SIZE(minor_msg)) |
---|
| 782 | + nfp_printk(level, state->cpp, "%s, reason code: %d\n", |
---|
| 783 | + major_msg[major], minor); |
---|
| 784 | + else |
---|
| 785 | + nfp_printk(level, state->cpp, "%s%c %s\n", |
---|
| 786 | + major_msg[major], minor ? ',' : '.', |
---|
| 787 | + minor_msg[minor]); |
---|
510 | 788 | } |
---|
511 | 789 | |
---|
512 | 790 | int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw) |
---|
513 | 791 | { |
---|
514 | | - return nfp_nsp_command_buf(state, SPCODE_FW_LOAD, fw->size, fw->data, |
---|
515 | | - fw->size, NULL, 0); |
---|
| 792 | + struct nfp_nsp_command_buf_arg load_fw = { |
---|
| 793 | + { |
---|
| 794 | + .code = SPCODE_FW_LOAD, |
---|
| 795 | + .option = fw->size, |
---|
| 796 | + .error_cb = nfp_nsp_load_fw_extended_msg, |
---|
| 797 | + }, |
---|
| 798 | + .in_buf = fw->data, |
---|
| 799 | + .in_size = fw->size, |
---|
| 800 | + }; |
---|
| 801 | + int ret; |
---|
| 802 | + |
---|
| 803 | + ret = nfp_nsp_command_buf(state, &load_fw); |
---|
| 804 | + if (ret < 0) |
---|
| 805 | + return ret; |
---|
| 806 | + |
---|
| 807 | + nfp_nsp_load_fw_extended_msg(state, ret); |
---|
| 808 | + return 0; |
---|
516 | 809 | } |
---|
517 | 810 | |
---|
518 | 811 | int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw) |
---|
519 | 812 | { |
---|
520 | | - /* The flash time is specified to take a maximum of 70s so we add an |
---|
521 | | - * additional factor to this spec time. |
---|
522 | | - */ |
---|
523 | | - u32 timeout_sec = 2.5 * 70; |
---|
| 813 | + struct nfp_nsp_command_buf_arg write_flash = { |
---|
| 814 | + { |
---|
| 815 | + .code = SPCODE_NSP_WRITE_FLASH, |
---|
| 816 | + .option = fw->size, |
---|
| 817 | + .timeout_sec = 900, |
---|
| 818 | + }, |
---|
| 819 | + .in_buf = fw->data, |
---|
| 820 | + .in_size = fw->size, |
---|
| 821 | + }; |
---|
524 | 822 | |
---|
525 | | - return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size, |
---|
526 | | - fw->data, fw->size, NULL, 0, timeout_sec); |
---|
| 823 | + return nfp_nsp_command_buf(state, &write_flash); |
---|
527 | 824 | } |
---|
528 | 825 | |
---|
529 | 826 | int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
530 | 827 | { |
---|
531 | | - return nfp_nsp_command_buf(state, SPCODE_ETH_RESCAN, size, NULL, 0, |
---|
532 | | - buf, size); |
---|
| 828 | + struct nfp_nsp_command_buf_arg eth_rescan = { |
---|
| 829 | + { |
---|
| 830 | + .code = SPCODE_ETH_RESCAN, |
---|
| 831 | + .option = size, |
---|
| 832 | + }, |
---|
| 833 | + .out_buf = buf, |
---|
| 834 | + .out_size = size, |
---|
| 835 | + }; |
---|
| 836 | + |
---|
| 837 | + return nfp_nsp_command_buf(state, ð_rescan); |
---|
533 | 838 | } |
---|
534 | 839 | |
---|
535 | 840 | int nfp_nsp_write_eth_table(struct nfp_nsp *state, |
---|
536 | 841 | const void *buf, unsigned int size) |
---|
537 | 842 | { |
---|
538 | | - return nfp_nsp_command_buf(state, SPCODE_ETH_CONTROL, size, buf, size, |
---|
539 | | - NULL, 0); |
---|
| 843 | + struct nfp_nsp_command_buf_arg eth_ctrl = { |
---|
| 844 | + { |
---|
| 845 | + .code = SPCODE_ETH_CONTROL, |
---|
| 846 | + .option = size, |
---|
| 847 | + }, |
---|
| 848 | + .in_buf = buf, |
---|
| 849 | + .in_size = size, |
---|
| 850 | + }; |
---|
| 851 | + |
---|
| 852 | + return nfp_nsp_command_buf(state, ð_ctrl); |
---|
540 | 853 | } |
---|
541 | 854 | |
---|
542 | 855 | int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
543 | 856 | { |
---|
544 | | - return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0, |
---|
545 | | - buf, size); |
---|
| 857 | + struct nfp_nsp_command_buf_arg identify = { |
---|
| 858 | + { |
---|
| 859 | + .code = SPCODE_NSP_IDENTIFY, |
---|
| 860 | + .option = size, |
---|
| 861 | + }, |
---|
| 862 | + .out_buf = buf, |
---|
| 863 | + .out_size = size, |
---|
| 864 | + }; |
---|
| 865 | + |
---|
| 866 | + return nfp_nsp_command_buf(state, &identify); |
---|
546 | 867 | } |
---|
547 | 868 | |
---|
548 | 869 | int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, |
---|
549 | 870 | void *buf, unsigned int size) |
---|
550 | 871 | { |
---|
551 | | - return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask, |
---|
552 | | - NULL, 0, buf, size); |
---|
| 872 | + struct nfp_nsp_command_buf_arg sensors = { |
---|
| 873 | + { |
---|
| 874 | + .code = SPCODE_NSP_SENSORS, |
---|
| 875 | + .option = sensor_mask, |
---|
| 876 | + }, |
---|
| 877 | + .out_buf = buf, |
---|
| 878 | + .out_size = size, |
---|
| 879 | + }; |
---|
| 880 | + |
---|
| 881 | + return nfp_nsp_command_buf(state, &sensors); |
---|
| 882 | +} |
---|
| 883 | + |
---|
| 884 | +int nfp_nsp_load_stored_fw(struct nfp_nsp *state) |
---|
| 885 | +{ |
---|
| 886 | + const struct nfp_nsp_command_arg arg = { |
---|
| 887 | + .code = SPCODE_FW_STORED, |
---|
| 888 | + .error_cb = nfp_nsp_load_fw_extended_msg, |
---|
| 889 | + }; |
---|
| 890 | + int ret; |
---|
| 891 | + |
---|
| 892 | + ret = __nfp_nsp_command(state, &arg); |
---|
| 893 | + if (ret < 0) |
---|
| 894 | + return ret; |
---|
| 895 | + |
---|
| 896 | + nfp_nsp_load_fw_extended_msg(state, ret); |
---|
| 897 | + return 0; |
---|
| 898 | +} |
---|
| 899 | + |
---|
| 900 | +static int |
---|
| 901 | +__nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size, |
---|
| 902 | + bool optional) |
---|
| 903 | +{ |
---|
| 904 | + struct nfp_nsp_command_buf_arg hwinfo_lookup = { |
---|
| 905 | + { |
---|
| 906 | + .code = SPCODE_HWINFO_LOOKUP, |
---|
| 907 | + .option = size, |
---|
| 908 | + .error_quiet = optional, |
---|
| 909 | + }, |
---|
| 910 | + .in_buf = buf, |
---|
| 911 | + .in_size = size, |
---|
| 912 | + .out_buf = buf, |
---|
| 913 | + .out_size = size, |
---|
| 914 | + }; |
---|
| 915 | + |
---|
| 916 | + return nfp_nsp_command_buf(state, &hwinfo_lookup); |
---|
| 917 | +} |
---|
| 918 | + |
---|
| 919 | +int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
| 920 | +{ |
---|
| 921 | + int err; |
---|
| 922 | + |
---|
| 923 | + size = min_t(u32, size, NFP_HWINFO_LOOKUP_SIZE); |
---|
| 924 | + |
---|
| 925 | + err = __nfp_nsp_hwinfo_lookup(state, buf, size, false); |
---|
| 926 | + if (err) |
---|
| 927 | + return err; |
---|
| 928 | + |
---|
| 929 | + if (strnlen(buf, size) == size) { |
---|
| 930 | + nfp_err(state->cpp, "NSP HWinfo value not NULL-terminated\n"); |
---|
| 931 | + return -EINVAL; |
---|
| 932 | + } |
---|
| 933 | + |
---|
| 934 | + return 0; |
---|
| 935 | +} |
---|
| 936 | + |
---|
| 937 | +int nfp_nsp_hwinfo_lookup_optional(struct nfp_nsp *state, void *buf, |
---|
| 938 | + unsigned int size, const char *default_val) |
---|
| 939 | +{ |
---|
| 940 | + int err; |
---|
| 941 | + |
---|
| 942 | + /* Ensure that the default value is usable irrespective of whether |
---|
| 943 | + * it is actually going to be used. |
---|
| 944 | + */ |
---|
| 945 | + if (strnlen(default_val, size) == size) |
---|
| 946 | + return -EINVAL; |
---|
| 947 | + |
---|
| 948 | + if (!nfp_nsp_has_hwinfo_lookup(state)) { |
---|
| 949 | + strcpy(buf, default_val); |
---|
| 950 | + return 0; |
---|
| 951 | + } |
---|
| 952 | + |
---|
| 953 | + size = min_t(u32, size, NFP_HWINFO_LOOKUP_SIZE); |
---|
| 954 | + |
---|
| 955 | + err = __nfp_nsp_hwinfo_lookup(state, buf, size, true); |
---|
| 956 | + if (err) { |
---|
| 957 | + if (err == -ENOENT) { |
---|
| 958 | + strcpy(buf, default_val); |
---|
| 959 | + return 0; |
---|
| 960 | + } |
---|
| 961 | + |
---|
| 962 | + nfp_err(state->cpp, "NSP HWinfo lookup failed: %d\n", err); |
---|
| 963 | + return err; |
---|
| 964 | + } |
---|
| 965 | + |
---|
| 966 | + if (strnlen(buf, size) == size) { |
---|
| 967 | + nfp_err(state->cpp, "NSP HWinfo value not NULL-terminated\n"); |
---|
| 968 | + return -EINVAL; |
---|
| 969 | + } |
---|
| 970 | + |
---|
| 971 | + return 0; |
---|
| 972 | +} |
---|
| 973 | + |
---|
| 974 | +int nfp_nsp_hwinfo_set(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
| 975 | +{ |
---|
| 976 | + struct nfp_nsp_command_buf_arg hwinfo_set = { |
---|
| 977 | + { |
---|
| 978 | + .code = SPCODE_HWINFO_SET, |
---|
| 979 | + .option = size, |
---|
| 980 | + }, |
---|
| 981 | + .in_buf = buf, |
---|
| 982 | + .in_size = size, |
---|
| 983 | + }; |
---|
| 984 | + |
---|
| 985 | + return nfp_nsp_command_buf(state, &hwinfo_set); |
---|
| 986 | +} |
---|
| 987 | + |
---|
| 988 | +int nfp_nsp_fw_loaded(struct nfp_nsp *state) |
---|
| 989 | +{ |
---|
| 990 | + const struct nfp_nsp_command_arg arg = { |
---|
| 991 | + .code = SPCODE_FW_LOADED, |
---|
| 992 | + }; |
---|
| 993 | + |
---|
| 994 | + return __nfp_nsp_command(state, &arg); |
---|
| 995 | +} |
---|
| 996 | + |
---|
| 997 | +int nfp_nsp_versions(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
| 998 | +{ |
---|
| 999 | + struct nfp_nsp_command_buf_arg versions = { |
---|
| 1000 | + { |
---|
| 1001 | + .code = SPCODE_VERSIONS, |
---|
| 1002 | + .option = min_t(u32, size, NFP_VERSIONS_SIZE), |
---|
| 1003 | + }, |
---|
| 1004 | + .out_buf = buf, |
---|
| 1005 | + .out_size = min_t(u32, size, NFP_VERSIONS_SIZE), |
---|
| 1006 | + }; |
---|
| 1007 | + |
---|
| 1008 | + return nfp_nsp_command_buf(state, &versions); |
---|
| 1009 | +} |
---|
| 1010 | + |
---|
| 1011 | +const char *nfp_nsp_versions_get(enum nfp_nsp_versions id, bool flash, |
---|
| 1012 | + const u8 *buf, unsigned int size) |
---|
| 1013 | +{ |
---|
| 1014 | + static const u32 id2off[] = { |
---|
| 1015 | + [NFP_VERSIONS_BSP] = NFP_VERSIONS_BSP_OFF, |
---|
| 1016 | + [NFP_VERSIONS_CPLD] = NFP_VERSIONS_CPLD_OFF, |
---|
| 1017 | + [NFP_VERSIONS_APP] = NFP_VERSIONS_APP_OFF, |
---|
| 1018 | + [NFP_VERSIONS_BUNDLE] = NFP_VERSIONS_BUNDLE_OFF, |
---|
| 1019 | + [NFP_VERSIONS_UNDI] = NFP_VERSIONS_UNDI_OFF, |
---|
| 1020 | + [NFP_VERSIONS_NCSI] = NFP_VERSIONS_NCSI_OFF, |
---|
| 1021 | + [NFP_VERSIONS_CFGR] = NFP_VERSIONS_CFGR_OFF, |
---|
| 1022 | + }; |
---|
| 1023 | + unsigned int field, buf_field_cnt, buf_off; |
---|
| 1024 | + |
---|
| 1025 | + if (id >= ARRAY_SIZE(id2off) || !id2off[id]) |
---|
| 1026 | + return ERR_PTR(-EINVAL); |
---|
| 1027 | + |
---|
| 1028 | + field = id * 2 + flash; |
---|
| 1029 | + |
---|
| 1030 | + buf_field_cnt = get_unaligned_le16(buf); |
---|
| 1031 | + if (buf_field_cnt <= field) |
---|
| 1032 | + return ERR_PTR(-ENOENT); |
---|
| 1033 | + |
---|
| 1034 | + buf_off = get_unaligned_le16(buf + id2off[id] + flash * 2); |
---|
| 1035 | + if (!buf_off) |
---|
| 1036 | + return ERR_PTR(-ENOENT); |
---|
| 1037 | + |
---|
| 1038 | + if (buf_off >= size) |
---|
| 1039 | + return ERR_PTR(-EINVAL); |
---|
| 1040 | + if (strnlen(&buf[buf_off], size - buf_off) == size - buf_off) |
---|
| 1041 | + return ERR_PTR(-EINVAL); |
---|
| 1042 | + |
---|
| 1043 | + return (const char *)&buf[buf_off]; |
---|
| 1044 | +} |
---|
| 1045 | + |
---|
| 1046 | +static int |
---|
| 1047 | +__nfp_nsp_module_eeprom(struct nfp_nsp *state, void *buf, unsigned int size) |
---|
| 1048 | +{ |
---|
| 1049 | + struct nfp_nsp_command_buf_arg module_eeprom = { |
---|
| 1050 | + { |
---|
| 1051 | + .code = SPCODE_READ_SFF_EEPROM, |
---|
| 1052 | + .option = size, |
---|
| 1053 | + }, |
---|
| 1054 | + .in_buf = buf, |
---|
| 1055 | + .in_size = size, |
---|
| 1056 | + .out_buf = buf, |
---|
| 1057 | + .out_size = size, |
---|
| 1058 | + }; |
---|
| 1059 | + |
---|
| 1060 | + return nfp_nsp_command_buf(state, &module_eeprom); |
---|
| 1061 | +} |
---|
| 1062 | + |
---|
| 1063 | +int nfp_nsp_read_module_eeprom(struct nfp_nsp *state, int eth_index, |
---|
| 1064 | + unsigned int offset, void *data, |
---|
| 1065 | + unsigned int len, unsigned int *read_len) |
---|
| 1066 | +{ |
---|
| 1067 | + struct eeprom_buf { |
---|
| 1068 | + u8 metalen; |
---|
| 1069 | + __le16 length; |
---|
| 1070 | + __le16 offset; |
---|
| 1071 | + __le16 readlen; |
---|
| 1072 | + u8 eth_index; |
---|
| 1073 | + u8 data[0]; |
---|
| 1074 | + } __packed *buf; |
---|
| 1075 | + int bufsz, ret; |
---|
| 1076 | + |
---|
| 1077 | + BUILD_BUG_ON(offsetof(struct eeprom_buf, data) % 8); |
---|
| 1078 | + |
---|
| 1079 | + /* Buffer must be large enough and rounded to the next block size. */ |
---|
| 1080 | + bufsz = struct_size(buf, data, round_up(len, NSP_SFF_EEPROM_BLOCK_LEN)); |
---|
| 1081 | + buf = kzalloc(bufsz, GFP_KERNEL); |
---|
| 1082 | + if (!buf) |
---|
| 1083 | + return -ENOMEM; |
---|
| 1084 | + |
---|
| 1085 | + buf->metalen = |
---|
| 1086 | + offsetof(struct eeprom_buf, data) / NSP_SFF_EEPROM_BLOCK_LEN; |
---|
| 1087 | + buf->length = cpu_to_le16(len); |
---|
| 1088 | + buf->offset = cpu_to_le16(offset); |
---|
| 1089 | + buf->eth_index = eth_index; |
---|
| 1090 | + |
---|
| 1091 | + ret = __nfp_nsp_module_eeprom(state, buf, bufsz); |
---|
| 1092 | + |
---|
| 1093 | + *read_len = min_t(unsigned int, len, le16_to_cpu(buf->readlen)); |
---|
| 1094 | + if (*read_len) |
---|
| 1095 | + memcpy(data, buf->data, *read_len); |
---|
| 1096 | + |
---|
| 1097 | + if (!ret && *read_len < len) |
---|
| 1098 | + ret = -EIO; |
---|
| 1099 | + |
---|
| 1100 | + kfree(buf); |
---|
| 1101 | + |
---|
| 1102 | + return ret; |
---|
553 | 1103 | } |
---|