cfi_cmdset_0001.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,870 行 · 第 1/4 页
C
1,870 行
return 0;}static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ struct kvec vec; vec.iov_base = (void *) buf; vec.iov_len = len; return cfi_intelext_writev(mtd, &vec, 1, to, retlen);}static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; map_word status; int retries = 3; int ret; adr += chip->start; retry: spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); if (ret) { spin_unlock(chip->mutex); return ret; } XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); xip_disable(map, chip, adr); /* Clear the status register first */ map_write(map, CMD(0x50), adr); /* Now erase */ map_write(map, CMD(0x20), adr); map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, chip->erase_time); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; xip_enable(map, chip, adr); printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); goto out; } /* We've broken this before. It doesn't hurt to be safe */ map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; status = map_read(map, adr); /* check for errors */ if (map_word_bitsset(map, status, CMD(0x3a))) { unsigned long chipstatus = MERGESTATUS(status); /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); if ((chipstatus & 0x30) == 0x30) { printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus); ret = -EINVAL; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name); ret = -EIO; } else if (chipstatus & 0x20 && retries--) { printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; } else { printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus); ret = -EIO; } goto out; } xip_enable(map, chip, adr); out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr){ unsigned long ofs, len; int ret; ofs = instr->addr; len = instr->len; ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL); if (ret) return ret; instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0;}static void cfi_intelext_sync (struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int i; struct flchip *chip; int ret = 0; for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_SYNCING); if (!ret) { chip->oldstate = chip->state; chip->state = FL_SYNCING; /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ } spin_unlock(chip->mutex); } /* Unlock the chips again */ for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; chip->oldstate = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); }}static int __xipram do_getlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; int status, ofs_factor = cfi->interleave * cfi->device_type; adr += chip->start; xip_disable(map, chip, adr+(2*ofs_factor)); map_write(map, CMD(0x90), adr+(2*ofs_factor)); chip->state = FL_JEDEC_QUERY; status = cfi_read_query(map, adr+(2*ofs_factor)); xip_enable(map, chip, 0); return status;}#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk){ struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; int udelay; int ret; adr += chip->start; spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { spin_unlock(chip->mutex); return ret; } ENABLE_VPP(map); xip_disable(map, chip, adr); map_write(map, CMD(0x60), adr); if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { map_write(map, CMD(0x01), adr); chip->state = FL_LOCKING; } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { map_write(map, CMD(0xD0), adr); chip->state = FL_UNLOCKING; } else BUG(); /* * If Instant Individual Block Locking supported then no need * to delay. */ udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; ret = WAIT_TIMEOUT(map, chip, adr, udelay); if (ret) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; xip_enable(map, chip, adr); printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); goto out; } xip_enable(map, chip, adr);out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret;}static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len){ int ret; ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); return ret;}static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){ int ret; ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); return ret;}static void cfi_intelext_save_locks(struct mtd_info *mtd){ struct mtd_erase_region_info *region; int block, status, i; unsigned long adr; size_t len; for (i = 0; i < mtd->numeraseregions; i++) { region = &mtd->eraseregions[i]; if (!region->lockmap) continue; for (block = 0; block < region->numblocks; block++){ len = region->erasesize; adr = region->offset + block * len; status = cfi_varsize_frob(mtd, do_getlockstatus_oneblock, adr, len, 0); if (status) set_bit(block, region->lockmap); else clear_bit(block, region->lockmap); } }}static int cfi_intelext_suspend(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; int i; struct flchip *chip; int ret = 0; if ((mtd->flags & MTD_STUPID_LOCK) && extp && (extp->FeatureSupport & (1 << 5))) cfi_intelext_save_locks(mtd); for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; spin_lock(chip->mutex); switch (chip->state) { case FL_READY: case FL_STATUS: case FL_CFI_QUERY: case FL_JEDEC_QUERY: if (chip->oldstate == FL_READY) { /* place the chip in a known state before suspend */ map_write(map, CMD(0xFF), cfi->chips[i].start); chip->oldstate = chip->state; chip->state = FL_PM_SUSPENDED; /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ } else { /* There seems to be an operation pending. We must wait for it. */ printk(KERN_NOTICE "Flash device refused suspend due to pending operation (oldstate %d)\n", chip->oldstate); ret = -EAGAIN; } break; default: /* Should we actually wait? Once upon a time these routines weren't allowed to. Or should we return -EAGAIN, because the upper layers ought to have already shut down anything which was using the device anyway? The latter for now. */ printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate); ret = -EAGAIN; case FL_PM_SUSPENDED: break; } spin_unlock(chip->mutex); } /* Unlock the chips again */ if (ret) { for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { /* No need to force it into a known state here, because we're returning failure, and it didn't get power cycled */ chip->state = chip->oldstate; chip->oldstate = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); } } return ret;}static void cfi_intelext_restore_locks(struct mtd_info *mtd){ struct mtd_erase_region_info *region; int block, i; unsigned long adr; size_t len; for (i = 0; i < mtd->numeraseregions; i++) { region = &mtd->eraseregions[i]; if (!region->lockmap) continue; for (block = 0; block < region->numblocks; block++) { len = region->erasesize; adr = region->offset + block * len; if (!test_bit(block, region->lockmap)) cfi_intelext_unlock(mtd, adr, len); } }}static void cfi_intelext_resume(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; int i; struct flchip *chip; for (i=0; i<cfi->numchips; i++) { chip = &cfi->chips[i]; spin_lock(chip->mutex); /* Go to known state. Chip may have been power cycled */ if (chip->state == FL_PM_SUSPENDED) { map_write(map, CMD(0xFF), cfi->chips[i].start); chip->oldstate = chip->state = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); } if ((mtd->flags & MTD_STUPID_LOCK) && extp && (extp->FeatureSupport & (1 << 5))) cfi_intelext_restore_locks(mtd);}static int cfi_intelext_reset(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int i, ret; for (i=0; i < cfi->numchips; i++) { struct flchip *chip = &cfi->chips[i]; /* force the completion of any ongoing operation and switch to array mode so any bootloader in flash is accessible for soft reboot. */ spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_SYNCING); if (!ret) { map_write(map, CMD(0xff), chip->start); chip->state = FL_READY; } spin_unlock(chip->mutex); } return 0;}static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, void *v){ struct mtd_info *mtd; mtd = container_of(nb, struct mtd_info, reboot_notifier); cfi_intelext_reset(mtd); return NOTIFY_DONE;}static void cfi_intelext_destroy(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; struct mtd_erase_region_info *region; int i; cfi_intelext_reset(mtd); unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi->chips[0].priv); kfree(cfi); for (i = 0; i < mtd->numeraseregions; i++) { region = &mtd->eraseregions[i]; if (region->lockmap) kfree(region->lockmap); } kfree(mtd->eraseregions);}MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");MODULE_ALIAS("cfi_cmdset_0003");MODULE_ALIAS("cfi_cmdset_0200");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?