linux sdio card休眠处理 sdio card removed解决办法

本文详细介绍了在SDIO卡使用过程中遇到的card removed问题及解决方案,通过设置nonremovable和keeppower避免睡眠模式下的异常行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         最近调试几款sdio card suspend时都会出现sdio card removed,之后 

要么死机要么模块不能正常工作,根本原因也就是休眠没有处理好。昨天终于找到了

解决方法。

         1:host端需要设置nonremovable,软件设置:mmc->caps |= 
MMC_CAP_NONREMOVABLE;
         2:host端需要设置keep power,在sdio card suspend时 软件设 
置:host->pm_flags | = MMC_PM_KEEP_POWER;


         目前我所接触到的4g网卡,博通网卡,sdio加密t卡等都会出现card 
removed问题。

         关于2补充下需要在sdio card pm中置host keep power:


         static int XXX_suspend(struct device *pdev)
{
     struct sdio_func *func = dev_to_sdio_func(pdev);

     /* keep power while host suspended */
     ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
     if (ret) {
         sd_err(("%s: error while trying to keep power\n", __FUNCTION__));
         return ret;
     }

     return 0;
}

static const struct dev_pm_ops XXX_pm_ops = {
     .suspend    = XXX_suspend,
     .resume        = XXX_resume,
};


          今天花了点时间理清了card removed的原因。

        出现1错误的原因是在resume 时pm_notify调用到了msm_rescan,如果没 
有置nonremovable,将会跑进detect,而进去就会detect出了card removed,
进而进行了移除操作。


       
  void mmc_rescan(struct work_struct *work)
     {
         struct mmc_host *host =
             container_of(work, struct mmc_host, detect.work);
         bool extend_wakelock = false;

         if (host->rescan_disable)
             return;

         mmc_bus_get(host);

         /*
          * if there is a _removable_ card registered, check whether it is
          * still present
          */
         if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
             && !(host->caps & MMC_CAP_NONREMOVABLE))
             host->bus_ops->detect(host);
         ---------
     }
         下面是dump_stack()打印的调用信息:
<4>[   48.709320] [<c0013d4c>] (unwind_backtrace+0x0/0x11c) from 
[<bf011d74>] (dhdsdio_disconnect+0xc/0x10c [bcmdhd])
<4>[   48.720214] [<bf011d74>] (dhdsdio_disconnect+0xc/0x10c [bcmdhd]) 
from [<bf01f9a8>] (bcmsdh_remove+0x1c/0x98 [bcmdhd])
<4>[   48.730041] [<bf01f9a8>] (bcmsdh_remove+0x1c/0x98 [bcmdhd]) from 
[<bf001a00>] (bcmsdh_sdmmc_remove+0x28/0x70 [bcmdhd])
<4>[   48.740600] [<bf001a00>] (bcmsdh_sdmmc_remove+0x28/0x70 [bcmdhd]) 
from [<c05855e0>] (sdio_bus_remove+0x38/0xf0)
<4>[   48.753021] [<c05855e0>] (sdio_bus_remove+0x38/0xf0) from 
[<c03a26c8>] (__device_release_driver+0x9c/0xe0)
<4>[   48.762725] [<c03a26c8>] (__device_release_driver+0x9c/0xe0) from 
[<c03a2728>] (device_release_driver+0x1c/0x28)
<4>[   48.771881] [<c03a2728>] (device_release_driver+0x1c/0x28) from 
[<c03a21f8>] (bus_remove_device+0x124/0x140)
<4>[   48.781829] [<c03a21f8>] (bus_remove_device+0x124/0x140) from 
[<c039fe30>] (device_del+0x108/0x16c)
<4>[   48.790802] [<c039fe30>] (device_del+0x108/0x16c) from 
[<c058596c>] (sdio_remove_func+0x1c/0x28)
<4>[   48.799560] [<c058596c>] (sdio_remove_func+0x1c/0x28) from 
[<c0584bfc>] (mmc_sdio_remove+0x3c/0x68)
<4>[   48.808593] [<c0584bfc>] (mmc_sdio_remove+0x3c/0x68) from 
[<c0584cb4>] (mmc_sdio_detect+0x8c/0xb4)
<4>[   48.817565] [<c0584cb4>] (mmc_sdio_detect+0x8c/0xb4) from 
[<c057e0c8>] (mmc_rescan+0x7c/0x2d8)
<4>[   48.826141] [<c057e0c8>] (mmc_rescan+0x7c/0x2d8) from [<c0099dd8>] 
(process_one_work+0x27c/0x484)
<4>[   48.834991] [<c0099dd8>] (process_one_work+0x27c/0x484) from 
[<c009a1f0>] (worker_thread+0x210/0x3b0)
<4>[   48.844177] [<c009a1f0>] (worker_thread+0x210/0x3b0) from 
[<c009e08c>] (kthread+0x80/0x8c)
<4>[   48.852355] [<c009e08c>] (kthread+0x80/0x8c) from [<c000eaa8>] 
(kernel_thread_exit+0x0/0x8)
<6>[   49.083587] mmc2: card 0001 removed


          出现2错误的原因是在sdio resume时,如果没有设置keep power就会 
