Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.30-rc4 269 lines 6.5 kB view raw
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 22struct 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 30static 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 55static 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 87static 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 133static 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 150static 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 173static 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 190static 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 205void 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 222void 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 231int 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}