aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/mtd.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-11-27 23:38:14 -0500
committerBen Hutchings <bhutchings@solarflare.com>2013-08-27 17:25:21 -0400
commit45a3fd55acc8989ff93d469e57b123cd3702a948 (patch)
tree39c1d3c5fdd95182b6832b2b7e27b765f4f97575 /drivers/net/ethernet/sfc/mtd.c
parent141d748e70a22629ef1e1823f88b3d5741ac38af (diff)
sfc: Move MTD operations into efx_nic_type
Merge the per-NIC-type MTD probe selection and struct efx_mtd_ops into struct efx_nic_type. Move the implementations into the appropriate source files. Several NVRAM functions are now only called from MTD operations which are now implemented in the same file (falcon.c or mcdi.c). There is no need for them to be extern, or to be defined at all if CONFIG_SFC_MTD is not enabled, so move them into the #ifdef CONFIG_SFC_MTD sections in those files. Most of the SPI-related definitions are also only used in falcon.c, so move them there. Put the remainder of spi.h into nic.h (which previously included it). Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet/sfc/mtd.c')
-rw-r--r--drivers/net/ethernet/sfc/mtd.c564
1 files changed, 8 insertions, 556 deletions
diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c
index f5819c746e7a..8be9a69a61e1 100644
--- a/drivers/net/ethernet/sfc/mtd.c
+++ b/drivers/net/ethernet/sfc/mtd.c
@@ -8,167 +8,17 @@
8 * by the Free Software Foundation, incorporated herein by reference. 8 * by the Free Software Foundation, incorporated herein by reference.
9 */ 9 */
10 10
11#include <linux/bitops.h>
12#include <linux/module.h> 11#include <linux/module.h>
13#include <linux/mtd/mtd.h> 12#include <linux/mtd/mtd.h>
14#include <linux/delay.h>
15#include <linux/slab.h> 13#include <linux/slab.h>
16#include <linux/rtnetlink.h> 14#include <linux/rtnetlink.h>
17 15
18#include "net_driver.h" 16#include "net_driver.h"
19#include "spi.h"
20#include "efx.h" 17#include "efx.h"
21#include "nic.h"
22#include "mcdi.h"
23#include "mcdi_pcol.h"
24
25#define FALCON_SPI_VERIFY_BUF_LEN 16
26
27struct efx_mtd_partition {
28 struct list_head node;
29 struct mtd_info mtd;
30 const char *dev_type_name;
31 const char *type_name;
32 char name[IFNAMSIZ + 20];
33};
34
35struct falcon_mtd_partition {
36 struct efx_mtd_partition common;
37 const struct falcon_spi_device *spi;
38 size_t offset;
39};
40
41struct efx_mtd_ops {
42 void (*rename)(struct efx_mtd_partition *part);
43 int (*read)(struct mtd_info *mtd, loff_t start, size_t len,
44 size_t *retlen, u8 *buffer);
45 int (*erase)(struct mtd_info *mtd, loff_t start, size_t len);
46 int (*write)(struct mtd_info *mtd, loff_t start, size_t len,
47 size_t *retlen, const u8 *buffer);
48 int (*sync)(struct mtd_info *mtd);
49};
50 18
51#define to_efx_mtd_partition(mtd) \ 19#define to_efx_mtd_partition(mtd) \
52 container_of(mtd, struct efx_mtd_partition, mtd) 20 container_of(mtd, struct efx_mtd_partition, mtd)
53 21
54#define to_falcon_mtd_partition(mtd) \
55 container_of(mtd, struct falcon_mtd_partition, common.mtd)
56
57static int falcon_mtd_probe(struct efx_nic *efx);
58static int siena_mtd_probe(struct efx_nic *efx);
59
60/* SPI utilities */
61
62static int
63falcon_spi_slow_wait(struct falcon_mtd_partition *part, bool uninterruptible)
64{
65 const struct falcon_spi_device *spi = part->spi;
66 struct efx_nic *efx = part->common.mtd.priv;
67 u8 status;
68 int rc, i;
69
70 /* Wait up to 4s for flash/EEPROM to finish a slow operation. */
71 for (i = 0; i < 40; i++) {
72 __set_current_state(uninterruptible ?
73 TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
74 schedule_timeout(HZ / 10);
75 rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
76 &status, sizeof(status));
77 if (rc)
78 return rc;
79 if (!(status & SPI_STATUS_NRDY))
80 return 0;
81 if (signal_pending(current))
82 return -EINTR;
83 }
84 pr_err("%s: timed out waiting for %s\n",
85 part->common.name, part->common.dev_type_name);
86 return -ETIMEDOUT;
87}
88
89static int
90falcon_spi_unlock(struct efx_nic *efx, const struct falcon_spi_device *spi)
91{
92 const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
93 SPI_STATUS_BP0);
94 u8 status;
95 int rc;
96
97 rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
98 &status, sizeof(status));
99 if (rc)
100 return rc;
101
102 if (!(status & unlock_mask))
103 return 0; /* already unlocked */
104
105 rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
106 if (rc)
107 return rc;
108 rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
109 if (rc)
110 return rc;
111
112 status &= ~unlock_mask;
113 rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status,
114 NULL, sizeof(status));
115 if (rc)
116 return rc;
117 rc = falcon_spi_wait_write(efx, spi);
118 if (rc)
119 return rc;
120
121 return 0;
122}
123
124static int
125falcon_spi_erase(struct falcon_mtd_partition *part, loff_t start, size_t len)
126{
127 const struct falcon_spi_device *spi = part->spi;
128 struct efx_nic *efx = part->common.mtd.priv;
129 unsigned pos, block_len;
130 u8 empty[FALCON_SPI_VERIFY_BUF_LEN];
131 u8 buffer[FALCON_SPI_VERIFY_BUF_LEN];
132 int rc;
133
134 if (len != spi->erase_size)
135 return -EINVAL;
136
137 if (spi->erase_command == 0)
138 return -EOPNOTSUPP;
139
140 rc = falcon_spi_unlock(efx, spi);
141 if (rc)
142 return rc;
143 rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
144 if (rc)
145 return rc;
146 rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL,
147 NULL, 0);
148 if (rc)
149 return rc;
150 rc = falcon_spi_slow_wait(part, false);
151
152 /* Verify the entire region has been wiped */
153 memset(empty, 0xff, sizeof(empty));
154 for (pos = 0; pos < len; pos += block_len) {
155 block_len = min(len - pos, sizeof(buffer));
156 rc = falcon_spi_read(efx, spi, start + pos, block_len,
157 NULL, buffer);
158 if (rc)
159 return rc;
160 if (memcmp(empty, buffer, block_len))
161 return -EIO;
162
163 /* Avoid locking up the system */
164 cond_resched();
165 if (signal_pending(current))
166 return -EINTR;
167 }
168
169 return rc;
170}
171
172/* MTD interface */ 22/* MTD interface */
173 23
174static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) 24static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
@@ -176,7 +26,7 @@ static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
176 struct efx_nic *efx = mtd->priv; 26 struct efx_nic *efx = mtd->priv;
177 int rc; 27 int rc;
178 28
179 rc = efx->mtd_ops->erase(mtd, erase->addr, erase->len); 29 rc = efx->type->mtd_erase(mtd, erase->addr, erase->len);
180 if (rc == 0) { 30 if (rc == 0) {
181 erase->state = MTD_ERASE_DONE; 31 erase->state = MTD_ERASE_DONE;
182 } else { 32 } else {
@@ -193,7 +43,7 @@ static void efx_mtd_sync(struct mtd_info *mtd)
193 struct efx_nic *efx = mtd->priv; 43 struct efx_nic *efx = mtd->priv;
194 int rc; 44 int rc;
195 45
196 rc = efx->mtd_ops->sync(mtd); 46 rc = efx->type->mtd_sync(mtd);
197 if (rc) 47 if (rc)
198 pr_err("%s: %s sync failed (%d)\n", 48 pr_err("%s: %s sync failed (%d)\n",
199 part->name, part->dev_type_name, rc); 49 part->name, part->dev_type_name, rc);
@@ -213,15 +63,8 @@ static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
213 list_del(&part->node); 63 list_del(&part->node);
214} 64}
215 65
216static void efx_mtd_rename_partition(struct efx_mtd_partition *part) 66int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
217{ 67 size_t n_parts, size_t sizeof_part)
218 struct efx_nic *efx = part->mtd.priv;
219
220 efx->mtd_ops->rename(part);
221}
222
223static int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
224 size_t n_parts, size_t sizeof_part)
225{ 68{
226 struct efx_mtd_partition *part; 69 struct efx_mtd_partition *part;
227 size_t i; 70 size_t i;
@@ -236,11 +79,11 @@ static int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
236 part->mtd.priv = efx; 79 part->mtd.priv = efx;
237 part->mtd.name = part->name; 80 part->mtd.name = part->name;
238 part->mtd._erase = efx_mtd_erase; 81 part->mtd._erase = efx_mtd_erase;
239 part->mtd._read = efx->mtd_ops->read; 82 part->mtd._read = efx->type->mtd_read;
240 part->mtd._write = efx->mtd_ops->write; 83 part->mtd._write = efx->type->mtd_write;
241 part->mtd._sync = efx_mtd_sync; 84 part->mtd._sync = efx_mtd_sync;
242 85
243 efx_mtd_rename_partition(part); 86 efx->type->mtd_rename(part);
244 87
245 if (mtd_device_register(&part->mtd, NULL, 0)) 88 if (mtd_device_register(&part->mtd, NULL, 0))
246 goto fail; 89 goto fail;
@@ -286,396 +129,5 @@ void efx_mtd_rename(struct efx_nic *efx)
286 ASSERT_RTNL(); 129 ASSERT_RTNL();
287 130
288 list_for_each_entry(part, &efx->mtd_list, node) 131 list_for_each_entry(part, &efx->mtd_list, node)
289 efx_mtd_rename_partition(part); 132 efx->type->mtd_rename(part);
290}
291
292int efx_mtd_probe(struct efx_nic *efx)
293{
294 if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
295 return siena_mtd_probe(efx);
296 else
297 return falcon_mtd_probe(efx);
298}
299
300/* Implementation of MTD operations for Falcon */
301
302static void falcon_mtd_rename(struct efx_mtd_partition *part)
303{
304 struct efx_nic *efx = part->mtd.priv;
305
306 snprintf(part->name, sizeof(part->name), "%s %s",
307 efx->name, part->type_name);
308}
309
310static int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
311 size_t len, size_t *retlen, u8 *buffer)
312{
313 struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
314 struct efx_nic *efx = mtd->priv;
315 struct falcon_nic_data *nic_data = efx->nic_data;
316 int rc;
317
318 rc = mutex_lock_interruptible(&nic_data->spi_lock);
319 if (rc)
320 return rc;
321 rc = falcon_spi_read(efx, part->spi, part->offset + start,
322 len, retlen, buffer);
323 mutex_unlock(&nic_data->spi_lock);
324 return rc;
325}
326
327static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
328{
329 struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
330 struct efx_nic *efx = mtd->priv;
331 struct falcon_nic_data *nic_data = efx->nic_data;
332 int rc;
333
334 rc = mutex_lock_interruptible(&nic_data->spi_lock);
335 if (rc)
336 return rc;
337 rc = falcon_spi_erase(part, part->offset + start, len);
338 mutex_unlock(&nic_data->spi_lock);
339 return rc;
340}
341
342static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
343 size_t len, size_t *retlen, const u8 *buffer)
344{
345 struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
346 struct efx_nic *efx = mtd->priv;
347 struct falcon_nic_data *nic_data = efx->nic_data;
348 int rc;
349
350 rc = mutex_lock_interruptible(&nic_data->spi_lock);
351 if (rc)
352 return rc;
353 rc = falcon_spi_write(efx, part->spi, part->offset + start,
354 len, retlen, buffer);
355 mutex_unlock(&nic_data->spi_lock);
356 return rc;
357}
358
359static int falcon_mtd_sync(struct mtd_info *mtd)
360{
361 struct falcon_mtd_partition *part = to_falcon_mtd_partition(mtd);
362 struct efx_nic *efx = mtd->priv;
363 struct falcon_nic_data *nic_data = efx->nic_data;
364 int rc;
365
366 mutex_lock(&nic_data->spi_lock);
367 rc = falcon_spi_slow_wait(part, true);
368 mutex_unlock(&nic_data->spi_lock);
369 return rc;
370}
371
372static const struct efx_mtd_ops falcon_mtd_ops = {
373 .rename = falcon_mtd_rename,
374 .read = falcon_mtd_read,
375 .erase = falcon_mtd_erase,
376 .write = falcon_mtd_write,
377 .sync = falcon_mtd_sync,
378};
379
380static int falcon_mtd_probe(struct efx_nic *efx)
381{
382 struct falcon_nic_data *nic_data = efx->nic_data;
383 struct falcon_mtd_partition *parts;
384 struct falcon_spi_device *spi;
385 size_t n_parts;
386 int rc = -ENODEV;
387
388 ASSERT_RTNL();
389
390 efx->mtd_ops = &falcon_mtd_ops;
391
392 /* Allocate space for maximum number of partitions */
393 parts = kcalloc(2, sizeof(*parts), GFP_KERNEL);
394 n_parts = 0;
395
396 spi = &nic_data->spi_flash;
397 if (falcon_spi_present(spi) && spi->size > FALCON_FLASH_BOOTCODE_START) {
398 parts[n_parts].spi = spi;
399 parts[n_parts].offset = FALCON_FLASH_BOOTCODE_START;
400 parts[n_parts].common.dev_type_name = "flash";
401 parts[n_parts].common.type_name = "sfc_flash_bootrom";
402 parts[n_parts].common.mtd.type = MTD_NORFLASH;
403 parts[n_parts].common.mtd.flags = MTD_CAP_NORFLASH;
404 parts[n_parts].common.mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
405 parts[n_parts].common.mtd.erasesize = spi->erase_size;
406 n_parts++;
407 }
408
409 spi = &nic_data->spi_eeprom;
410 if (falcon_spi_present(spi) && spi->size > FALCON_EEPROM_BOOTCONFIG_START) {
411 parts[n_parts].spi = spi;
412 parts[n_parts].offset = FALCON_EEPROM_BOOTCONFIG_START;
413 parts[n_parts].common.dev_type_name = "EEPROM";
414 parts[n_parts].common.type_name = "sfc_bootconfig";
415 parts[n_parts].common.mtd.type = MTD_RAM;
416 parts[n_parts].common.mtd.flags = MTD_CAP_RAM;
417 parts[n_parts].common.mtd.size =
418 min(spi->size, FALCON_EEPROM_BOOTCONFIG_END) -
419 FALCON_EEPROM_BOOTCONFIG_START;
420 parts[n_parts].common.mtd.erasesize = spi->erase_size;
421 n_parts++;
422 }
423
424 rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts));
425 if (rc)
426 kfree(parts);
427 return rc;
428}
429
430/* Implementation of MTD operations for Siena */
431
432struct efx_mcdi_mtd_partition {
433 struct efx_mtd_partition common;
434 bool updating;
435 u8 nvram_type;
436 u16 fw_subtype;
437};
438
439#define to_efx_mcdi_mtd_partition(mtd) \
440 container_of(mtd, struct efx_mcdi_mtd_partition, common.mtd)
441
442static void siena_mtd_rename(struct efx_mtd_partition *part)
443{
444 struct efx_mcdi_mtd_partition *mcdi_part =
445 container_of(part, struct efx_mcdi_mtd_partition, common);
446 struct efx_nic *efx = part->mtd.priv;
447
448 snprintf(part->name, sizeof(part->name), "%s %s:%02x",
449 efx->name, part->type_name, mcdi_part->fw_subtype);
450}
451
452static int siena_mtd_read(struct mtd_info *mtd, loff_t start,
453 size_t len, size_t *retlen, u8 *buffer)
454{
455 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
456 struct efx_nic *efx = mtd->priv;
457 loff_t offset = start;
458 loff_t end = min_t(loff_t, start + len, mtd->size);
459 size_t chunk;
460 int rc = 0;
461
462 while (offset < end) {
463 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
464 rc = efx_mcdi_nvram_read(efx, part->nvram_type, offset,
465 buffer, chunk);
466 if (rc)
467 goto out;
468 offset += chunk;
469 buffer += chunk;
470 }
471out:
472 *retlen = offset - start;
473 return rc;
474}
475
476static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
477{
478 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
479 struct efx_nic *efx = mtd->priv;
480 loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
481 loff_t end = min_t(loff_t, start + len, mtd->size);
482 size_t chunk = part->common.mtd.erasesize;
483 int rc = 0;
484
485 if (!part->updating) {
486 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
487 if (rc)
488 goto out;
489 part->updating = true;
490 }
491
492 /* The MCDI interface can in fact do multiple erase blocks at once;
493 * but erasing may be slow, so we make multiple calls here to avoid
494 * tripping the MCDI RPC timeout. */
495 while (offset < end) {
496 rc = efx_mcdi_nvram_erase(efx, part->nvram_type, offset,
497 chunk);
498 if (rc)
499 goto out;
500 offset += chunk;
501 }
502out:
503 return rc;
504}
505
506static int siena_mtd_write(struct mtd_info *mtd, loff_t start,
507 size_t len, size_t *retlen, const u8 *buffer)
508{
509 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
510 struct efx_nic *efx = mtd->priv;
511 loff_t offset = start;
512 loff_t end = min_t(loff_t, start + len, mtd->size);
513 size_t chunk;
514 int rc = 0;
515
516 if (!part->updating) {
517 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
518 if (rc)
519 goto out;
520 part->updating = true;
521 }
522
523 while (offset < end) {
524 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
525 rc = efx_mcdi_nvram_write(efx, part->nvram_type, offset,
526 buffer, chunk);
527 if (rc)
528 goto out;
529 offset += chunk;
530 buffer += chunk;
531 }
532out:
533 *retlen = offset - start;
534 return rc;
535}
536
537static int siena_mtd_sync(struct mtd_info *mtd)
538{
539 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
540 struct efx_nic *efx = mtd->priv;
541 int rc = 0;
542
543 if (part->updating) {
544 part->updating = false;
545 rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
546 }
547
548 return rc;
549} 133}
550
551static const struct efx_mtd_ops siena_mtd_ops = {
552 .rename = siena_mtd_rename,
553 .read = siena_mtd_read,
554 .erase = siena_mtd_erase,
555 .write = siena_mtd_write,
556 .sync = siena_mtd_sync,
557};
558
559struct siena_nvram_type_info {
560 int port;
561 const char *name;
562};
563
564static const struct siena_nvram_type_info siena_nvram_types[] = {
565 [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" },
566 [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" },
567 [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" },
568 [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" },
569 [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" },
570 [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" },
571 [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" },
572 [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" },
573 [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" },
574 [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" },
575 [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" },
576 [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" },
577 [MC_CMD_NVRAM_TYPE_FPGA] = { 0, "sfc_fpga" },
578};
579
580static int siena_mtd_probe_partition(struct efx_nic *efx,
581 struct efx_mcdi_mtd_partition *part,
582 unsigned int type)
583{
584 const struct siena_nvram_type_info *info;
585 size_t size, erase_size;
586 bool protected;
587 int rc;
588
589 if (type >= ARRAY_SIZE(siena_nvram_types) ||
590 siena_nvram_types[type].name == NULL)
591 return -ENODEV;
592
593 info = &siena_nvram_types[type];
594
595 if (info->port != efx_port_num(efx))
596 return -ENODEV;
597
598 rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
599 if (rc)
600 return rc;
601 if (protected)
602 return -ENODEV; /* hide it */
603
604 part->nvram_type = type;
605 part->common.dev_type_name = "Siena NVRAM manager";
606 part->common.type_name = info->name;
607
608 part->common.mtd.type = MTD_NORFLASH;
609 part->common.mtd.flags = MTD_CAP_NORFLASH;
610 part->common.mtd.size = size;
611 part->common.mtd.erasesize = erase_size;
612
613 return 0;
614}
615
616static int siena_mtd_get_fw_subtypes(struct efx_nic *efx,
617 struct efx_mcdi_mtd_partition *parts,
618 size_t n_parts)
619{
620 uint16_t fw_subtype_list[
621 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM];
622 size_t i;
623 int rc;
624
625 rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list, NULL);
626 if (rc)
627 return rc;
628
629 for (i = 0; i < n_parts; i++)
630 parts[i].fw_subtype = fw_subtype_list[parts[i].nvram_type];
631
632 return 0;
633}
634
635static int siena_mtd_probe(struct efx_nic *efx)
636{
637 struct efx_mcdi_mtd_partition *parts;
638 u32 nvram_types;
639 unsigned int type;
640 size_t n_parts;
641 int rc;
642
643 ASSERT_RTNL();
644
645 efx->mtd_ops = &siena_mtd_ops;
646
647 rc = efx_mcdi_nvram_types(efx, &nvram_types);
648 if (rc)
649 return rc;
650
651 parts = kcalloc(hweight32(nvram_types), sizeof(*parts), GFP_KERNEL);
652 if (!parts)
653 return -ENOMEM;
654
655 type = 0;
656 n_parts = 0;
657
658 while (nvram_types != 0) {
659 if (nvram_types & 1) {
660 rc = siena_mtd_probe_partition(efx, &parts[n_parts],
661 type);
662 if (rc == 0)
663 n_parts++;
664 else if (rc != -ENODEV)
665 goto fail;
666 }
667 type++;
668 nvram_types >>= 1;
669 }
670
671 rc = siena_mtd_get_fw_subtypes(efx, parts, n_parts);
672 if (rc)
673 goto fail;
674
675 rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts));
676fail:
677 if (rc)
678 kfree(parts);
679 return rc;
680}
681