blob: ba6c87a73d86efd5c8a52aa473c191a0de9660ab [file] [log] [blame]
Ben Hutchingsf4150722008-11-04 20:34:28 +00001/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2005-2006 Fen Systems Ltd.
Ben Hutchings0a6f40c2011-02-25 00:01:34 +00004 * Copyright 2006-2010 Solarflare Communications Inc.
Ben Hutchingsf4150722008-11-04 20:34:28 +00005 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation, incorporated herein by reference.
9 */
10
Ben Hutchings8880f4e2009-11-29 15:15:41 +000011#include <linux/bitops.h>
Ben Hutchingsf4150722008-11-04 20:34:28 +000012#include <linux/module.h>
13#include <linux/mtd/mtd.h>
14#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Ben Hutchings76884832009-11-29 15:10:44 +000016#include <linux/rtnetlink.h>
Ben Hutchingsf4150722008-11-04 20:34:28 +000017
Ben Hutchingsf4150722008-11-04 20:34:28 +000018#include "net_driver.h"
19#include "spi.h"
Hannes Ederff2ef902009-02-18 17:49:50 -080020#include "efx.h"
Ben Hutchings744093c2009-11-29 15:12:08 +000021#include "nic.h"
Ben Hutchings8880f4e2009-11-29 15:15:41 +000022#include "mcdi.h"
23#include "mcdi_pcol.h"
Ben Hutchingsf4150722008-11-04 20:34:28 +000024
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +000025#define FALCON_SPI_VERIFY_BUF_LEN 16
Ben Hutchingsf4150722008-11-04 20:34:28 +000026
Ben Hutchings76884832009-11-29 15:10:44 +000027struct efx_mtd_partition {
Ben Hutchingsb7666302012-11-28 04:38:10 +000028 struct list_head node;
Ben Hutchingsf4150722008-11-04 20:34:28 +000029 struct mtd_info mtd;
Ben Hutchings8880f4e2009-11-29 15:15:41 +000030 union {
31 struct {
32 bool updating;
33 u8 nvram_type;
34 u16 fw_subtype;
35 } mcdi;
Ben Hutchingsb7666302012-11-28 04:38:10 +000036 struct {
37 const struct falcon_spi_device *spi;
38 size_t offset;
39 } falcon;
Ben Hutchings8880f4e2009-11-29 15:15:41 +000040 };
Ben Hutchingsb7666302012-11-28 04:38:10 +000041 const char *dev_type_name;
Ben Hutchings76884832009-11-29 15:10:44 +000042 const char *type_name;
Ben Hutchingsf4150722008-11-04 20:34:28 +000043 char name[IFNAMSIZ + 20];
44};
45
Ben Hutchings76884832009-11-29 15:10:44 +000046struct efx_mtd_ops {
47 int (*read)(struct mtd_info *mtd, loff_t start, size_t len,
48 size_t *retlen, u8 *buffer);
49 int (*erase)(struct mtd_info *mtd, loff_t start, size_t len);
50 int (*write)(struct mtd_info *mtd, loff_t start, size_t len,
51 size_t *retlen, const u8 *buffer);
52 int (*sync)(struct mtd_info *mtd);
53};
54
Ben Hutchings76884832009-11-29 15:10:44 +000055#define to_efx_mtd_partition(mtd) \
56 container_of(mtd, struct efx_mtd_partition, mtd)
57
58static int falcon_mtd_probe(struct efx_nic *efx);
Ben Hutchings8880f4e2009-11-29 15:15:41 +000059static int siena_mtd_probe(struct efx_nic *efx);
Ben Hutchings76884832009-11-29 15:10:44 +000060
Ben Hutchingsf4150722008-11-04 20:34:28 +000061/* SPI utilities */
62
Ben Hutchings0c605a22010-06-23 11:29:24 +000063static int
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +000064falcon_spi_slow_wait(struct efx_mtd_partition *part, bool uninterruptible)
Ben Hutchingsf4150722008-11-04 20:34:28 +000065{
Ben Hutchingsb7666302012-11-28 04:38:10 +000066 const struct falcon_spi_device *spi = part->falcon.spi;
67 struct efx_nic *efx = part->mtd.priv;
Ben Hutchingsf4150722008-11-04 20:34:28 +000068 u8 status;
69 int rc, i;
70
71 /* Wait up to 4s for flash/EEPROM to finish a slow operation. */
72 for (i = 0; i < 40; i++) {
73 __set_current_state(uninterruptible ?
74 TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
75 schedule_timeout(HZ / 10);
Ben Hutchings76884832009-11-29 15:10:44 +000076 rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
Ben Hutchingsf4150722008-11-04 20:34:28 +000077 &status, sizeof(status));
78 if (rc)
79 return rc;
80 if (!(status & SPI_STATUS_NRDY))
81 return 0;
82 if (signal_pending(current))
83 return -EINTR;
84 }
Ben Hutchingsb7666302012-11-28 04:38:10 +000085 pr_err("%s: timed out waiting for %s\n",
86 part->name, part->dev_type_name);
Ben Hutchingsf4150722008-11-04 20:34:28 +000087 return -ETIMEDOUT;
88}
89
Ben Hutchings76884832009-11-29 15:10:44 +000090static int
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +000091falcon_spi_unlock(struct efx_nic *efx, const struct falcon_spi_device *spi)
Ben Hutchingsf4150722008-11-04 20:34:28 +000092{
93 const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
94 SPI_STATUS_BP0);
95 u8 status;
96 int rc;
97
Ben Hutchings76884832009-11-29 15:10:44 +000098 rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
99 &status, sizeof(status));
Ben Hutchingsf4150722008-11-04 20:34:28 +0000100 if (rc)
101 return rc;
102
103 if (!(status & unlock_mask))
104 return 0; /* already unlocked */
105
Ben Hutchings76884832009-11-29 15:10:44 +0000106 rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000107 if (rc)
108 return rc;
Ben Hutchings76884832009-11-29 15:10:44 +0000109 rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000110 if (rc)
111 return rc;
112
113 status &= ~unlock_mask;
Ben Hutchings76884832009-11-29 15:10:44 +0000114 rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status,
115 NULL, sizeof(status));
Ben Hutchingsf4150722008-11-04 20:34:28 +0000116 if (rc)
117 return rc;
Ben Hutchings76884832009-11-29 15:10:44 +0000118 rc = falcon_spi_wait_write(efx, spi);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000119 if (rc)
120 return rc;
121
122 return 0;
123}
124
Ben Hutchings0c605a22010-06-23 11:29:24 +0000125static int
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000126falcon_spi_erase(struct efx_mtd_partition *part, loff_t start, size_t len)
Ben Hutchingsf4150722008-11-04 20:34:28 +0000127{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000128 const struct falcon_spi_device *spi = part->falcon.spi;
129 struct efx_nic *efx = part->mtd.priv;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000130 unsigned pos, block_len;
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000131 u8 empty[FALCON_SPI_VERIFY_BUF_LEN];
132 u8 buffer[FALCON_SPI_VERIFY_BUF_LEN];
Ben Hutchingsf4150722008-11-04 20:34:28 +0000133 int rc;
134
135 if (len != spi->erase_size)
136 return -EINVAL;
137
138 if (spi->erase_command == 0)
139 return -EOPNOTSUPP;
140
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000141 rc = falcon_spi_unlock(efx, spi);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000142 if (rc)
143 return rc;
Ben Hutchings76884832009-11-29 15:10:44 +0000144 rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000145 if (rc)
146 return rc;
Ben Hutchings76884832009-11-29 15:10:44 +0000147 rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL,
148 NULL, 0);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000149 if (rc)
150 return rc;
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000151 rc = falcon_spi_slow_wait(part, false);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000152
153 /* Verify the entire region has been wiped */
154 memset(empty, 0xff, sizeof(empty));
155 for (pos = 0; pos < len; pos += block_len) {
156 block_len = min(len - pos, sizeof(buffer));
Ben Hutchings76884832009-11-29 15:10:44 +0000157 rc = falcon_spi_read(efx, spi, start + pos, block_len,
158 NULL, buffer);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000159 if (rc)
160 return rc;
161 if (memcmp(empty, buffer, block_len))
162 return -EIO;
163
164 /* Avoid locking up the system */
165 cond_resched();
166 if (signal_pending(current))
167 return -EINTR;
168 }
169
170 return rc;
171}
172
173/* MTD interface */
174
Ben Hutchingsf4150722008-11-04 20:34:28 +0000175static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
176{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000177 struct efx_nic *efx = mtd->priv;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000178 int rc;
179
Ben Hutchingsb7666302012-11-28 04:38:10 +0000180 rc = efx->mtd_ops->erase(mtd, erase->addr, erase->len);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000181 if (rc == 0) {
182 erase->state = MTD_ERASE_DONE;
183 } else {
184 erase->state = MTD_ERASE_FAILED;
Shmulik Ladkani88dfda52012-02-12 11:13:08 +0200185 erase->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000186 }
187 mtd_erase_callback(erase);
188 return rc;
189}
190
Ben Hutchings76884832009-11-29 15:10:44 +0000191static void efx_mtd_sync(struct mtd_info *mtd)
Ben Hutchingsf4150722008-11-04 20:34:28 +0000192{
Ben Hutchings0c605a22010-06-23 11:29:24 +0000193 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000194 struct efx_nic *efx = mtd->priv;
Ben Hutchings76884832009-11-29 15:10:44 +0000195 int rc;
196
Ben Hutchingsb7666302012-11-28 04:38:10 +0000197 rc = efx->mtd_ops->sync(mtd);
Ben Hutchings76884832009-11-29 15:10:44 +0000198 if (rc)
Ben Hutchings0c605a22010-06-23 11:29:24 +0000199 pr_err("%s: %s sync failed (%d)\n",
Ben Hutchingsb7666302012-11-28 04:38:10 +0000200 part->name, part->dev_type_name, rc);
Ben Hutchings76884832009-11-29 15:10:44 +0000201}
202
203static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
204{
205 int rc;
206
207 for (;;) {
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100208 rc = mtd_device_unregister(&part->mtd);
Ben Hutchings76884832009-11-29 15:10:44 +0000209 if (rc != -EBUSY)
210 break;
211 ssleep(1);
212 }
213 WARN_ON(rc);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000214 list_del(&part->node);
Ben Hutchings76884832009-11-29 15:10:44 +0000215}
216
Ben Hutchingsb7666302012-11-28 04:38:10 +0000217static void efx_mtd_rename_partition(struct efx_mtd_partition *part)
Ben Hutchings76884832009-11-29 15:10:44 +0000218{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000219 struct efx_nic *efx = part->mtd.priv;
Ben Hutchings76884832009-11-29 15:10:44 +0000220
Ben Hutchingsb7666302012-11-28 04:38:10 +0000221 if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
222 snprintf(part->name, sizeof(part->name), "%s %s:%02x",
223 efx->name, part->type_name, part->mcdi.fw_subtype);
224 else
225 snprintf(part->name, sizeof(part->name), "%s %s",
226 efx->name, part->type_name);
Ben Hutchings76884832009-11-29 15:10:44 +0000227}
228
Ben Hutchingsb7666302012-11-28 04:38:10 +0000229static int efx_mtd_add(struct efx_nic *efx,
230 struct efx_mtd_partition *parts, size_t n_parts)
Ben Hutchings76884832009-11-29 15:10:44 +0000231{
232 struct efx_mtd_partition *part;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000233 size_t i;
Ben Hutchings76884832009-11-29 15:10:44 +0000234
Ben Hutchingsb7666302012-11-28 04:38:10 +0000235 for (i = 0; i < n_parts; i++) {
236 part = &parts[i];
Ben Hutchings76884832009-11-29 15:10:44 +0000237
Ben Hutchings76884832009-11-29 15:10:44 +0000238 part->mtd.writesize = 1;
239
240 part->mtd.owner = THIS_MODULE;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000241 part->mtd.priv = efx;
Ben Hutchings76884832009-11-29 15:10:44 +0000242 part->mtd.name = part->name;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +0200243 part->mtd._erase = efx_mtd_erase;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000244 part->mtd._read = efx->mtd_ops->read;
245 part->mtd._write = efx->mtd_ops->write;
Artem Bityutskiy3c3c10b2012-01-30 14:58:32 +0200246 part->mtd._sync = efx_mtd_sync;
Ben Hutchings76884832009-11-29 15:10:44 +0000247
Ben Hutchingsb7666302012-11-28 04:38:10 +0000248 efx_mtd_rename_partition(part);
249
Jamie Ilesee0e87b2011-05-23 10:23:40 +0100250 if (mtd_device_register(&part->mtd, NULL, 0))
Ben Hutchings76884832009-11-29 15:10:44 +0000251 goto fail;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000252
253 /* Add to list in order - efx_mtd_remove() depends on this */
254 list_add_tail(&part->node, &efx->mtd_list);
Ben Hutchings76884832009-11-29 15:10:44 +0000255 }
256
Ben Hutchings76884832009-11-29 15:10:44 +0000257 return 0;
258
259fail:
Ben Hutchingsb7666302012-11-28 04:38:10 +0000260 while (i--)
261 efx_mtd_remove_partition(&parts[i]);
Ben Hutchings7c431612012-01-27 17:23:58 +0000262 /* Failure is unlikely here, but probably means we're out of memory */
Ben Hutchings76884832009-11-29 15:10:44 +0000263 return -ENOMEM;
264}
265
266void efx_mtd_remove(struct efx_nic *efx)
267{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000268 struct efx_mtd_partition *parts, *part, *next;
Ben Hutchings76884832009-11-29 15:10:44 +0000269
270 WARN_ON(efx_dev_registered(efx));
271
Ben Hutchingsb7666302012-11-28 04:38:10 +0000272 if (list_empty(&efx->mtd_list))
273 return;
274
275 parts = list_first_entry(&efx->mtd_list, struct efx_mtd_partition,
276 node);
277
278 list_for_each_entry_safe(part, next, &efx->mtd_list, node)
279 efx_mtd_remove_partition(part);
280
281 kfree(parts);
Ben Hutchings76884832009-11-29 15:10:44 +0000282}
283
284void efx_mtd_rename(struct efx_nic *efx)
285{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000286 struct efx_mtd_partition *part;
Ben Hutchings76884832009-11-29 15:10:44 +0000287
288 ASSERT_RTNL();
289
Ben Hutchingsb7666302012-11-28 04:38:10 +0000290 list_for_each_entry(part, &efx->mtd_list, node)
291 efx_mtd_rename_partition(part);
Ben Hutchings76884832009-11-29 15:10:44 +0000292}
293
294int efx_mtd_probe(struct efx_nic *efx)
295{
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000296 if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
297 return siena_mtd_probe(efx);
298 else
299 return falcon_mtd_probe(efx);
Ben Hutchings76884832009-11-29 15:10:44 +0000300}
301
302/* Implementation of MTD operations for Falcon */
303
304static int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
305 size_t len, size_t *retlen, u8 *buffer)
306{
307 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000308 struct efx_nic *efx = mtd->priv;
Ben Hutchings4de92182010-12-02 13:47:29 +0000309 struct falcon_nic_data *nic_data = efx->nic_data;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000310 int rc;
311
Ben Hutchings4de92182010-12-02 13:47:29 +0000312 rc = mutex_lock_interruptible(&nic_data->spi_lock);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000313 if (rc)
314 return rc;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000315 rc = falcon_spi_read(efx, part->falcon.spi, part->falcon.offset + start,
316 len, retlen, buffer);
Ben Hutchings4de92182010-12-02 13:47:29 +0000317 mutex_unlock(&nic_data->spi_lock);
Ben Hutchingsf4150722008-11-04 20:34:28 +0000318 return rc;
319}
320
Ben Hutchings76884832009-11-29 15:10:44 +0000321static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
322{
323 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000324 struct efx_nic *efx = mtd->priv;
Ben Hutchings4de92182010-12-02 13:47:29 +0000325 struct falcon_nic_data *nic_data = efx->nic_data;
Ben Hutchings76884832009-11-29 15:10:44 +0000326 int rc;
327
Ben Hutchings4de92182010-12-02 13:47:29 +0000328 rc = mutex_lock_interruptible(&nic_data->spi_lock);
Ben Hutchings76884832009-11-29 15:10:44 +0000329 if (rc)
330 return rc;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000331 rc = falcon_spi_erase(part, part->falcon.offset + start, len);
Ben Hutchings4de92182010-12-02 13:47:29 +0000332 mutex_unlock(&nic_data->spi_lock);
Ben Hutchings76884832009-11-29 15:10:44 +0000333 return rc;
334}
335
336static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
337 size_t len, size_t *retlen, const u8 *buffer)
338{
339 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000340 struct efx_nic *efx = mtd->priv;
Ben Hutchings4de92182010-12-02 13:47:29 +0000341 struct falcon_nic_data *nic_data = efx->nic_data;
Ben Hutchings76884832009-11-29 15:10:44 +0000342 int rc;
343
Ben Hutchings4de92182010-12-02 13:47:29 +0000344 rc = mutex_lock_interruptible(&nic_data->spi_lock);
Ben Hutchings76884832009-11-29 15:10:44 +0000345 if (rc)
346 return rc;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000347 rc = falcon_spi_write(efx, part->falcon.spi,
348 part->falcon.offset + start, len, retlen, buffer);
Ben Hutchings4de92182010-12-02 13:47:29 +0000349 mutex_unlock(&nic_data->spi_lock);
Ben Hutchings76884832009-11-29 15:10:44 +0000350 return rc;
351}
352
353static int falcon_mtd_sync(struct mtd_info *mtd)
Ben Hutchingsf4150722008-11-04 20:34:28 +0000354{
Ben Hutchings0c605a22010-06-23 11:29:24 +0000355 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000356 struct efx_nic *efx = mtd->priv;
Ben Hutchings4de92182010-12-02 13:47:29 +0000357 struct falcon_nic_data *nic_data = efx->nic_data;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000358 int rc;
359
Ben Hutchings4de92182010-12-02 13:47:29 +0000360 mutex_lock(&nic_data->spi_lock);
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000361 rc = falcon_spi_slow_wait(part, true);
Ben Hutchings4de92182010-12-02 13:47:29 +0000362 mutex_unlock(&nic_data->spi_lock);
Ben Hutchings76884832009-11-29 15:10:44 +0000363 return rc;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000364}
365
Ben Hutchings18e83e42012-01-05 19:05:20 +0000366static const struct efx_mtd_ops falcon_mtd_ops = {
Ben Hutchings76884832009-11-29 15:10:44 +0000367 .read = falcon_mtd_read,
368 .erase = falcon_mtd_erase,
369 .write = falcon_mtd_write,
370 .sync = falcon_mtd_sync,
371};
Ben Hutchingsf4150722008-11-04 20:34:28 +0000372
Ben Hutchings76884832009-11-29 15:10:44 +0000373static int falcon_mtd_probe(struct efx_nic *efx)
Ben Hutchingsf4150722008-11-04 20:34:28 +0000374{
Ben Hutchings4de92182010-12-02 13:47:29 +0000375 struct falcon_nic_data *nic_data = efx->nic_data;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000376 struct efx_mtd_partition *parts;
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000377 struct falcon_spi_device *spi;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000378 size_t n_parts;
Ben Hutchings6a8872c2010-12-02 13:47:10 +0000379 int rc = -ENODEV;
Ben Hutchings76884832009-11-29 15:10:44 +0000380
381 ASSERT_RTNL();
Ben Hutchingsf4150722008-11-04 20:34:28 +0000382
Ben Hutchingsb7666302012-11-28 04:38:10 +0000383 efx->mtd_ops = &falcon_mtd_ops;
384
385 /* Allocate space for maximum number of partitions */
386 parts = kcalloc(2, sizeof(*parts), GFP_KERNEL);
387 n_parts = 0;
388
Ben Hutchings4de92182010-12-02 13:47:29 +0000389 spi = &nic_data->spi_flash;
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000390 if (falcon_spi_present(spi) && spi->size > FALCON_FLASH_BOOTCODE_START) {
Ben Hutchingsb7666302012-11-28 04:38:10 +0000391 parts[n_parts].falcon.spi = spi;
392 parts[n_parts].falcon.offset = FALCON_FLASH_BOOTCODE_START;
393 parts[n_parts].dev_type_name = "flash";
394 parts[n_parts].type_name = "sfc_flash_bootrom";
395 parts[n_parts].mtd.type = MTD_NORFLASH;
396 parts[n_parts].mtd.flags = MTD_CAP_NORFLASH;
397 parts[n_parts].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
398 parts[n_parts].mtd.erasesize = spi->erase_size;
399 n_parts++;
Ben Hutchings6a8872c2010-12-02 13:47:10 +0000400 }
Ben Hutchingsf4150722008-11-04 20:34:28 +0000401
Ben Hutchings4de92182010-12-02 13:47:29 +0000402 spi = &nic_data->spi_eeprom;
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000403 if (falcon_spi_present(spi) && spi->size > FALCON_EEPROM_BOOTCONFIG_START) {
Ben Hutchingsb7666302012-11-28 04:38:10 +0000404 parts[n_parts].falcon.spi = spi;
405 parts[n_parts].falcon.offset = FALCON_EEPROM_BOOTCONFIG_START;
406 parts[n_parts].dev_type_name = "EEPROM";
407 parts[n_parts].type_name = "sfc_bootconfig";
408 parts[n_parts].mtd.type = MTD_RAM;
409 parts[n_parts].mtd.flags = MTD_CAP_RAM;
410 parts[n_parts].mtd.size =
Ben Hutchingsecd0a6f2012-11-28 04:12:41 +0000411 min(spi->size, FALCON_EEPROM_BOOTCONFIG_END) -
412 FALCON_EEPROM_BOOTCONFIG_START;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000413 parts[n_parts].mtd.erasesize = spi->erase_size;
414 n_parts++;
Ben Hutchings6a8872c2010-12-02 13:47:10 +0000415 }
416
Ben Hutchingsb7666302012-11-28 04:38:10 +0000417 rc = efx_mtd_add(efx, parts, n_parts);
418 if (rc)
419 kfree(parts);
Ben Hutchings76884832009-11-29 15:10:44 +0000420 return rc;
Ben Hutchingsf4150722008-11-04 20:34:28 +0000421}
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000422
423/* Implementation of MTD operations for Siena */
424
425static int siena_mtd_read(struct mtd_info *mtd, loff_t start,
426 size_t len, size_t *retlen, u8 *buffer)
427{
428 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000429 struct efx_nic *efx = mtd->priv;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000430 loff_t offset = start;
431 loff_t end = min_t(loff_t, start + len, mtd->size);
432 size_t chunk;
433 int rc = 0;
434
435 while (offset < end) {
Ben Hutchings5a27e862010-01-25 15:49:59 -0800436 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000437 rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset,
438 buffer, chunk);
439 if (rc)
440 goto out;
441 offset += chunk;
442 buffer += chunk;
443 }
444out:
445 *retlen = offset - start;
446 return rc;
447}
448
449static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
450{
451 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000452 struct efx_nic *efx = mtd->priv;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000453 loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
454 loff_t end = min_t(loff_t, start + len, mtd->size);
455 size_t chunk = part->mtd.erasesize;
456 int rc = 0;
457
458 if (!part->mcdi.updating) {
459 rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
460 if (rc)
461 goto out;
Rusty Russell3db1cd52011-12-19 13:56:45 +0000462 part->mcdi.updating = true;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000463 }
464
465 /* The MCDI interface can in fact do multiple erase blocks at once;
466 * but erasing may be slow, so we make multiple calls here to avoid
467 * tripping the MCDI RPC timeout. */
468 while (offset < end) {
469 rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset,
470 chunk);
471 if (rc)
472 goto out;
473 offset += chunk;
474 }
475out:
476 return rc;
477}
478
479static int siena_mtd_write(struct mtd_info *mtd, loff_t start,
480 size_t len, size_t *retlen, const u8 *buffer)
481{
482 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000483 struct efx_nic *efx = mtd->priv;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000484 loff_t offset = start;
485 loff_t end = min_t(loff_t, start + len, mtd->size);
486 size_t chunk;
487 int rc = 0;
488
489 if (!part->mcdi.updating) {
490 rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
491 if (rc)
492 goto out;
Rusty Russell3db1cd52011-12-19 13:56:45 +0000493 part->mcdi.updating = true;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000494 }
495
496 while (offset < end) {
Ben Hutchings5a27e862010-01-25 15:49:59 -0800497 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000498 rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset,
499 buffer, chunk);
500 if (rc)
501 goto out;
502 offset += chunk;
503 buffer += chunk;
504 }
505out:
506 *retlen = offset - start;
507 return rc;
508}
509
510static int siena_mtd_sync(struct mtd_info *mtd)
511{
512 struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
Ben Hutchingsb7666302012-11-28 04:38:10 +0000513 struct efx_nic *efx = mtd->priv;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000514 int rc = 0;
515
516 if (part->mcdi.updating) {
Rusty Russell3db1cd52011-12-19 13:56:45 +0000517 part->mcdi.updating = false;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000518 rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type);
519 }
520
521 return rc;
522}
523
Ben Hutchings18e83e42012-01-05 19:05:20 +0000524static const struct efx_mtd_ops siena_mtd_ops = {
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000525 .read = siena_mtd_read,
526 .erase = siena_mtd_erase,
527 .write = siena_mtd_write,
528 .sync = siena_mtd_sync,
529};
530
531struct siena_nvram_type_info {
532 int port;
533 const char *name;
534};
535
Ben Hutchings18e83e42012-01-05 19:05:20 +0000536static const struct siena_nvram_type_info siena_nvram_types[] = {
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000537 [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" },
538 [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" },
539 [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" },
540 [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" },
541 [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" },
542 [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" },
543 [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" },
544 [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" },
545 [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" },
546 [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" },
547 [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" },
548 [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" },
Ben Hutchingse5621542011-07-05 00:05:56 +0100549 [MC_CMD_NVRAM_TYPE_FPGA] = { 0, "sfc_fpga" },
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000550};
551
552static int siena_mtd_probe_partition(struct efx_nic *efx,
Ben Hutchingsb7666302012-11-28 04:38:10 +0000553 struct efx_mtd_partition *part,
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000554 unsigned int type)
555{
Ben Hutchings18e83e42012-01-05 19:05:20 +0000556 const struct siena_nvram_type_info *info;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000557 size_t size, erase_size;
558 bool protected;
559 int rc;
560
Ben Hutchingse5621542011-07-05 00:05:56 +0100561 if (type >= ARRAY_SIZE(siena_nvram_types) ||
562 siena_nvram_types[type].name == NULL)
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000563 return -ENODEV;
564
565 info = &siena_nvram_types[type];
566
567 if (info->port != efx_port_num(efx))
568 return -ENODEV;
569
570 rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
571 if (rc)
572 return rc;
573 if (protected)
574 return -ENODEV; /* hide it */
575
576 part->mcdi.nvram_type = type;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000577 part->dev_type_name = "Siena NVRAM manager";
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000578 part->type_name = info->name;
579
580 part->mtd.type = MTD_NORFLASH;
581 part->mtd.flags = MTD_CAP_NORFLASH;
582 part->mtd.size = size;
583 part->mtd.erasesize = erase_size;
584
585 return 0;
586}
587
588static int siena_mtd_get_fw_subtypes(struct efx_nic *efx,
Ben Hutchingsb7666302012-11-28 04:38:10 +0000589 struct efx_mtd_partition *parts,
590 size_t n_parts)
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000591{
Ben Hutchingse3f5ec12011-07-05 00:04:42 +0100592 uint16_t fw_subtype_list[
593 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM];
Ben Hutchingsb7666302012-11-28 04:38:10 +0000594 size_t i;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000595 int rc;
596
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100597 rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list, NULL);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000598 if (rc)
599 return rc;
600
Ben Hutchingsb7666302012-11-28 04:38:10 +0000601 for (i = 0; i < n_parts; i++)
602 parts[i].mcdi.fw_subtype =
603 fw_subtype_list[parts[i].mcdi.nvram_type];
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000604
605 return 0;
606}
607
608static int siena_mtd_probe(struct efx_nic *efx)
609{
Ben Hutchingsb7666302012-11-28 04:38:10 +0000610 struct efx_mtd_partition *parts;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000611 u32 nvram_types;
612 unsigned int type;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000613 size_t n_parts;
614 int rc;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000615
616 ASSERT_RTNL();
617
Ben Hutchingsb7666302012-11-28 04:38:10 +0000618 efx->mtd_ops = &siena_mtd_ops;
619
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000620 rc = efx_mcdi_nvram_types(efx, &nvram_types);
621 if (rc)
622 return rc;
623
Ben Hutchingsb7666302012-11-28 04:38:10 +0000624 parts = kcalloc(hweight32(nvram_types), sizeof(*parts), GFP_KERNEL);
625 if (!parts)
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000626 return -ENOMEM;
627
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000628 type = 0;
Ben Hutchingsb7666302012-11-28 04:38:10 +0000629 n_parts = 0;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000630
631 while (nvram_types != 0) {
632 if (nvram_types & 1) {
Ben Hutchingsb7666302012-11-28 04:38:10 +0000633 rc = siena_mtd_probe_partition(efx, &parts[n_parts],
634 type);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000635 if (rc == 0)
Ben Hutchingsb7666302012-11-28 04:38:10 +0000636 n_parts++;
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000637 else if (rc != -ENODEV)
638 goto fail;
639 }
640 type++;
641 nvram_types >>= 1;
642 }
643
Ben Hutchingsb7666302012-11-28 04:38:10 +0000644 rc = siena_mtd_get_fw_subtypes(efx, parts, n_parts);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000645 if (rc)
646 goto fail;
647
Ben Hutchingsb7666302012-11-28 04:38:10 +0000648 rc = efx_mtd_add(efx, parts, n_parts);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000649fail:
650 if (rc)
Ben Hutchingsb7666302012-11-28 04:38:10 +0000651 kfree(parts);
Ben Hutchings8880f4e2009-11-29 15:15:41 +0000652 return rc;
653}
654