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

重启失败

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);
}
void do_kernel_restart(char *cmd)
{
        atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
}
register_restart_handler
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)
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信息

原因

是使用了32Mflash,在重启的时候,没有退出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