📄 cfi_cmdset_0020.c
字号:
the address actually falls */ i--; if ((instr->addr + instr->len) & (regions[i].erasesize-1)) return -EINVAL; chipnum = instr->addr >> cfi->chipshift; adr = instr->addr - (chipnum << cfi->chipshift); len = instr->len; i=first; while(len) { ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); if (ret) return ret; adr += regions[i].erasesize; len -= regions[i].erasesize; if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) i++; if (adr >> cfi->chipshift) { adr = 0; chipnum++; if (chipnum >= cfi->numchips) break; } } instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0;}static void cfi_staa_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; DECLARE_WAITQUEUE(wait, current); for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; retry: spin_lock_bh(chip->mutex); switch(chip->state) { case FL_READY: case FL_STATUS: case FL_CFI_QUERY: case FL_JEDEC_QUERY: 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. */ case FL_SYNCING: spin_unlock_bh(chip->mutex); break; default: /* Not an idle state */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); goto retry; } } /* Unlock the chips again */ for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock_bh(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); } spin_unlock_bh(chip->mutex); }}static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){ struct cfi_private *cfi = map->fldrv_priv; map_word status, status_OK; unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); timeo = jiffies + HZ;retry: spin_lock_bh(chip->mutex); /* Check that the chip's ready to talk to us. */ switch (chip->state) { case FL_CFI_QUERY: case FL_JEDEC_QUERY: case FL_READY: map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; case FL_STATUS: status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); printk(KERN_ERR "waiting for chip to be ready timed out in lock\n"); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); goto retry; default: /* Stick ourselves on a wait queue to be woken when someone changes the status */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + HZ; goto retry; } ENABLE_VPP(map); map_write(map, CMD(0x60), adr); map_write(map, CMD(0x01), adr); chip->state = FL_LOCKING; spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ timeo = jiffies + (HZ*2); for (;;) { status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; /* OK Still waiting */ if (time_after(jiffies, timeo)) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]); DISABLE_VPP(map); spin_unlock_bh(chip->mutex); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } /* Done and happy. */ chip->state = FL_STATUS; DISABLE_VPP(map); wake_up(&chip->wq); spin_unlock_bh(chip->mutex); return 0;}static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long adr; int chipnum, ret = 0;#ifdef DEBUG_LOCK_BITS int ofs_factor = cfi->interleave * cfi->device_type;#endif if (ofs & (mtd->erasesize - 1)) return -EINVAL; if (len & (mtd->erasesize -1)) return -EINVAL; if ((len + ofs) > mtd->size) return -EINVAL; chipnum = ofs >> cfi->chipshift; adr = ofs - (chipnum << cfi->chipshift); while(len) {#ifdef DEBUG_LOCK_BITS cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);#ifdef DEBUG_LOCK_BITS cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif if (ret) return ret; adr += mtd->erasesize; len -= mtd->erasesize; if (adr >> cfi->chipshift) { adr = 0; chipnum++; if (chipnum >= cfi->numchips) break; } } return 0;}static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr){ struct cfi_private *cfi = map->fldrv_priv; map_word status, status_OK; unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); timeo = jiffies + HZ;retry: spin_lock_bh(chip->mutex); /* Check that the chip's ready to talk to us. */ switch (chip->state) { case FL_CFI_QUERY: case FL_JEDEC_QUERY: case FL_READY: map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; case FL_STATUS: status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n"); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); goto retry; default: /* Stick ourselves on a wait queue to be woken when someone changes the status */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + HZ; goto retry; } ENABLE_VPP(map); map_write(map, CMD(0x60), adr); map_write(map, CMD(0xD0), adr); chip->state = FL_UNLOCKING; spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ timeo = jiffies + (HZ*2); for (;;) { status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; /* OK Still waiting */ if (time_after(jiffies, timeo)) { map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]); DISABLE_VPP(map); spin_unlock_bh(chip->mutex); return -EIO; } /* Latency issues. Drop the unlock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } /* Done and happy. */ chip->state = FL_STATUS; DISABLE_VPP(map); wake_up(&chip->wq); spin_unlock_bh(chip->mutex); return 0;}static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; unsigned long adr; int chipnum, ret = 0;#ifdef DEBUG_LOCK_BITS int ofs_factor = cfi->interleave * cfi->device_type;#endif chipnum = ofs >> cfi->chipshift; adr = ofs - (chipnum << cfi->chipshift);#ifdef DEBUG_LOCK_BITS { unsigned long temp_adr = adr; unsigned long temp_len = len; cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); while (temp_len) { printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); temp_adr += mtd->erasesize; temp_len -= mtd->erasesize; } cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); }#endif ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);#ifdef DEBUG_LOCK_BITS cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);#endif return ret;}static int cfi_staa_suspend(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_bh(chip->mutex); switch(chip->state) { case FL_READY: case FL_STATUS: case FL_CFI_QUERY: case FL_JEDEC_QUERY: 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. */ case FL_PM_SUSPENDED: break; default: ret = -EAGAIN; break; } spin_unlock_bh(chip->mutex); } /* Unlock the chips again */ if (ret) { for (i--; i >=0; i--) { chip = &cfi->chips[i]; spin_lock_bh(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; wake_up(&chip->wq); } spin_unlock_bh(chip->mutex); } } return ret;}static void cfi_staa_resume(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int i; struct flchip *chip; for (i=0; i<cfi->numchips; i++) { chip = &cfi->chips[i]; spin_lock_bh(chip->mutex); /* Go to known state. Chip may have been power cycled */ if (chip->state == FL_PM_SUSPENDED) { map_write(map, CMD(0xFF), 0); chip->state = FL_READY; wake_up(&chip->wq); } spin_unlock_bh(chip->mutex); }}static void cfi_staa_destroy(struct mtd_info *mtd){ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; kfree(cfi->cmdset_priv); kfree(cfi);}MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -