# 关于系统reboot 在使用spi flash时,执行reboot命令,有时会无法重启,这里追查下原因。 ## 正常重启信息 ~~~ # reboot # Stopping network: OK Saving random seed... done. Stopping logging: OK umount: devtmpfs busy - remounted read-only [ 16.812893] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null) Sent SIGTERM to all processes Sent SIGKILL to all processes Requesting system reboot [ 18.830716] reboot: Restarting system ~~~ kernel/reboot.c: ~~~ void kernel_restart(char *cmd) { kernel_restart_prepare(cmd); migrate_to_reboot_cpu(); syscore_shutdown(); if (!cmd) pr_emerg("Restarting system\n"); else pr_emerg("Restarting system with command '%s'\n", cmd); kmsg_dump(KMSG_DUMP_RESTART); machine_restart(cmd); } ~~~ arch/arm/kernel/setup.c: arm_pm_restart = mdesc->restart; ## 重启失败 arch/arm/kernel/reboot.c ~~~ void machine_restart(char *cmd) { local_irq_disable(); smp_send_stop(); if (arm_pm_restart) arm_pm_restart(reboot_mode, cmd); else do_kernel_restart(cmd); //正常来说不会走到这里 /* Give a grace period for failure to restart of 1s */ mdelay(1000); /* Whoops - the platform was unable to reboot. Tell the user! */ printk("Reboot failed -- System halted\n"); while (1); } ~~~ kernel/reboot.c ~~~ void do_kernel_restart(char *cmd) { atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd); } ~~~ register_restart_handler kernel/notifier.c ~~~ int atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v) { return __atomic_notifier_call_chain(nh, val, v, -1, NULL); } ~~~ ## spi flash问题 ~~~ [ 312.719945] INFO: trying to register non-static key. [ 312.724967] the code is fine but needs lockdep annotation. [ 312.730448] turning off the locking correctness validator. [ 312.735943] CPU: 0 PID: 162 Comm: sync Not tainted 4.13.0-licheepi-zero+ #55 [ 312.742981] Hardware name: Allwinner sun8i Family [ 312.747734] [<c010e8a8>] (unwind_backtrace) from [<c010b594>] (show_stack+0x10/0x14) [ 312.755483] [<c010b594>] (show_stack) from [<c048ec4c>] (dump_stack+0x84/0x98) [ 312.762711] [<c048ec4c>] (dump_stack) from [<c015e698>] (register_lock_class+0x3f8/0x624) [ 312.770886] [<c015e698>] (register_lock_class) from [<c015fb0c>] (__lock_acquire.constprop.7+0x60/0x954) [ 312.780358] [<c015fb0c>] (__lock_acquire.constprop.7) from [<c0160468>] (lock_acquire+0x68/0x84) [ 312.789143] [<c0160468>] (lock_acquire) from [<c0132498>] (flush_work+0x50/0x290) [ 312.796624] [<c0132498>] (flush_work) from [<c0133f00>] (__cancel_work_timer+0xec/0x1c4) [ 312.804722] [<c0133f00>] (__cancel_work_timer) from [<c028d1b4>] (jffs2_sync_fs+0x14/0x38) [ 312.812995] [<c028d1b4>] (jffs2_sync_fs) from [<c0207e30>] (iterate_supers+0xc0/0x120) [ 312.820912] [<c0207e30>] (iterate_supers) from [<c0233708>] (sys_sync+0x44/0xa4) [ 312.828310] [<c0233708>] (sys_sync) from [<c0107620>] (ret_fast_syscall+0x0/0x3c) ~~~ fs/jffs2/super.c ~~~ static int jffs2_sync_fs(struct super_block *sb, int wait) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); #ifdef CONFIG_JFFS2_FS_WRITEBUFFER cancel_delayed_work_sync(&c->wbuf_dwork); #endif mutex_lock(&c->alloc_sem); jffs2_flush_wbuf_pad(c); mutex_unlock(&c->alloc_sem); return 0; } ~~~ ~~~ bool cancel_delayed_work_sync(struct delayed_work *dwork) { return __cancel_work_timer(&dwork->work, true); } EXPORT_SYMBOL(cancel_delayed_work_sync); ~~~ CONFIG_JFFS2_FS_WRITEBUFFER去掉,可以不出现oops信息 ## 原因 是使用了32M flash,在重启的时候,没有退出4-byte地址模式导致。(因为板子上没有PMU,没有对flash进行复位) ~~~ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, const struct flash_info *info) { /* Do some manufacturer fixups first */ switch (JEDEC_MFR(info)) { case SNOR_MFR_SPANSION: /* No small sector erase for 4-byte command set */ nor->erase_opcode = SPINOR_OP_SE; nor->mtd.erasesize = info->sector_size; break; default: break; } nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); } /* Enable/disable 4-byte addressing mode. */ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) { int status; bool need_wren = false; u8 cmd; switch (JEDEC_MFR(info)) { case SNOR_MFR_MICRON: /* Some Micron need WREN command; all will accept it */ need_wren = true; case SNOR_MFR_MACRONIX: case SNOR_MFR_WINBOND: if (need_wren) write_enable(nor); //nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; status = nor->write_reg(nor, cmd, NULL, 0); if (need_wren) write_disable(nor); return status; default: /* Spansion style */ nor->cmd_buf[0] = enable << 7; return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); } } ~~~ ~~~ struct m25p { struct spi_device *spi; struct spi_nor spi_nor; u8 command[MAX_CMD_SIZE]; }; ~~~ ~~~ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); //add to exit 4-byte address mode /* Clean up MTD stuff. */ return mtd_device_unregister(&flash->spi_nor.mtd); } ~~~ 新增关机接口 ~~~ static void m25p_shutdown(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); struct spi_nor nor = flash->spi_nor; int status; //add to exit 4-byte address mode nor.write_reg(&nor, SPINOR_OP_WREN, NULL, 0); status = nor.write_reg(&nor, SPINOR_OP_EX4B, NULL, 0); printk("remove spi flash!\n"); /* Clean up MTD stuff. */ mtd_device_unregister(&flash->spi_nor.mtd); return; } ~~~ ~~~ static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .of_match_table = m25p_of_table, }, .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. * And also when they're otherwise idle... */ }; ~~~ CONFIG_SPI_FLASH_BAR ## 参考资料 http://www.wowotech.net/linux_kenrel/reboot.html http://blog.csdn.net/manfeel/article/details/43530817