1 /*-
2 * Copyright 2009 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_types.h"
32 #include "efx_regs.h"
33 #include "efx_impl.h"
34
35 #if EFSYS_OPT_SIENA
36
37 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
38
39 __checkReturn int
siena_nvram_partn_size(__in efx_nic_t * enp,__in unsigned int partn,__out size_t * sizep)40 siena_nvram_partn_size(
41 __in efx_nic_t *enp,
42 __in unsigned int partn,
43 __out size_t *sizep)
44 {
45 efx_mcdi_req_t req;
46 uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
47 MC_CMD_NVRAM_INFO_OUT_LEN)];
48 int rc;
49
50 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
51 rc = ENOTSUP;
52 goto fail1;
53 }
54
55 req.emr_cmd = MC_CMD_NVRAM_INFO;
56 req.emr_in_buf = payload;
57 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
58 req.emr_out_buf = payload;
59 req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
60
61 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
62
63 efx_mcdi_execute(enp, &req);
64
65 if (req.emr_rc != 0) {
66 rc = req.emr_rc;
67 goto fail2;
68 }
69
70 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
71 rc = EMSGSIZE;
72 goto fail3;
73 }
74
75 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
76
77 return (0);
78
79 fail3:
80 EFSYS_PROBE(fail3);
81 fail2:
82 EFSYS_PROBE(fail2);
83 fail1:
84 EFSYS_PROBE1(fail1, int, rc);
85
86 return (rc);
87 }
88
89 __checkReturn int
siena_nvram_partn_lock(__in efx_nic_t * enp,__in unsigned int partn)90 siena_nvram_partn_lock(
91 __in efx_nic_t *enp,
92 __in unsigned int partn)
93 {
94 efx_mcdi_req_t req;
95 uint8_t payload[MC_CMD_NVRAM_UPDATE_START_IN_LEN];
96 int rc;
97
98 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
99 req.emr_in_buf = payload;
100 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
101 EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_START_OUT_LEN == 0);
102 req.emr_out_buf = NULL;
103 req.emr_out_length = 0;
104
105 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
106
107 efx_mcdi_execute(enp, &req);
108
109 if (req.emr_rc != 0) {
110 rc = req.emr_rc;
111 goto fail1;
112 }
113
114 return (0);
115
116 fail1:
117 EFSYS_PROBE1(fail1, int, rc);
118
119 return (rc);
120 }
121
122 __checkReturn int
siena_nvram_partn_read(__in efx_nic_t * enp,__in unsigned int partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)123 siena_nvram_partn_read(
124 __in efx_nic_t *enp,
125 __in unsigned int partn,
126 __in unsigned int offset,
127 __out_bcount(size) caddr_t data,
128 __in size_t size)
129 {
130 efx_mcdi_req_t req;
131 uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
132 MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK))];
133 size_t chunk;
134 int rc;
135
136 while (size > 0) {
137 chunk = MIN(size, SIENA_NVRAM_CHUNK);
138
139 req.emr_cmd = MC_CMD_NVRAM_READ;
140 req.emr_in_buf = payload;
141 req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
142 req.emr_out_buf = payload;
143 req.emr_out_length =
144 MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK);
145
146 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
147 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
148 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, chunk);
149
150 efx_mcdi_execute(enp, &req);
151
152 if (req.emr_rc != 0) {
153 rc = req.emr_rc;
154 goto fail1;
155 }
156
157 if (req.emr_out_length_used <
158 MC_CMD_NVRAM_READ_OUT_LEN(chunk)) {
159 rc = EMSGSIZE;
160 goto fail2;
161 }
162
163 memcpy(data,
164 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
165 chunk);
166
167 size -= chunk;
168 data += chunk;
169 offset += chunk;
170 }
171
172 return (0);
173
174 fail2:
175 EFSYS_PROBE(fail2);
176 fail1:
177 EFSYS_PROBE1(fail1, int, rc);
178
179 return (rc);
180 }
181
182 __checkReturn int
siena_nvram_partn_erase(__in efx_nic_t * enp,__in unsigned int partn,__in unsigned int offset,__in size_t size)183 siena_nvram_partn_erase(
184 __in efx_nic_t *enp,
185 __in unsigned int partn,
186 __in unsigned int offset,
187 __in size_t size)
188 {
189 efx_mcdi_req_t req;
190 uint8_t payload[MC_CMD_NVRAM_ERASE_IN_LEN];
191 int rc;
192
193 req.emr_cmd = MC_CMD_NVRAM_ERASE;
194 req.emr_in_buf = payload;
195 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
196 EFX_STATIC_ASSERT(MC_CMD_NVRAM_ERASE_OUT_LEN == 0);
197 req.emr_out_buf = NULL;
198 req.emr_out_length = 0;
199
200 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
201 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
202 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
203
204 efx_mcdi_execute(enp, &req);
205
206 if (req.emr_rc != 0) {
207 rc = req.emr_rc;
208 goto fail1;
209 }
210
211 return (0);
212
213 fail1:
214 EFSYS_PROBE1(fail1, int, rc);
215
216 return (rc);
217 }
218
219 __checkReturn int
siena_nvram_partn_write(__in efx_nic_t * enp,__in unsigned int partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)220 siena_nvram_partn_write(
221 __in efx_nic_t *enp,
222 __in unsigned int partn,
223 __in unsigned int offset,
224 __out_bcount(size) caddr_t data,
225 __in size_t size)
226 {
227 efx_mcdi_req_t req;
228 uint8_t payload[MC_CMD_NVRAM_WRITE_IN_LEN(SIENA_NVRAM_CHUNK)];
229 size_t chunk;
230 int rc;
231
232 while (size > 0) {
233 chunk = MIN(size, SIENA_NVRAM_CHUNK);
234
235 req.emr_cmd = MC_CMD_NVRAM_WRITE;
236 req.emr_in_buf = payload;
237 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(chunk);
238 EFX_STATIC_ASSERT(MC_CMD_NVRAM_WRITE_OUT_LEN == 0);
239 req.emr_out_buf = NULL;
240 req.emr_out_length = 0;
241
242 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
243 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
244 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, chunk);
245
246 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
247 data, chunk);
248
249 efx_mcdi_execute(enp, &req);
250
251 if (req.emr_rc != 0) {
252 rc = req.emr_rc;
253 goto fail1;
254 }
255
256 size -= chunk;
257 data += chunk;
258 offset += chunk;
259 }
260
261 return (0);
262
263 fail1:
264 EFSYS_PROBE1(fail1, int, rc);
265
266 return (rc);
267 }
268
269 void
siena_nvram_partn_unlock(__in efx_nic_t * enp,__in unsigned int partn)270 siena_nvram_partn_unlock(
271 __in efx_nic_t *enp,
272 __in unsigned int partn)
273 {
274 efx_mcdi_req_t req;
275 uint8_t payload[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN];
276 uint32_t reboot;
277 int rc;
278
279 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
280 req.emr_in_buf = payload;
281 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
282 EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN == 0);
283 req.emr_out_buf = NULL;
284 req.emr_out_length = 0;
285
286 /*
287 * Reboot into the new image only for PHYs. The driver has to
288 * explicitly cope with an MC reboot after a firmware update.
289 */
290 reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||
291 partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
292 partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
293
294 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
295 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
296
297 efx_mcdi_execute(enp, &req);
298
299 if (req.emr_rc != 0) {
300 rc = req.emr_rc;
301 goto fail1;
302 }
303
304 return;
305
306 fail1:
307 EFSYS_PROBE1(fail1, int, rc);
308 }
309
310 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
311
312 #if EFSYS_OPT_NVRAM
313
314 typedef struct siena_parttbl_entry_s {
315 unsigned int partn;
316 unsigned int port;
317 efx_nvram_type_t nvtype;
318 } siena_parttbl_entry_t;
319
320 static siena_parttbl_entry_t siena_parttbl[] = {
321 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 1, EFX_NVRAM_NULLPHY},
322 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 2, EFX_NVRAM_NULLPHY},
323 {MC_CMD_NVRAM_TYPE_MC_FW, 1, EFX_NVRAM_MC_FIRMWARE},
324 {MC_CMD_NVRAM_TYPE_MC_FW, 2, EFX_NVRAM_MC_FIRMWARE},
325 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 1, EFX_NVRAM_MC_GOLDEN},
326 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 2, EFX_NVRAM_MC_GOLDEN},
327 {MC_CMD_NVRAM_TYPE_EXP_ROM, 1, EFX_NVRAM_BOOTROM},
328 {MC_CMD_NVRAM_TYPE_EXP_ROM, 2, EFX_NVRAM_BOOTROM},
329 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
330 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG},
331 {MC_CMD_NVRAM_TYPE_PHY_PORT0, 1, EFX_NVRAM_PHY},
332 {MC_CMD_NVRAM_TYPE_PHY_PORT1, 2, EFX_NVRAM_PHY},
333 {MC_CMD_NVRAM_TYPE_FPGA, 1, EFX_NVRAM_FPGA},
334 {MC_CMD_NVRAM_TYPE_FPGA, 2, EFX_NVRAM_FPGA},
335 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP},
336 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP},
337 {MC_CMD_NVRAM_TYPE_FC_FW, 1, EFX_NVRAM_FCFW},
338 {MC_CMD_NVRAM_TYPE_FC_FW, 2, EFX_NVRAM_FCFW},
339 {MC_CMD_NVRAM_TYPE_CPLD, 1, EFX_NVRAM_CPLD},
340 {MC_CMD_NVRAM_TYPE_CPLD, 2, EFX_NVRAM_CPLD},
341 {0, 0, 0},
342 };
343
344 static __checkReturn siena_parttbl_entry_t *
siena_parttbl_entry(__in efx_nic_t * enp,__in efx_nvram_type_t type)345 siena_parttbl_entry(
346 __in efx_nic_t *enp,
347 __in efx_nvram_type_t type)
348 {
349 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
350 siena_parttbl_entry_t *entry;
351
352 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
353
354 for (entry = siena_parttbl; entry->port > 0; ++entry) {
355 if (entry->port == emip->emi_port && entry->nvtype == type)
356 return (entry);
357 }
358
359 return (NULL);
360 }
361
362 #if EFSYS_OPT_DIAG
363
364 __checkReturn int
siena_nvram_test(__in efx_nic_t * enp)365 siena_nvram_test(
366 __in efx_nic_t *enp)
367 {
368 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
369 siena_parttbl_entry_t *entry;
370 efx_mcdi_req_t req;
371 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
372 MC_CMD_NVRAM_TEST_OUT_LEN)];
373 int result;
374 int rc;
375
376 req.emr_cmd = MC_CMD_NVRAM_TEST;
377 req.emr_in_buf = payload;
378 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
379 req.emr_out_buf = payload;
380 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
381
382 /*
383 * Iterate over the list of supported partition types
384 * applicable to *this* port
385 */
386 for (entry = siena_parttbl; entry->port > 0; ++entry) {
387 if (entry->port != emip->emi_port ||
388 !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))
389 continue;
390
391 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn);
392
393 efx_mcdi_execute(enp, &req);
394
395 if (req.emr_rc != 0) {
396 rc = req.emr_rc;
397 goto fail1;
398 }
399
400 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
401 rc = EMSGSIZE;
402 goto fail2;
403 }
404
405 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
406 if (result == MC_CMD_NVRAM_TEST_FAIL) {
407
408 EFSYS_PROBE1(nvram_test_failure, int, entry->partn);
409
410 rc = (EINVAL);
411 goto fail3;
412 }
413 }
414
415 return (0);
416
417 fail3:
418 EFSYS_PROBE(fail3);
419 fail2:
420 EFSYS_PROBE(fail2);
421 fail1:
422 EFSYS_PROBE1(fail1, int, rc);
423
424 return (rc);
425 }
426
427 #endif /* EFSYS_OPT_DIAG */
428
429 __checkReturn int
siena_nvram_size(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out size_t * sizep)430 siena_nvram_size(
431 __in efx_nic_t *enp,
432 __in efx_nvram_type_t type,
433 __out size_t *sizep)
434 {
435 siena_parttbl_entry_t *entry;
436 int rc;
437
438 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
439 rc = ENOTSUP;
440 goto fail1;
441 }
442
443 if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0)
444 goto fail2;
445
446 return (0);
447
448 fail2:
449 EFSYS_PROBE(fail2);
450 fail1:
451 EFSYS_PROBE1(fail1, int, rc);
452
453 *sizep = 0;
454
455 return (rc);
456 }
457
458 #define SIENA_DYNAMIC_CFG_SIZE(_nitems) \
459 (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \
460 sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))
461
462 __checkReturn int
siena_nvram_get_dynamic_cfg(__in efx_nic_t * enp,__in unsigned int partn,__in boolean_t vpd,__out siena_mc_dynamic_config_hdr_t ** dcfgp,__out size_t * sizep)463 siena_nvram_get_dynamic_cfg(
464 __in efx_nic_t *enp,
465 __in unsigned int partn,
466 __in boolean_t vpd,
467 __out siena_mc_dynamic_config_hdr_t **dcfgp,
468 __out size_t *sizep)
469 {
470 siena_mc_dynamic_config_hdr_t *dcfg;
471 size_t size;
472 uint8_t cksum;
473 unsigned int vpd_offset;
474 unsigned int vpd_length;
475 unsigned int hdr_length;
476 unsigned int nversions;
477 unsigned int pos;
478 unsigned int region;
479 int rc;
480
481 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 ||
482 partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1);
483
484 /*
485 * Allocate sufficient memory for the entire dynamiccfg area, even
486 * if we're not actually going to read in the VPD.
487 */
488 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
489 goto fail1;
490
491 EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg);
492 if (dcfg == NULL) {
493 rc = ENOMEM;
494 goto fail2;
495 }
496
497 if ((rc = siena_nvram_partn_read(enp, partn, 0,
498 (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0)
499 goto fail3;
500
501 /* Verify the magic */
502 if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0)
503 != SIENA_MC_DYNAMIC_CONFIG_MAGIC)
504 goto invalid1;
505
506 /* All future versions of the structure must be backwards compatable */
507 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0);
508
509 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
510 nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
511 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
512 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
513
514 /* Verify the hdr doesn't overflow the partn size */
515 if (hdr_length > size || vpd_offset > size || vpd_length > size ||
516 vpd_length + vpd_offset > size)
517 goto invalid2;
518
519 /* Verify the header has room for all it's versions */
520 if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) ||
521 hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions))
522 goto invalid3;
523
524 /*
525 * Read the remaining portion of the dcfg, either including
526 * the whole of VPD (there is no vpd length in this structure,
527 * so we have to parse each tag), or just the dcfg header itself
528 */
529 region = vpd ? vpd_offset + vpd_length : hdr_length;
530 if (region > SIENA_NVRAM_CHUNK) {
531 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
532 (caddr_t)dcfg + SIENA_NVRAM_CHUNK,
533 region - SIENA_NVRAM_CHUNK)) != 0)
534 goto fail4;
535 }
536
537 /* Verify checksum */
538 cksum = 0;
539 for (pos = 0; pos < hdr_length; pos++)
540 cksum += ((uint8_t *)dcfg)[pos];
541 if (cksum != 0)
542 goto invalid4;
543
544 goto done;
545
546 invalid4:
547 EFSYS_PROBE(invalid4);
548 invalid3:
549 EFSYS_PROBE(invalid3);
550 invalid2:
551 EFSYS_PROBE(invalid2);
552 invalid1:
553 EFSYS_PROBE(invalid1);
554
555 /*
556 * Construct a new "null" dcfg, with an empty version vector,
557 * and an empty VPD chunk trailing. This has the neat side effect
558 * of testing the exception paths in the write path.
559 */
560 EFX_POPULATE_DWORD_1(dcfg->magic,
561 EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC);
562 EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg));
563 EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0,
564 SIENA_MC_DYNAMIC_CONFIG_VERSION);
565 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
566 EFX_DWORD_0, sizeof (*dcfg));
567 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0);
568 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0);
569
570 done:
571 *dcfgp = dcfg;
572 *sizep = size;
573
574 return (0);
575
576 fail4:
577 EFSYS_PROBE(fail4);
578 fail3:
579 EFSYS_PROBE(fail3);
580 fail2:
581 EFSYS_PROBE(fail2);
582
583 EFSYS_KMEM_FREE(enp->en_esip, size, dcfg);
584
585 fail1:
586 EFSYS_PROBE1(fail1, int, rc);
587
588 return (rc);
589 }
590
591 static __checkReturn int
siena_nvram_get_subtype(__in efx_nic_t * enp,__in unsigned int partn,__out uint32_t * subtypep)592 siena_nvram_get_subtype(
593 __in efx_nic_t *enp,
594 __in unsigned int partn,
595 __out uint32_t *subtypep)
596 {
597 efx_mcdi_req_t req;
598 uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX];
599 efx_word_t *fw_list;
600 int rc;
601
602 req.emr_cmd = MC_CMD_GET_BOARD_CFG;
603 EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0);
604 req.emr_in_buf = NULL;
605 req.emr_in_length = 0;
606 req.emr_out_buf = outbuf;
607 req.emr_out_length = sizeof (outbuf);
608
609 efx_mcdi_execute(enp, &req);
610
611 if (req.emr_rc != 0) {
612 rc = req.emr_rc;
613 goto fail1;
614 }
615
616 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
617 rc = EMSGSIZE;
618 goto fail2;
619 }
620
621 if (req.emr_out_length_used <
622 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST +
623 (partn + 1) * sizeof (efx_word_t)) {
624 rc = ENOENT;
625 goto fail3;
626 }
627
628 fw_list = MCDI_OUT2(req, efx_word_t,
629 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
630 *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0);
631
632 return (0);
633
634 fail3:
635 EFSYS_PROBE(fail3);
636 fail2:
637 EFSYS_PROBE(fail2);
638 fail1:
639 EFSYS_PROBE1(fail1, int, rc);
640
641 return (rc);
642 }
643
644 __checkReturn int
645 siena_nvram_get_version(
646 __in efx_nic_t *enp,
647 __in efx_nvram_type_t type,
648 __out uint32_t *subtypep,
649 __out_ecount(4) uint16_t version[4])
650 {
651 siena_mc_dynamic_config_hdr_t *dcfg;
652 siena_parttbl_entry_t *entry;
653 unsigned int dcfg_partn;
654 unsigned int partn;
655 int rc;
656
657 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
658 rc = ENOTSUP;
659 goto fail1;
660 }
661 partn = entry->partn;
662
663 if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
664 rc = ENOTSUP;
665 goto fail2;
666 }
667
668 if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0)
669 goto fail3;
670
671 /*
672 * Some partitions are accessible from both ports (for instance BOOTROM)
673 * Find the highest version reported by all dcfg structures on ports
674 * that have access to this partition.
675 */
676 version[0] = version[1] = version[2] = version[3] = 0;
677 for (entry = siena_parttbl; entry->port > 0; ++entry) {
678 unsigned int nitems;
679 uint16_t temp[4];
680 size_t length;
681
682 if (entry->partn != partn)
683 continue;
684
685 dcfg_partn = (entry->port == 1)
686 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
687 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
688 /*
689 * Ingore missing partitions on port 2, assuming they're due
690 * to to running on a single port part.
691 */
692 if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) {
693 if (entry->port == 2)
694 continue;
695 }
696
697 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
698 B_FALSE, &dcfg, &length)) != 0)
699 goto fail4;
700
701 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items,
702 EFX_DWORD_0);
703 if (nitems < entry->partn)
704 goto done;
705
706 temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w,
707 EFX_WORD_0);
708 temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x,
709 EFX_WORD_0);
710 temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y,
711 EFX_WORD_0);
712 temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z,
713 EFX_WORD_0);
714 if (memcmp(version, temp, sizeof (temp)) < 0)
715 memcpy(version, temp, sizeof (temp));
716
717 done:
718 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
719 }
720
721 return (0);
722
723 fail4:
724 EFSYS_PROBE(fail4);
725 fail3:
726 EFSYS_PROBE(fail3);
727 fail2:
728 EFSYS_PROBE(fail2);
729 fail1:
730 EFSYS_PROBE1(fail1, int, rc);
731
732 return (rc);
733 }
734
735 __checkReturn int
siena_nvram_rw_start(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out size_t * chunk_sizep)736 siena_nvram_rw_start(
737 __in efx_nic_t *enp,
738 __in efx_nvram_type_t type,
739 __out size_t *chunk_sizep)
740 {
741 siena_parttbl_entry_t *entry;
742 int rc;
743
744 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
745 rc = ENOTSUP;
746 goto fail1;
747 }
748
749 if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0)
750 goto fail2;
751
752 if (chunk_sizep != NULL)
753 *chunk_sizep = SIENA_NVRAM_CHUNK;
754
755 return (0);
756
757 fail2:
758 EFSYS_PROBE(fail2);
759 fail1:
760 EFSYS_PROBE1(fail1, int, rc);
761
762 return (rc);
763 }
764
765 __checkReturn int
siena_nvram_read_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)766 siena_nvram_read_chunk(
767 __in efx_nic_t *enp,
768 __in efx_nvram_type_t type,
769 __in unsigned int offset,
770 __out_bcount(size) caddr_t data,
771 __in size_t size)
772 {
773 siena_parttbl_entry_t *entry;
774 int rc;
775
776 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
777 rc = ENOTSUP;
778 goto fail1;
779 }
780
781 if ((rc = siena_nvram_partn_read(enp, entry->partn,
782 offset, data, size)) != 0)
783 goto fail2;
784
785 return (0);
786
787 fail2:
788 EFSYS_PROBE(fail2);
789 fail1:
790 EFSYS_PROBE1(fail1, int, rc);
791
792 return (rc);
793 }
794
795 __checkReturn int
siena_nvram_erase(__in efx_nic_t * enp,__in efx_nvram_type_t type)796 siena_nvram_erase(
797 __in efx_nic_t *enp,
798 __in efx_nvram_type_t type)
799 {
800 siena_parttbl_entry_t *entry;
801 size_t size;
802 int rc;
803
804 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
805 rc = ENOTSUP;
806 goto fail1;
807 }
808
809 if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0)
810 goto fail2;
811
812 if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0)
813 goto fail3;
814
815 return (0);
816
817 fail3:
818 EFSYS_PROBE(fail3);
819 fail2:
820 EFSYS_PROBE(fail2);
821 fail1:
822 EFSYS_PROBE1(fail1, int, rc);
823
824 return (rc);
825 }
826
827 __checkReturn int
siena_nvram_write_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__in_bcount (size)caddr_t data,__in size_t size)828 siena_nvram_write_chunk(
829 __in efx_nic_t *enp,
830 __in efx_nvram_type_t type,
831 __in unsigned int offset,
832 __in_bcount(size) caddr_t data,
833 __in size_t size)
834 {
835 siena_parttbl_entry_t *entry;
836 int rc;
837
838 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
839 rc = ENOTSUP;
840 goto fail1;
841 }
842
843 if ((rc = siena_nvram_partn_write(enp, entry->partn,
844 offset, data, size)) != 0)
845 goto fail2;
846
847 return (0);
848
849 fail2:
850 EFSYS_PROBE(fail2);
851 fail1:
852 EFSYS_PROBE1(fail1, int, rc);
853
854 return (rc);
855 }
856
857 void
siena_nvram_rw_finish(__in efx_nic_t * enp,__in efx_nvram_type_t type)858 siena_nvram_rw_finish(
859 __in efx_nic_t *enp,
860 __in efx_nvram_type_t type)
861 {
862 siena_parttbl_entry_t *entry;
863
864 if ((entry = siena_parttbl_entry(enp, type)) != NULL)
865 siena_nvram_partn_unlock(enp, entry->partn);
866 }
867
868 __checkReturn int
siena_nvram_set_version(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out uint16_t version[4])869 siena_nvram_set_version(
870 __in efx_nic_t *enp,
871 __in efx_nvram_type_t type,
872 __out uint16_t version[4])
873 {
874 siena_mc_dynamic_config_hdr_t *dcfg = NULL;
875 siena_parttbl_entry_t *entry;
876 unsigned int dcfg_partn;
877 size_t partn_size;
878 unsigned int hdr_length;
879 unsigned int vpd_length;
880 unsigned int vpd_offset;
881 unsigned int nitems;
882 unsigned int required_hdr_length;
883 unsigned int pos;
884 uint8_t cksum;
885 uint32_t subtype;
886 size_t length;
887 int rc;
888
889 if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
890 rc = ENOTSUP;
891 goto fail1;
892 }
893
894 dcfg_partn = (entry->port == 1)
895 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
896 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
897
898 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
899 goto fail2;
900
901 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
902 goto fail2;
903
904 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
905 B_TRUE, &dcfg, &length)) != 0)
906 goto fail3;
907
908 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
909 nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
910 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
911 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
912
913 /*
914 * NOTE: This function will blatt any fields trailing the version
915 * vector, or the VPD chunk.
916 */
917 required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1);
918 if (required_hdr_length + vpd_length > length) {
919 rc = ENOSPC;
920 goto fail4;
921 }
922
923 if (vpd_offset < required_hdr_length) {
924 (void) memmove((caddr_t)dcfg + required_hdr_length,
925 (caddr_t)dcfg + vpd_offset, vpd_length);
926 vpd_offset = required_hdr_length;
927 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
928 EFX_DWORD_0, vpd_offset);
929 }
930
931 if (hdr_length < required_hdr_length) {
932 (void) memset((caddr_t)dcfg + hdr_length, 0,
933 required_hdr_length - hdr_length);
934 hdr_length = required_hdr_length;
935 EFX_POPULATE_WORD_1(dcfg->length,
936 EFX_WORD_0, hdr_length);
937 }
938
939 /* Get the subtype to insert into the fw_subtype array */
940 if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0)
941 goto fail5;
942
943 /* Fill out the new version */
944 EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype,
945 EFX_DWORD_0, subtype);
946 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w,
947 EFX_WORD_0, version[0]);
948 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x,
949 EFX_WORD_0, version[1]);
950 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y,
951 EFX_WORD_0, version[2]);
952 EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z,
953 EFX_WORD_0, version[3]);
954
955 /* Update the version count */
956 if (nitems < entry->partn + 1) {
957 nitems = entry->partn + 1;
958 EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items,
959 EFX_DWORD_0, nitems);
960 }
961
962 /* Update the checksum */
963 cksum = 0;
964 for (pos = 0; pos < hdr_length; pos++)
965 cksum += ((uint8_t *)dcfg)[pos];
966 dcfg->csum.eb_u8[0] -= cksum;
967
968 /* Erase and write the new partition */
969 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
970 goto fail6;
971
972 /* Write out the new structure to nvram */
973 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0,
974 (caddr_t)dcfg, vpd_offset + vpd_length)) != 0)
975 goto fail7;
976
977 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
978
979 siena_nvram_partn_unlock(enp, dcfg_partn);
980
981 return (0);
982
983 fail7:
984 EFSYS_PROBE(fail7);
985 fail6:
986 EFSYS_PROBE(fail6);
987 fail5:
988 EFSYS_PROBE(fail5);
989 fail4:
990 EFSYS_PROBE(fail4);
991
992 EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
993 fail3:
994 EFSYS_PROBE(fail3);
995 fail2:
996 EFSYS_PROBE(fail2);
997 fail1:
998 EFSYS_PROBE1(fail1, int, rc);
999
1000 return (rc);
1001 }
1002
1003 #endif /* EFSYS_OPT_NVRAM */
1004
1005 #endif /* EFSYS_OPT_SIENA */
1006