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 + -
显示快捷键?