# 關于系統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
- 前言
- 荔枝派TODO任務領取
- linux使用小貼士
- 入門篇
- 板卡介紹
- 開箱指南
- 燒錄啟動系統
- 聯網方法
- 鏡像使用
- 鏡像說明
- buildroot系統使用
- debian系統使用
- 外設操作
- 外設操作概覽
- 低速外設
- GPIO
- GPIO模擬低速接口
- UART
- PWM
- I2C
- SPI
- 高速接口
- SDIO
- USB
- EtherNet
- DVP CSI
- MIPI CSI
- 模擬外設
- CODEC
- LRADC
- 常見設備驅動
- USB攝像頭
- USB 3G/4G 網卡
- 舵機
- 開發篇
- UBOOT適配
- UBOOT編譯
- UBOOT配置
- UBOOT配置屏幕分辨率
- UBOOT配置SPI啟動
- Linux內核開發
- Linux內核編譯
- BSP Linux內核編譯.md
- Linux內核選項
- 外設驅動與設備樹
- RTL8723BS驅動
- 根文件系統定制
- buildroot定制系統
- buildroot添加軟件包
- openwrt定制系統
- emdebian定制系統
- camdriod開發
- camdriod編譯
- 主線Uboot引導Camdriod
- 系統鏡像打包
- XBOOT適配
- 荔枝運行XBOOT
- 應用篇
- 游戲機-基于EmulationStation
- 游戲機-gnuboy
- 語音識別-科大訊飛云
- GUI-QT5
- 語音識別-離線關鍵詞識別
- 路由器-Lichee Zero
- 投稿文章
- 荔枝派Zero開箱指南
- Zero i2c oled使用指南
- zero SPI LCD使用指南
- Zero u-boot編譯和使用指南
- TF WiFi使用方法
- Zero Ethernet使用指南
- Zero 移植Qt5.4.1
- ZeroSpiNorFlash啟動系統制作指南
- Visio-uboot-sunxi流程
- lichee 編譯踩坑記錄(ilichee ZERO)
- lichee_zero_外設GPIO接口
- TF WIFI 小白編
- 從零開始LicheePi Zero的開發
- 認識Zero的硬件
- 搭建Zero的開發環境
- 主線Uboot
- 主線kernel
- BSP kernel
- BSP內核啟動
- bsp內核的攝像頭使用
- BSP內核中的保留內存
- uboot啟動BSP內核常見錯誤
- BSP內核 FBTFT移植
- BSP內核啟動錯誤及警告解決
- buildroot 根文件系統
- emdebian 根文件系統
- SPI Flash 系統編譯
- sunxi-fel增加對16M 以上flash的支持
- overlayfs的使用
- jffs2系統掛載不上的常見原因
- JFFS2 文件系統簡介
- uboot對spi flash的識別
- bsp內核的SPI flash啟動
- Docker開發環境
- Docker 命令速查
- 基礎ubuntu系統配置
- docker離線鏡像
- Zero系統燒錄
- dd鏡像燒錄
- 分區鏡像燒錄
- SPI Flash系統燒錄
- 一鍵鏡像燒錄
- Zero外設把玩
- I2C操作
- PWM輸出
- CODEC的使用
- 以太網使用指南
- GPIO操作
- 文件IO方式
- C語言接口(mmap)
- Python操作GPIO
- pinctrl-sunxi介紹
- UART操作
- 點屏
- 點屏之RGB屏
- 點屏之SPI屏 ili9341
- 點屏之SPI OLED
- 點屏之I2C OLED
- 點屏之SPI屏 ili9488
- 點屏之MCU屏
- 點屏之觸摸屏驅動
- 點屏之simple-framebuffer
- 點屏之屏幕時序
- 時鐘控制器CCM
- 攝像頭
- BSP DVP攝像頭
- BSP MIPI 攝像頭
- 主線DVP攝像頭
- 主線 MIPI攝像頭
- SPI 操作
- 應用層開發
- 開機自啟動
- Segment Fault調試
- Zero通過OTG共享PC網絡
- USB攝像頭使用
- 基于QT的GUI開發
- 移植tslib
- 移植QT5.9.1
- 移植QT4.8.7
- QtCreator使用
- Qt5.x移植到Qt4.8
- Qt字體相關
- Qt移植總結
- Qt裁剪
- Qt去除鼠標指針顯示
- zero_imager使用
- 驅動開發
- 設備樹簡介
- GPU/DRM 顯示驅動
- sys下設備樹查看
- atmel觸摸屏驅動分析
- atmel觸摸屏中斷改輪詢
- uboot下gpio操作
- helloworld驅動編譯演示
- FBTFT分析
- 內核模塊靜態加載的順序
- SPI驅動分析
- SPI 驅動編寫
- Uboot開發
- 開機logo
- 看門狗的使用
- 關于系統reboot
- 內核printk等級設置