跑sdio reset与go idle(CMD 0)后进入init_card第一个CMD就不会响应了,也就是
这2个操作后card异常了。


  
static int mmc_sdio_resume(struct mmc_host *host)
{
     int i, err = 0;

     BUG_ON(!host);
     BUG_ON(!host->card);

     /* Basic card reinitialization. */
     mmc_claim_host(host);

     /* No need to reinitialize powered-resumed nonremovable cards */
     if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
         sdio_reset(host);
         mmc_go_idle(host);
         err = mmc_sdio_init_card(host, host->ocr, host->card,
                     mmc_card_keep_power(host));
         ---------
}
        以下是dump_stack()打印信息:
     <4>[   55.269378] [<c0013d4c>] (unwind_backtrace+0x0/0x11c) from 
[<c057d650>] (mmc_resume_host+0xec/0x15c)
<4>[   55.269439] [<c057d650>] (mmc_resume_host+0xec/0x15c) from 
[<c058bfdc>] (msmsdcc_runtime_resume+0xb8/0x17c)
<4>[   55.269500] [<c058bfdc>] (msmsdcc_runtime_resume+0xb8/0x17c) from 
[<c058c2ac>] (msmsdcc_pm_resume+0x44/0xa8)
<4>[   55.269561] [<c058c2ac>] (msmsdcc_pm_resume+0x44/0xa8) from 
[<c03a4074>] (platform_pm_resume+0x40/0x54)
<4>[   55.269653] [<c03a4074>] (platform_pm_resume+0x40/0x54) from 
[<c03a8160>] (dpm_run_callback+0x44/0x7c)
<4>[   55.269683] [<c03a8160>] (dpm_run_callback+0x44/0x7c) from 
[<c03a8c18>] (device_resume+0x140/0x184)
<4>[   55.269744] [<c03a8c18>] (device_resume+0x140/0x184) from 
[<c03a94ec>] (dpm_resume+0xfc/0x234)
<4>[   55.269805] [<c03a94ec>] (dpm_resume+0xfc/0x234) from [<c03a97f0>] 
(dpm_resume_end+0xc/0x18)
<4>[   55.269866] [<c03a97f0>] (dpm_resume_end+0xc/0x18) from 
[<c00b63bc>] (suspend_devices_and_enter+0x240/0x314)
<4>[   55.269927] [<c00b63bc>] (suspend_devices_and_enter+0x240/0x314) 
from [<c00b65b0>] (pm_suspend+0x120/0x200)
<4>[   55.269958] [<c00b65b0>] (pm_suspend+0x120/0x200) from 
[<c00b7508>] (suspend+0x68/0x180)
<4>[   55.270019] [<c00b7508>] (suspend+0x68/0x180) from [<c0099dd8>] 
(process_one_work+0x27c/0x484)
<4>[   55.270080] [<c0099dd8>] (process_one_work+0x27c/0x484) from 
[<c009a1f0>] (worker_thread+0x210/0x3b0)
<4>[   55.270141] [<c009a1f0>] (worker_thread+0x210/0x3b0) from 
[<c009e08c>] (kthread+0x80/0x8c)
<4>[   55.270202] [<c009e08c>] (kthread+0x80/0x8c) from [<c000eaa8>] 
(kernel_thread_exit+0x0/0x8)
<4>[   55.270233] mmc2: error -110 during resume (card was removed?)


以上2点做到了理论上kernel可以正常睡眠了,下面是正常的睡眠log:



### RTW SDIO MMC I2C 技术含义与关联解析 #### SDIO 技术概述 SDIO(Secure Digital Input Output)是一种基于 SD 卡接口的扩展协议,允许通过 SD 插槽连接各种外围设备。SDIO 不仅保留了 SD 存储卡的功能,还增加了对输入/输出外设的支持,例如 Wi-Fi 模块、蓝牙模块等[^2]。在 Linux 系统中,SDIO 设备的识别过程由 `mmc_attach_sdio(host)` 函数实现,该函数位于 `drivers/mmc/core/sdio.c` 文件中。主机控制器会根据一定的顺序识别设备类型,依次尝试识别为 SDIO、SD 和 MMC 设备,并通过发送不同命令来确认设备类型[^3]。 #### MMC 技术特性 MMC(MultiMediaCard)是一种早期的存储卡标准,后来被 SD 卡所取代,但其底层通信协议仍然广泛使用于嵌入式系统中。MMC 接口支持多种类型的设备,包括纯存储设备和 I/O 设备。Wi-Fi 模块通常作为 SDIO 类型存在,因此在驱动初始化时会被标记为 `MMC_TYPE_SDIO`。这种分类对于后续的设备操作和电源管理策略具有重要意义[^1]。 #### I2C 与 SDIO 的对比 I2C(Inter-Integrated Circuit)是一种串行总线协议,用于连接低速外设芯片,常用于传感器、EEPROM 等设备之间的通信。相比之下,SDIO 是一种更高速的接口,适用于需要更高带宽的数据传输场景,如无线网络模块。虽然两者都可用于连接外设,但 I2C 更适合短距离、低功耗、低速率的应用,而 SDIO 更适合需要较高吞吐量的设备,如 Wi-Fi 或以太网适配器。 #### SDIO 设备的电源管理问题 在 SDIO 设备运行过程中,可能会出现因主机控制器进入休眠状态而导致的“card removed”问题。为了解决这一问题,可以在主机端设置 `mmc->caps |= MMC_CAP_NONREMOVABLE;` 来告知系统该设备不可移除。此外,在 SDIO 设备挂起期间,还需要设置 `host->pm_flags |= MMC_PM_KEEP_POWER;` 以保持供电状态,防止设备断开连接[^4]。 #### RTW 相关技术应用 RTW(Realtek Wireless)Wi-Fi 模块通常采用 SDIO 接口与主控通信,这类模块在 Linux 内核中依赖于 SDIO 子系统的支持。由于 SDIO 接口具备较高的数据吞吐能力,因此非常适合用于无线通信模块的数据传输需求。同时,为了确保 SDIO 接口在系统休眠时仍能正常工作,必须正确配置电源管理标志位,以避免设备被误认为已移除。 ```c // 设置不可移除标志位 mmc->caps |= MMC_CAP_NONREMOVABLE; // 在 suspend 阶段保持供电 host->pm_flags |= MMC_PM_KEEP_POWER; ``` 这些设置在某些 4G 网卡、博通 Wi-Fi 模块以及 SDIO 加密卡中均有实际应用案例[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值