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

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>

authored by

Mika Korhonen and committed by
David Woodhouse
73885aea 7126bd8b

+76 -56
+76 -56
drivers/mtd/onenand/onenand_base.c
··· 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 2187 * @param mtd MTD device structure 2188 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 2199 struct onenand_chip *this = mtd->priv; 2195 - unsigned int block_size; 2196 2200 loff_t addr = instr->addr; 2197 - loff_t len = instr->len; 2198 - int ret = 0, i; 2199 - struct mtd_erase_region_info *region = NULL; 2201 + int len = instr->len; 2200 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); 2203 - 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; 2205 + if (region) { 2206 + /* region is set for Flex-OneNAND */ 2216 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 2208 } 2234 2209 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 - } 2240 - 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 2210 instr->state = MTD_ERASING; 2248 2211 2212 + /* Loop through the blocks */ 2249 2213 while (len) { 2250 2214 cond_resched(); 2251 2215 ··· 2219 2255 "at addr 0x%012llx\n", 2220 2256 __func__, (unsigned long long) addr); 2221 2257 instr->state = MTD_ERASE_FAILED; 2222 - goto erase_exit; 2258 + return -EIO; 2223 2259 } 2224 2260 2225 2261 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); ··· 2233 2269 __func__, onenand_block(this, addr)); 2234 2270 instr->state = MTD_ERASE_FAILED; 2235 2271 instr->fail_addr = addr; 2236 - goto erase_exit; 2272 + return -EIO; 2237 2273 } 2238 2274 2239 2275 len -= block_size; ··· 2251 2287 /* FIXME: This should be handled at MTD partitioning level. */ 2252 2288 printk(KERN_ERR "%s: Unaligned address\n", 2253 2289 __func__); 2254 - goto erase_exit; 2290 + return -EIO; 2255 2291 } 2256 2292 } 2293 + } 2294 + return 0; 2295 + } 2257 2296 2297 + /** 2298 + * onenand_erase - [MTD Interface] erase block(s) 2299 + * @param mtd MTD device structure 2300 + * @param instr erase instruction 2301 + * 2302 + * Erase one or more blocks 2303 + */ 2304 + static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) 2305 + { 2306 + struct onenand_chip *this = mtd->priv; 2307 + unsigned int block_size; 2308 + loff_t addr = instr->addr; 2309 + loff_t len = instr->len; 2310 + int ret = 0; 2311 + struct mtd_erase_region_info *region = NULL; 2312 + loff_t region_offset = 0; 2313 + 2314 + DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, 2315 + (unsigned long long) instr->addr, (unsigned long long) instr->len); 2316 + 2317 + /* Do not allow erase past end of device */ 2318 + if (unlikely((len + addr) > mtd->size)) { 2319 + printk(KERN_ERR "%s: Erase past end of device\n", __func__); 2320 + return -EINVAL; 2258 2321 } 2259 2322 2260 - instr->state = MTD_ERASE_DONE; 2323 + if (FLEXONENAND(this)) { 2324 + /* Find the eraseregion of this address */ 2325 + int i = flexonenand_region(mtd, addr); 2261 2326 2262 - erase_exit: 2327 + region = &mtd->eraseregions[i]; 2328 + block_size = region->erasesize; 2263 2329 2264 - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; 2330 + /* Start address within region must align on block boundary. 2331 + * Erase region's start offset is always block start address. 2332 + */ 2333 + region_offset = region->offset; 2334 + } else 2335 + block_size = 1 << this->erase_shift; 2336 + 2337 + /* Start address must align on block boundary */ 2338 + if (unlikely((addr - region_offset) & (block_size - 1))) { 2339 + printk(KERN_ERR "%s: Unaligned address\n", __func__); 2340 + return -EINVAL; 2341 + } 2342 + 2343 + /* Length must align on block boundary */ 2344 + if (unlikely(len & (block_size - 1))) { 2345 + printk(KERN_ERR "%s: Length not block aligned\n", __func__); 2346 + return -EINVAL; 2347 + } 2348 + 2349 + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; 2350 + 2351 + /* Grab the lock and see if the device is available */ 2352 + onenand_get_device(mtd, FL_ERASING); 2353 + 2354 + ret = onenand_block_by_block_erase(mtd, instr, region, block_size); 2265 2355 2266 2356 /* Deselect and wake up anyone waiting on the device */ 2267 2357 onenand_release_device(mtd); 2268 2358 2269 2359 /* Do call back function */ 2270 - if (!ret) 2360 + if (!ret) { 2361 + instr->state = MTD_ERASE_DONE; 2271 2362 mtd_erase_callback(instr); 2363 + } 2272 2364 2273 2365 return ret; 2274 2366 }