关于系统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