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