diff options
author | Mika Korhonen <ext-mika.2.korhonen@nokia.com> | 2009-10-23 01:50:42 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-11-30 04:42:55 -0500 |
commit | 73885aeaca046a21183db598c2da46529e46fdab (patch) | |
tree | edf13d8b7fbbb84e18ebe842dd226858a887ca57 /drivers/mtd | |
parent | 7126bd8be4ee009c56c4ec037f07f2c0884413fc (diff) |
mtd: OneNAND: move erase method to a separate function
Separate the actual execution of erase to a new function:
onenand_block_by_block_erase(). This is done in preparation for
the multiblock erase support.
Signed-off-by: Mika Korhonen <ext-mika.2.korhonen@nokia.com>
Reviewed-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 132 |
1 files changed, 76 insertions, 56 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7bd6ad3ff30a..894ebadc3e69 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -2183,69 +2183,33 @@ static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allo | |||
2183 | } | 2183 | } |
2184 | 2184 | ||
2185 | /** | 2185 | /** |
2186 | * onenand_erase - [MTD Interface] erase block(s) | 2186 | * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase |
2187 | * @param mtd MTD device structure | 2187 | * @param mtd MTD device structure |
2188 | * @param instr erase instruction | 2188 | * @param instr erase instruction |
2189 | * @param region erase region | ||
2190 | * @param block_size erase block size | ||
2189 | * | 2191 | * |
2190 | * Erase one ore more blocks | 2192 | * Erase one or more blocks one block at a time |
2191 | */ | 2193 | */ |
2192 | static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | 2194 | static int onenand_block_by_block_erase(struct mtd_info *mtd, |
2195 | struct erase_info *instr, | ||
2196 | struct mtd_erase_region_info *region, | ||
2197 | unsigned int block_size) | ||
2193 | { | 2198 | { |
2194 | struct onenand_chip *this = mtd->priv; | 2199 | struct onenand_chip *this = mtd->priv; |
2195 | unsigned int block_size; | ||
2196 | loff_t addr = instr->addr; | 2200 | loff_t addr = instr->addr; |
2197 | loff_t len = instr->len; | 2201 | int len = instr->len; |
2198 | int ret = 0, i; | ||
2199 | struct mtd_erase_region_info *region = NULL; | ||
2200 | loff_t region_end = 0; | 2202 | loff_t region_end = 0; |
2203 | int ret = 0; | ||
2201 | 2204 | ||
2202 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len); | 2205 | if (region) { |
2203 | 2206 | /* region is set for Flex-OneNAND */ | |
2204 | /* Do not allow erase past end of device */ | ||
2205 | if (unlikely((len + addr) > mtd->size)) { | ||
2206 | printk(KERN_ERR "%s: Erase past end of device\n", __func__); | ||
2207 | return -EINVAL; | ||
2208 | } | ||
2209 | |||
2210 | if (FLEXONENAND(this)) { | ||
2211 | /* Find the eraseregion of this address */ | ||
2212 | i = flexonenand_region(mtd, addr); | ||
2213 | region = &mtd->eraseregions[i]; | ||
2214 | |||
2215 | block_size = region->erasesize; | ||
2216 | region_end = region->offset + region->erasesize * region->numblocks; | 2207 | region_end = region->offset + region->erasesize * region->numblocks; |
2217 | |||
2218 | /* Start address within region must align on block boundary. | ||
2219 | * Erase region's start offset is always block start address. | ||
2220 | */ | ||
2221 | if (unlikely((addr - region->offset) & (block_size - 1))) { | ||
2222 | printk(KERN_ERR "%s: Unaligned address\n", __func__); | ||
2223 | return -EINVAL; | ||
2224 | } | ||
2225 | } else { | ||
2226 | block_size = 1 << this->erase_shift; | ||
2227 | |||
2228 | /* Start address must align on block boundary */ | ||
2229 | if (unlikely(addr & (block_size - 1))) { | ||
2230 | printk(KERN_ERR "%s: Unaligned address\n", __func__); | ||
2231 | return -EINVAL; | ||
2232 | } | ||
2233 | } | ||
2234 | |||
2235 | /* Length must align on block boundary */ | ||
2236 | if (unlikely(len & (block_size - 1))) { | ||
2237 | printk(KERN_ERR "%s: Length not block aligned\n", __func__); | ||
2238 | return -EINVAL; | ||
2239 | } | 2208 | } |
2240 | 2209 | ||
2241 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; | ||
2242 | |||
2243 | /* Grab the lock and see if the device is available */ | ||
2244 | onenand_get_device(mtd, FL_ERASING); | ||
2245 | |||
2246 | /* Loop through the blocks */ | ||
2247 | instr->state = MTD_ERASING; | 2210 | instr->state = MTD_ERASING; |
2248 | 2211 | ||
2212 | /* Loop through the blocks */ | ||
2249 | while (len) { | 2213 | while (len) { |
2250 | cond_resched(); | 2214 | cond_resched(); |
2251 | 2215 | ||
@@ -2255,7 +2219,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2255 | "at addr 0x%012llx\n", | 2219 | "at addr 0x%012llx\n", |
2256 | __func__, (unsigned long long) addr); | 2220 | __func__, (unsigned long long) addr); |
2257 | instr->state = MTD_ERASE_FAILED; | 2221 | instr->state = MTD_ERASE_FAILED; |
2258 | goto erase_exit; | 2222 | return -EIO; |
2259 | } | 2223 | } |
2260 | 2224 | ||
2261 | this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); | 2225 | this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); |
@@ -2269,7 +2233,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2269 | __func__, onenand_block(this, addr)); | 2233 | __func__, onenand_block(this, addr)); |
2270 | instr->state = MTD_ERASE_FAILED; | 2234 | instr->state = MTD_ERASE_FAILED; |
2271 | instr->fail_addr = addr; | 2235 | instr->fail_addr = addr; |
2272 | goto erase_exit; | 2236 | return -EIO; |
2273 | } | 2237 | } |
2274 | 2238 | ||
2275 | len -= block_size; | 2239 | len -= block_size; |
@@ -2287,24 +2251,80 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
2287 | /* FIXME: This should be handled at MTD partitioning level. */ | 2251 | /* FIXME: This should be handled at MTD partitioning level. */ |
2288 | printk(KERN_ERR "%s: Unaligned address\n", | 2252 | printk(KERN_ERR "%s: Unaligned address\n", |
2289 | __func__); | 2253 | __func__); |
2290 | goto erase_exit; | 2254 | return -EIO; |
2291 | } | 2255 | } |
2292 | } | 2256 | } |
2257 | } | ||
2258 | return 0; | ||
2259 | } | ||
2260 | |||
2261 | /** | ||
2262 | * onenand_erase - [MTD Interface] erase block(s) | ||
2263 | * @param mtd MTD device structure | ||
2264 | * @param instr erase instruction | ||
2265 | * | ||
2266 | * Erase one or more blocks | ||
2267 | */ | ||
2268 | static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
2269 | { | ||
2270 | struct onenand_chip *this = mtd->priv; | ||
2271 | unsigned int block_size; | ||
2272 | loff_t addr = instr->addr; | ||
2273 | loff_t len = instr->len; | ||
2274 | int ret = 0; | ||
2275 | struct mtd_erase_region_info *region = NULL; | ||
2276 | loff_t region_offset = 0; | ||
2277 | |||
2278 | DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, | ||
2279 | (unsigned long long) instr->addr, (unsigned long long) instr->len); | ||
2280 | |||
2281 | /* Do not allow erase past end of device */ | ||
2282 | if (unlikely((len + addr) > mtd->size)) { | ||
2283 | printk(KERN_ERR "%s: Erase past end of device\n", __func__); | ||
2284 | return -EINVAL; | ||
2285 | } | ||
2286 | |||
2287 | if (FLEXONENAND(this)) { | ||
2288 | /* Find the eraseregion of this address */ | ||
2289 | int i = flexonenand_region(mtd, addr); | ||
2290 | |||
2291 | region = &mtd->eraseregions[i]; | ||
2292 | block_size = region->erasesize; | ||
2293 | |||
2294 | /* Start address within region must align on block boundary. | ||
2295 | * Erase region's start offset is always block start address. | ||
2296 | */ | ||
2297 | region_offset = region->offset; | ||
2298 | } else | ||
2299 | block_size = 1 << this->erase_shift; | ||
2300 | |||
2301 | /* Start address must align on block boundary */ | ||
2302 | if (unlikely((addr - region_offset) & (block_size - 1))) { | ||
2303 | printk(KERN_ERR "%s: Unaligned address\n", __func__); | ||
2304 | return -EINVAL; | ||
2305 | } | ||
2293 | 2306 | ||
2307 | /* Length must align on block boundary */ | ||
2308 | if (unlikely(len & (block_size - 1))) { | ||
2309 | printk(KERN_ERR "%s: Length not block aligned\n", __func__); | ||
2310 | return -EINVAL; | ||
2294 | } | 2311 | } |
2295 | 2312 | ||
2296 | instr->state = MTD_ERASE_DONE; | 2313 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
2297 | 2314 | ||
2298 | erase_exit: | 2315 | /* Grab the lock and see if the device is available */ |
2316 | onenand_get_device(mtd, FL_ERASING); | ||
2299 | 2317 | ||
2300 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; | 2318 | ret = onenand_block_by_block_erase(mtd, instr, region, block_size); |
2301 | 2319 | ||
2302 | /* Deselect and wake up anyone waiting on the device */ | 2320 | /* Deselect and wake up anyone waiting on the device */ |
2303 | onenand_release_device(mtd); | 2321 | onenand_release_device(mtd); |
2304 | 2322 | ||
2305 | /* Do call back function */ | 2323 | /* Do call back function */ |
2306 | if (!ret) | 2324 | if (!ret) { |
2325 | instr->state = MTD_ERASE_DONE; | ||
2307 | mtd_erase_callback(instr); | 2326 | mtd_erase_callback(instr); |
2327 | } | ||
2308 | 2328 | ||
2309 | return ret; | 2329 | return ret; |
2310 | } | 2330 | } |