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

mtd: OneNAND: multiblock erase support

Add support for multiblock erase command. OneNANDs (excluding Flex-OneNAND)
are capable of simultaneous erase of up to 64 eraseblocks which is much faster.

This changes the erase requests for regions covering multiple eraseblocks
to be performed using multiblock erase.

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
72073027 73885aea

+194 -7
+18 -4
drivers/mtd/onenand/omap2.c
··· 112 112 unsigned long timeout; 113 113 u32 syscfg; 114 114 115 - if (state == FL_RESETING) { 116 - int i; 115 + if (state == FL_RESETING || state == FL_PREPARING_ERASE || 116 + state == FL_VERIFYING_ERASE) { 117 + int i = 21; 118 + unsigned int intr_flags = ONENAND_INT_MASTER; 117 119 118 - for (i = 0; i < 20; i++) { 120 + switch (state) { 121 + case FL_RESETING: 122 + intr_flags |= ONENAND_INT_RESET; 123 + break; 124 + case FL_PREPARING_ERASE: 125 + intr_flags |= ONENAND_INT_ERASE; 126 + break; 127 + case FL_VERIFYING_ERASE: 128 + i = 101; 129 + break; 130 + } 131 + 132 + while (--i) { 119 133 udelay(1); 120 134 intr = read_reg(c, ONENAND_REG_INTERRUPT); 121 135 if (intr & ONENAND_INT_MASTER) ··· 140 126 wait_err("controller error", state, ctrl, intr); 141 127 return -EIO; 142 128 } 143 - if (!(intr & ONENAND_INT_RESET)) { 129 + if ((intr & intr_flags) != intr_flags) { 144 130 wait_err("timeout", state, ctrl, intr); 145 131 return -EIO; 146 132 }
+171 -2
drivers/mtd/onenand/onenand_base.c
··· 34 34 35 35 #include <asm/io.h> 36 36 37 + /* 38 + * Multiblock erase if number of blocks to erase is 2 or more. 39 + * Maximum number of blocks for simultaneous erase is 64. 40 + */ 41 + #define MB_ERASE_MIN_BLK_COUNT 2 42 + #define MB_ERASE_MAX_BLK_COUNT 64 43 + 37 44 /* Default Flex-OneNAND boundary and lock respectively */ 38 45 static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 }; 39 46 ··· 360 353 break; 361 354 362 355 case ONENAND_CMD_ERASE: 356 + case ONENAND_CMD_MULTIBLOCK_ERASE: 357 + case ONENAND_CMD_ERASE_VERIFY: 363 358 case ONENAND_CMD_BUFFERRAM: 364 359 case ONENAND_CMD_OTP_ACCESS: 365 360 block = onenand_block(this, addr); ··· 506 497 if (interrupt & flags) 507 498 break; 508 499 509 - if (state != FL_READING) 500 + if (state != FL_READING && state != FL_PREPARING_ERASE) 510 501 cond_resched(); 511 502 } 512 503 /* To get correct interrupt status in timeout case */ ··· 536 527 } else if (state == FL_READING) { 537 528 printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", 538 529 __func__, ctrl, interrupt); 530 + return -EIO; 531 + } 532 + 533 + if (state == FL_PREPARING_ERASE && !(interrupt & ONENAND_INT_ERASE)) { 534 + printk(KERN_ERR "%s: mb erase timeout! ctrl=0x%04x intr=0x%04x\n", 535 + __func__, ctrl, interrupt); 536 + return -EIO; 537 + } 538 + 539 + if (!(interrupt & ONENAND_INT_MASTER)) { 540 + printk(KERN_ERR "%s: timeout! ctrl=0x%04x intr=0x%04x\n", 541 + __func__, ctrl, interrupt); 539 542 return -EIO; 540 543 } 541 544 ··· 2203 2182 return bbm->isbad_bbt(mtd, ofs, allowbbt); 2204 2183 } 2205 2184 2185 + 2186 + static int onenand_multiblock_erase_verify(struct mtd_info *mtd, 2187 + struct erase_info *instr) 2188 + { 2189 + struct onenand_chip *this = mtd->priv; 2190 + loff_t addr = instr->addr; 2191 + int len = instr->len; 2192 + unsigned int block_size = (1 << this->erase_shift); 2193 + int ret = 0; 2194 + 2195 + while (len) { 2196 + this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size); 2197 + ret = this->wait(mtd, FL_VERIFYING_ERASE); 2198 + if (ret) { 2199 + printk(KERN_ERR "%s: Failed verify, block %d\n", 2200 + __func__, onenand_block(this, addr)); 2201 + instr->state = MTD_ERASE_FAILED; 2202 + instr->fail_addr = addr; 2203 + return -1; 2204 + } 2205 + len -= block_size; 2206 + addr += block_size; 2207 + } 2208 + return 0; 2209 + } 2210 + 2211 + /** 2212 + * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase 2213 + * @param mtd MTD device structure 2214 + * @param instr erase instruction 2215 + * @param region erase region 2216 + * 2217 + * Erase one or more blocks up to 64 block at a time 2218 + */ 2219 + static int onenand_multiblock_erase(struct mtd_info *mtd, 2220 + struct erase_info *instr, 2221 + unsigned int block_size) 2222 + { 2223 + struct onenand_chip *this = mtd->priv; 2224 + loff_t addr = instr->addr; 2225 + int len = instr->len; 2226 + int eb_count = 0; 2227 + int ret = 0; 2228 + int bdry_block = 0; 2229 + 2230 + instr->state = MTD_ERASING; 2231 + 2232 + if (ONENAND_IS_DDP(this)) { 2233 + loff_t bdry_addr = this->chipsize >> 1; 2234 + if (addr < bdry_addr && (addr + len) > bdry_addr) 2235 + bdry_block = bdry_addr >> this->erase_shift; 2236 + } 2237 + 2238 + /* Pre-check bbs */ 2239 + while (len) { 2240 + /* Check if we have a bad block, we do not erase bad blocks */ 2241 + if (onenand_block_isbad_nolock(mtd, addr, 0)) { 2242 + printk(KERN_WARNING "%s: attempt to erase a bad block " 2243 + "at addr 0x%012llx\n", 2244 + __func__, (unsigned long long) addr); 2245 + instr->state = MTD_ERASE_FAILED; 2246 + return -EIO; 2247 + } 2248 + len -= block_size; 2249 + addr += block_size; 2250 + } 2251 + 2252 + len = instr->len; 2253 + addr = instr->addr; 2254 + 2255 + /* loop over 64 eb batches */ 2256 + while (len) { 2257 + struct erase_info verify_instr = *instr; 2258 + int max_eb_count = MB_ERASE_MAX_BLK_COUNT; 2259 + 2260 + verify_instr.addr = addr; 2261 + verify_instr.len = 0; 2262 + 2263 + /* do not cross chip boundary */ 2264 + if (bdry_block) { 2265 + int this_block = (addr >> this->erase_shift); 2266 + 2267 + if (this_block < bdry_block) { 2268 + max_eb_count = min(max_eb_count, 2269 + (bdry_block - this_block)); 2270 + } 2271 + } 2272 + 2273 + eb_count = 0; 2274 + 2275 + while (len > block_size && eb_count < (max_eb_count - 1)) { 2276 + this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE, 2277 + addr, block_size); 2278 + onenand_invalidate_bufferram(mtd, addr, block_size); 2279 + 2280 + ret = this->wait(mtd, FL_PREPARING_ERASE); 2281 + if (ret) { 2282 + printk(KERN_ERR "%s: Failed multiblock erase, " 2283 + "block %d\n", __func__, 2284 + onenand_block(this, addr)); 2285 + instr->state = MTD_ERASE_FAILED; 2286 + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; 2287 + return -EIO; 2288 + } 2289 + 2290 + len -= block_size; 2291 + addr += block_size; 2292 + eb_count++; 2293 + } 2294 + 2295 + /* last block of 64-eb series */ 2296 + cond_resched(); 2297 + this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); 2298 + onenand_invalidate_bufferram(mtd, addr, block_size); 2299 + 2300 + ret = this->wait(mtd, FL_ERASING); 2301 + /* Check if it is write protected */ 2302 + if (ret) { 2303 + printk(KERN_ERR "%s: Failed erase, block %d\n", 2304 + __func__, onenand_block(this, addr)); 2305 + instr->state = MTD_ERASE_FAILED; 2306 + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; 2307 + return -EIO; 2308 + } 2309 + 2310 + len -= block_size; 2311 + addr += block_size; 2312 + eb_count++; 2313 + 2314 + /* verify */ 2315 + verify_instr.len = eb_count * block_size; 2316 + if (onenand_multiblock_erase_verify(mtd, &verify_instr)) { 2317 + instr->state = verify_instr.state; 2318 + instr->fail_addr = verify_instr.fail_addr; 2319 + return -EIO; 2320 + } 2321 + 2322 + } 2323 + return 0; 2324 + } 2325 + 2326 + 2206 2327 /** 2207 2328 * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase 2208 2329 * @param mtd MTD device structure ··· 2478 2315 /* Grab the lock and see if the device is available */ 2479 2316 onenand_get_device(mtd, FL_ERASING); 2480 2317 2481 - ret = onenand_block_by_block_erase(mtd, instr, region, block_size); 2318 + if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { 2319 + /* region is set for Flex-OneNAND (no mb erase) */ 2320 + ret = onenand_block_by_block_erase(mtd, instr, 2321 + region, block_size); 2322 + } else { 2323 + ret = onenand_multiblock_erase(mtd, instr, block_size); 2324 + } 2482 2325 2483 2326 /* Deselect and wake up anyone waiting on the device */ 2484 2327 onenand_release_device(mtd);
+3 -1
include/linux/mtd/flashchip.h
··· 41 41 /* These 2 come from nand_state_t, which has been unified here */ 42 42 FL_READING, 43 43 FL_CACHEDPRG, 44 - /* These 2 come from onenand_state_t, which has been unified here */ 44 + /* These 4 come from onenand_state_t, which has been unified here */ 45 45 FL_RESETING, 46 46 FL_OTPING, 47 + FL_PREPARING_ERASE, 48 + FL_VERIFYING_ERASE, 47 49 48 50 FL_UNKNOWN 49 51 } flstate_t;
+2
include/linux/mtd/onenand_regs.h
··· 131 131 #define ONENAND_CMD_LOCK_TIGHT (0x2C) 132 132 #define ONENAND_CMD_UNLOCK_ALL (0x27) 133 133 #define ONENAND_CMD_ERASE (0x94) 134 + #define ONENAND_CMD_MULTIBLOCK_ERASE (0x95) 135 + #define ONENAND_CMD_ERASE_VERIFY (0x71) 134 136 #define ONENAND_CMD_RESET (0xF0) 135 137 #define ONENAND_CMD_OTP_ACCESS (0x65) 136 138 #define ONENAND_CMD_READID (0x90)