⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cfi_cmdset_0002.c

📁 mtd 模块 good for you
💻 C
📖 第 1 页 / 共 3 页
字号:
		printk(KERN_DEBUG "Wake up to write:\n");		if(signal_pending(current))			return -EINTR;#endif		timeo = jiffies + HZ;		goto retry;	}		chip->state = FL_WRITING;	adr += chip->start;	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",	       __func__, adr, datum );	ENABLE_VPP(map);	if (fast) { /* Unlock bypass */		cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);	}	else {	        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	        cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	}	cfi_write(map, datum, adr);	cfi_spin_unlock(chip->mutex);	cfi_udelay(chip->word_write_time);	cfi_spin_lock(chip->mutex);	/*	 * Polling toggle bits instead of reading back many times	 * This ensures that write operation is really completed,	 * or tells us why it failed.	 *	 * It appears tha the polling and decoding of error state might	 * be simplified.  Don't do it unless you really know what you	 * are doing.  You must remember that JESD21-C 3.5.3 states that	 * the status must be read back an _additional_ two times before	 * a failure is determined.  This is because these devices have	 * internal state machines that are asynchronous to the external	 * data bus.  During an erase or write the read-back status of the	 * polling bits might be transitioning internaly when the external	 * read-back occurs.  This means that the bits aren't in the final	 * state and they might appear to report an error as they transition	 * and are in a weird state.  This will produce infrequent errors	 * that will usually disappear the next time an erase or write	 * happens (Try tracking those errors down!).  To ensure that	 * the bits are not in transition the location must be read-back	 * two more times and compared against what was written - BOTH reads	 * MUST match what was written - don't think this can be simplified	 * to only the last read matching.  If the comparison fails, error	 * state can then be decoded.	 *	 * - Thayne Harbaugh	 */	dq6 = CMD(1<<6);	/* See comment above for timeout value. */	timeo = jiffies + uWriteTimeout; 			oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",	       __func__, oldstatus, status );	/*	 * This only checks if dq6 is still toggling and that our	 * timer hasn't expired.  We purposefully ignore the chips	 * internal timer that will assert dq5 and leave dq6 toggling.	 * This is done for a variety of reasons:	 * 1) Not all chips support dq5.	 * 2) Dealing with asynchronous status bit and data updates	 *    and reading a device two more times creates _messy_	 *    logic when trying to deal with interleaved devices -	 *    some may be changing while others are still busy.	 * 3) Checking dq5 only helps to optimize an error case that	 *    should at worst be infrequent and at best non-existent.	 *	 * If our timeout occurs _then_ we will check dq5 to see	 * if the device also had an internal timeout.	 */	while( ( ( status ^ oldstatus ) & dq6 )	       && ! ( ta = time_after(jiffies, timeo) ) ) {		if (need_resched()) {			cfi_spin_unlock(chip->mutex);			yield();			cfi_spin_lock(chip->mutex);		} else 			udelay(1);		oldstatus = cfi_read( map, adr );		status = cfi_read( map, adr );		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",		       __func__, oldstatus, status );	}	/*	 * Something kicked us out of the read-back loop.  We'll	 * check success befor checking failure.	 * Even though dq6 might be true data, it is unkown if	 * all of the other bits have changed to true data due to	 * the asynchronous nature of the internal state machine.	 * We will read two more times and use this to either	 * verify that the write completed successfully or	 * that something really went wrong.  BOTH reads	 * must match what was written - this certifies that	 * bits aren't still changing  and that the status	 * bits erroneously match the datum that was written.	 */	prev_oldstatus = oldstatus;	prev_status = status;	oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",	       __func__, oldstatus, status );	if ( oldstatus == datum && status == datum ) {		/* success - do nothing */		goto write_done;	}	if ( ta ) {		int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;		if ( status & dq5mask ) {			/* dq5 asserted - decode interleave chips */			printk( KERN_WARNING				"MTD %s(): FLASH internal timeout: 0x%.8x\n",				__func__,				status & dq5mask );		} else {			printk( KERN_WARNING				"MTD %s(): Software timed out during write.\n",				__func__ );		}		goto write_failed;	}	/*	 * If we get to here then it means that something	 * is wrong and it's not a timeout.  Something	 * is seriously wacky!  Dump some debug info.	 */	printk(KERN_WARNING	       "MTD %s(): Wacky!  Unable to decode failure status\n",	       __func__ );	printk(KERN_WARNING	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",	       __func__, adr, datum,	       prev_oldstatus, prev_status,	       oldstatus, status); write_failed:	ret = -EIO;	/* reset on all failures. */	cfi_write( map, CMD(0xF0), chip->start ); write_done:	DISABLE_VPP(map);	chip->state = FL_READY;	wake_up(&chip->wq);	cfi_spin_unlock(chip->mutex);	return ret;}static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf){	struct map_info *map = mtd->priv;	struct cfi_private *cfi = map->fldrv_priv;	int ret = 0;	int chipnum;	unsigned long ofs, chipstart;	*retlen = 0;	if (!len)		return 0;	chipnum = to >> cfi->chipshift;	ofs = to  - (chipnum << cfi->chipshift);	chipstart = cfi->chips[chipnum].start;	/* If it's not bus-aligned, do the first byte write */	if (ofs & (CFIDEV_BUSWIDTH-1)) {		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);		int i = ofs - bus_ofs;		int n = 0;		u_char tmp_buf[8];		__u32 datum;		map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);		while (len && i < CFIDEV_BUSWIDTH)			tmp_buf[i++] = buf[n++], len--;		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum], 				       bus_ofs, datum, 0);		if (ret) 			return ret;				ofs += n;		buf += n;		(*retlen) += n;		if (ofs >> cfi->chipshift) {			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;		}	}		if (cfi->fast_prog) {		/* Go into unlock bypass mode */		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);	}	/* We are now aligned, write as much as possible */	while(len >= CFIDEV_BUSWIDTH) {		__u32 datum;		if (cfi_buswidth_is_1()) {			datum = *(__u8*)buf;		} else if (cfi_buswidth_is_2()) {			datum = *(__u16*)buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)buf;		} else {			return -EINVAL;		}		ret = do_write_oneword(map, &cfi->chips[chipnum],				       ofs, datum, cfi->fast_prog);		if (ret) {			if (cfi->fast_prog){				/* Get out of unlock bypass mode */				cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);				cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);			}			return ret;		}		ofs += CFIDEV_BUSWIDTH;		buf += CFIDEV_BUSWIDTH;		(*retlen) += CFIDEV_BUSWIDTH;		len -= CFIDEV_BUSWIDTH;		if (ofs >> cfi->chipshift) {			if (cfi->fast_prog){				/* Get out of unlock bypass mode */				cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);				cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);			}			chipnum ++; 			ofs = 0;			if (chipnum == cfi->numchips)				return 0;			chipstart = cfi->chips[chipnum].start;			if (cfi->fast_prog){				/* Go into unlock bypass mode for next set of chips */				cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);				cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);				cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);			}		}	}	if (cfi->fast_prog){		/* Get out of unlock bypass mode */		cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);		cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);	}	/* Write the trailing bytes if any */	if (len & (CFIDEV_BUSWIDTH-1)) {		int i = 0, n = 0;		u_char tmp_buf[8];		__u32 datum;		map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);		while (len--)			tmp_buf[i++] = buf[n++];		if (cfi_buswidth_is_2()) {			datum = *(__u16*)tmp_buf;		} else if (cfi_buswidth_is_4()) {			datum = *(__u32*)tmp_buf;		} else {			return -EINVAL;  /* should never happen, but be safe */		}		ret = do_write_oneword(map, &cfi->chips[chipnum], 				ofs, datum, 0);		if (ret) 			return ret;				(*retlen) += n;	}	return 0;}static inline int do_erase_chip(struct map_info *map, struct flchip *chip){	unsigned int oldstatus, status, prev_oldstatus, prev_status;	unsigned int dq6;	unsigned long timeo = jiffies + HZ;	unsigned long int adr;	struct cfi_private *cfi = map->fldrv_priv;	DECLARE_WAITQUEUE(wait, current);	int ret = 0;	int ta = 0;	__u32 ones = 0; retry:	cfi_spin_lock(chip->mutex);	if (chip->state != FL_READY){		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&chip->wq, &wait);                		cfi_spin_unlock(chip->mutex);		schedule();		remove_wait_queue(&chip->wq, &wait);#if 0		if(signal_pending(current))			return -EINTR;#endif		timeo = jiffies + HZ;		goto retry;	}		chip->state = FL_ERASING;	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",	       __func__, chip->start );		/* Handle devices with one erase region, that only implement	 * the chip erase command.	 */	ENABLE_VPP(map);	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);	timeo = jiffies + (HZ*20);	adr = cfi->addr_unlock1;	/* Wait for the end of programing/erasure by using the toggle method.	 * As long as there is a programming procedure going on, bit 6	 * is toggling it's state with each consecutive read.	 * The toggling stops as soon as the procedure is completed.	 *	 * If the process has gone on for too long on the chip bit 5 gets.	 * After bit5 is set you can kill the operation by sending a reset	 * command to the chip.	 */	/* see comments in do_write_oneword */	dq6 = CMD(1<<6);	oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",	       __func__, oldstatus, status );	while( ( ( status ^ oldstatus ) & dq6 )	       && ! ( ta = time_after(jiffies, timeo) ) ) {		int wait_reps;		/* an initial short sleep */		cfi_spin_unlock(chip->mutex);		schedule_timeout(HZ/100);		cfi_spin_lock(chip->mutex);				if (chip->state != FL_ERASING) {			/* Someone's suspended the erase. Sleep */			set_current_state(TASK_UNINTERRUPTIBLE);			add_wait_queue(&chip->wq, &wait);						cfi_spin_unlock(chip->mutex);			printk("erase suspended. Sleeping\n");						schedule();			remove_wait_queue(&chip->wq, &wait);#if 0						if (signal_pending(current))				return -EINTR;#endif						timeo = jiffies + (HZ*2); /* FIXME */			cfi_spin_lock(chip->mutex);			continue;		}		/* Busy wait for 1/10 of a milisecond */		for(wait_reps = 0;		    (wait_reps < 100)			    && ( ( status ^ oldstatus ) & dq6 );		    wait_reps++) {						/* Latency issues. Drop the lock, wait a while and retry */			cfi_spin_unlock(chip->mutex);			cfi_udelay(1);			cfi_spin_lock(chip->mutex);			oldstatus = cfi_read(map, adr);			status = cfi_read(map, adr);			DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",			       __func__, oldstatus, status );		}		oldstatus = cfi_read(map, adr);		status = cfi_read(map, adr);		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",		       __func__, oldstatus, status );	}	prev_oldstatus = oldstatus;	prev_status = status;	oldstatus = cfi_read(map, adr);	status = cfi_read(map, adr);	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",	       __func__, oldstatus, status );	ones = CMD( (__u8)~0 );		if ( oldstatus == ones && status == ones ) {		/* success - do nothing */		goto erase_done;	}	if ( ta ) {		int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;		if ( status & dq5mask ) {			/* dq5 asserted - decode interleave chips */			printk( KERN_WARNING				"MTD %s(): FLASH internal timeout: 0x%.8x\n",				__func__,				status & dq5mask );		} else {			printk( KERN_WARNING				"MTD %s(): Software timed out during write.\n",				__func__ );		}		goto erase_failed;	}	printk(KERN_WARNING	       "MTD %s(): Wacky!  Unable to decode failure status\n",	       __func__ );	printk(KERN_WARNING	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",	       __func__, adr, ones,	       prev_oldstatus, prev_status,	       oldstatus, status); erase_failed:	ret = -EIO;	/* reset on all failures. */	cfi_write( map, CMD(0xF0), chip->start ); erase_done:	DISABLE_VPP(map);	chip->state = FL_READY;	wake_up(&chip->wq);	cfi_spin_unlock(chip->mutex);	return ret;}static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){	unsigned int oldstatus, status, prev_oldstatus, prev_status;	unsigned int dq6;	unsigned long timeo = jiffies + HZ;	struct cfi_private *cfi = map->fldrv_priv;	DECLARE_WAITQUEUE(wait, current);	int ret = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -