Merge branch 'topic/azt3328' into for-linus
[pandora-kernel.git] / drivers / net / sfc / mtd.c
1 /****************************************************************************
2  * Driver for Solarflare Solarstorm network controllers and boards
3  * Copyright 2005-2006 Fen Systems Ltd.
4  * Copyright 2006-2008 Solarflare Communications Inc.
5  *
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
11 #include <linux/module.h>
12 #include <linux/mtd/mtd.h>
13 #include <linux/delay.h>
14
15 #define EFX_DRIVER_NAME "sfc_mtd"
16 #include "net_driver.h"
17 #include "spi.h"
18 #include "efx.h"
19
20 #define EFX_SPI_VERIFY_BUF_LEN 16
21
22 struct efx_mtd {
23         const struct efx_spi_device *spi;
24         struct mtd_info mtd;
25         char name[IFNAMSIZ + 20];
26 };
27
28 /* SPI utilities */
29
30 static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
31 {
32         const struct efx_spi_device *spi = efx_mtd->spi;
33         struct efx_nic *efx = spi->efx;
34         u8 status;
35         int rc, i;
36
37         /* Wait up to 4s for flash/EEPROM to finish a slow operation. */
38         for (i = 0; i < 40; i++) {
39                 __set_current_state(uninterruptible ?
40                                     TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
41                 schedule_timeout(HZ / 10);
42                 rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
43                                     &status, sizeof(status));
44                 if (rc)
45                         return rc;
46                 if (!(status & SPI_STATUS_NRDY))
47                         return 0;
48                 if (signal_pending(current))
49                         return -EINTR;
50         }
51         EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
52         return -ETIMEDOUT;
53 }
54
55 static int efx_spi_unlock(const struct efx_spi_device *spi)
56 {
57         const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
58                                 SPI_STATUS_BP0);
59         u8 status;
60         int rc;
61
62         rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status));
63         if (rc)
64                 return rc;
65
66         if (!(status & unlock_mask))
67                 return 0; /* already unlocked */
68
69         rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
70         if (rc)
71                 return rc;
72         rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
73         if (rc)
74                 return rc;
75
76         status &= ~unlock_mask;
77         rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status));
78         if (rc)
79                 return rc;
80         rc = falcon_spi_wait_write(spi);
81         if (rc)
82                 return rc;
83
84         return 0;
85 }
86
87 static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
88 {
89         const struct efx_spi_device *spi = efx_mtd->spi;
90         unsigned pos, block_len;
91         u8 empty[EFX_SPI_VERIFY_BUF_LEN];
92         u8 buffer[EFX_SPI_VERIFY_BUF_LEN];
93         int rc;
94
95         if (len != spi->erase_size)
96                 return -EINVAL;
97
98         if (spi->erase_command == 0)
99                 return -EOPNOTSUPP;
100
101         rc = efx_spi_unlock(spi);
102         if (rc)
103                 return rc;
104         rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
105         if (rc)
106                 return rc;
107         rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0);
108         if (rc)
109                 return rc;
110         rc = efx_spi_slow_wait(efx_mtd, false);
111
112         /* Verify the entire region has been wiped */
113         memset(empty, 0xff, sizeof(empty));
114         for (pos = 0; pos < len; pos += block_len) {
115                 block_len = min(len - pos, sizeof(buffer));
116                 rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer);
117                 if (rc)
118                         return rc;
119                 if (memcmp(empty, buffer, block_len))
120                         return -EIO;
121
122                 /* Avoid locking up the system */
123                 cond_resched();
124                 if (signal_pending(current))
125                         return -EINTR;
126         }
127
128         return rc;
129 }
130
131 /* MTD interface */
132
133 static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
134                         size_t *retlen, u8 *buffer)
135 {
136         struct efx_mtd *efx_mtd = mtd->priv;
137         const struct efx_spi_device *spi = efx_mtd->spi;
138         struct efx_nic *efx = spi->efx;
139         int rc;
140
141         rc = mutex_lock_interruptible(&efx->spi_lock);
142         if (rc)
143                 return rc;
144         rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start,
145                              len, retlen, buffer);
146         mutex_unlock(&efx->spi_lock);
147         return rc;
148 }
149
150 static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
151 {
152         struct efx_mtd *efx_mtd = mtd->priv;
153         struct efx_nic *efx = efx_mtd->spi->efx;
154         int rc;
155
156         rc = mutex_lock_interruptible(&efx->spi_lock);
157         if (rc)
158                 return rc;
159         rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr,
160                            erase->len);
161         mutex_unlock(&efx->spi_lock);
162
163         if (rc == 0) {
164                 erase->state = MTD_ERASE_DONE;
165         } else {
166                 erase->state = MTD_ERASE_FAILED;
167                 erase->fail_addr = 0xffffffff;
168         }
169         mtd_erase_callback(erase);
170         return rc;
171 }
172
173 static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
174                          size_t len, size_t *retlen, const u8 *buffer)
175 {
176         struct efx_mtd *efx_mtd = mtd->priv;
177         const struct efx_spi_device *spi = efx_mtd->spi;
178         struct efx_nic *efx = spi->efx;
179         int rc;
180
181         rc = mutex_lock_interruptible(&efx->spi_lock);
182         if (rc)
183                 return rc;
184         rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start,
185                               len, retlen, buffer);
186         mutex_unlock(&efx->spi_lock);
187         return rc;
188 }
189
190 static void efx_mtd_sync(struct mtd_info *mtd)
191 {
192         struct efx_mtd *efx_mtd = mtd->priv;
193         struct efx_nic *efx = efx_mtd->spi->efx;
194         int rc;
195
196         mutex_lock(&efx->spi_lock);
197         rc = efx_spi_slow_wait(efx_mtd, true);
198         mutex_unlock(&efx->spi_lock);
199
200         if (rc)
201                 EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
202         return;
203 }
204
205 void efx_mtd_remove(struct efx_nic *efx)
206 {
207         if (efx->spi_flash && efx->spi_flash->mtd) {
208                 struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
209                 int rc;
210
211                 for (;;) {
212                         rc = del_mtd_device(&efx_mtd->mtd);
213                         if (rc != -EBUSY)
214                                 break;
215                         ssleep(1);
216                 }
217                 WARN_ON(rc);
218                 kfree(efx_mtd);
219         }
220 }
221
222 void efx_mtd_rename(struct efx_nic *efx)
223 {
224         if (efx->spi_flash && efx->spi_flash->mtd) {
225                 struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
226                 snprintf(efx_mtd->name, sizeof(efx_mtd->name),
227                          "%s sfc_flash_bootrom", efx->name);
228         }
229 }
230
231 int efx_mtd_probe(struct efx_nic *efx)
232 {
233         struct efx_spi_device *spi = efx->spi_flash;
234         struct efx_mtd *efx_mtd;
235
236         if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START)
237                 return -ENODEV;
238
239         efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
240         if (!efx_mtd)
241                 return -ENOMEM;
242
243         efx_mtd->spi = spi;
244         spi->mtd = efx_mtd;
245
246         efx_mtd->mtd.type = MTD_NORFLASH;
247         efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
248         efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
249         efx_mtd->mtd.erasesize = spi->erase_size;
250         efx_mtd->mtd.writesize = 1;
251         efx_mtd_rename(efx);
252
253         efx_mtd->mtd.owner = THIS_MODULE;
254         efx_mtd->mtd.priv = efx_mtd;
255         efx_mtd->mtd.name = efx_mtd->name;
256         efx_mtd->mtd.erase = efx_mtd_erase;
257         efx_mtd->mtd.read = efx_mtd_read;
258         efx_mtd->mtd.write = efx_mtd_write;
259         efx_mtd->mtd.sync = efx_mtd_sync;
260
261         if (add_mtd_device(&efx_mtd->mtd)) {
262                 kfree(efx_mtd);
263                 spi->mtd = NULL;
264                 /* add_mtd_device() returns 1 if the MTD table is full */
265                 return -ENOMEM;
266         }
267
268         return 0;
269 }