bcmdhd can't support removing host during suspend and
driver crash when detect card after resume due to no response
to CMD7.
It looks bcmdhd has a special requirement to enumerate card
by itself which is incompatible with current MMC core.
So implement post-cd feature to allow driver to detect card
as it wants, then we add back non-removable capability
to avoid MMC core to redetect card after resume.
root@imx6qdlsolo:~# echo standby > /sys/power/state
PM: Syncing filesystems ... done.
PM: Preparing system for standby sleep
Freezing user space processes ... (elapsed 0.001 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
PM: Entering standby sleep
evbug: Event. Dev: input3, Type: 0, Code: 0, Value: 1
evbug: Event. Dev: input2, Type: 0, Code: 0, Value: 1
PM: suspend of devices complete after 652.363 msecs
PM: suspend devices took 0.660 seconds
PM: late suspend of devices complete after 1.148 msecs
PM: noirq suspend of devices complete after 1.043 msecs
Disabling non-boot CPUs ...
CPU1: shutdown
Enabling non-boot CPUs ...
CPU1 is up
PM: noirq resume of devices complete after 0.534 msecs
PM: early resume of devices complete after 0.553 msecs
evbug: Event. Dev: input2, Type: 1, Code: 116, Value: 1
evbug: Event. Dev: input2, Type: 0, Code: 0, Value: 0
evbug: Event. Dev: input2, Type: 1, Code: 116, Value: 0
evbug: Event. Dev: input2, Type: 0, Code: 0, Value: 0
mmc1: error -110 during resume (card was removed?)
PM: resume of devices complete after 605.525 msecs
PM: resume devices took 0.610 seconds
PM: Finishing wakeup.
Restarting tasks ... done.
WARNING: driver bcmsdh_sdmmc did not remove its interrupt handler!
root@imx6qdlsolo:~# Unable to handle kernel NULL pointer dereference at virtual address 0000022c
pgd = 80004000
[0000022c] *pgd=00000000
Internal error: Oops: 17 [#1] PREEMPT SMP ARM
Modules linked in: bcmdhd evbug ov5647_camera_mipi mxc_mipi_csi mx6s_capture
CPU: 1 PID: 780 Comm: kworker/u4:4 Not tainted 4.1.15-01434-g70f4b36 #1310
Hardware name: Freescale i.MX7 Dual (Device Tree)
Workqueue: kmmcd mmc_rescan
task: a974af80 ti: a846e000 task.ti: a846e000
PC is at _raw_spin_lock_irqsave+0x1c/0x5c
LR is at get_parent_ip+0x10/0x2c
pc : [<8077b9d4>] lr : [<8005207c>] psr: 60050093
sp : a846fc20 ip : 0001001f fp : a800b000
r10: 00000000 r9 : 00000001 r8 : 0000022c
r7 : 00000002 r6 : 0000022c r5 : a0050013 r4 : 0000022c
r3 : a974af80 r2 : 00000001 r1 : a846fc44 r0 : 00000000
Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: a951406a DAC: 00000015
Process kworker/u4:4 (pid: 780, stack limit = 0xa846e210)
Stack: (0xa846fc20 to 0xa8470000)
fc20: 00000000 a846fc50 a846fc44 80061808 00000000 000001dc 00000000 805037fc
fc40: 8d89d5ec 00000000 a974af80 80053e88 00000000 00000000 ab7293c0 00000000
fc60: 7f09c828 000000c9 7f09c828 a916a804 00000001 0001001f a800b000 7f0698a4
fc80: a974afc8 00000001 00000000 00000000 00012ebc a974af80 00000001 80ad46c0
fca0: a974af80 00000000 a8eeccc0 00000001 0001001f a846fd04 00000000 7f099440
fcc0: a800b000 7f0699c4 a846fcdf 00000000 00000001 7f068834 a937c900 0105c688
fce0: a846fd04 a8e20000 00000000 00000001 00000000 7f071f08 a846fd04 a80a0000
fd00: ffffffff 00000000 ffffffff a8e20000 a8e20000 00000000 7f099440 00000000
fd20: 00000000 7f099440 a800b000 7f072f4c a974af80 00000000 00000000 80778564
fd40: a846fd54 a9346550 80330028 00000001 a846e000 a8e20000 7f099440 00000000
fd60: 18005000 a8eeccc0 00000000 7f099440 a800b000 7f073744 a846fd8c 80052130
fd80: a9273898 00000000 a800b000 a8e20000 7f099440 00000001 a8eec200 a9270000
fda0: 00000000 7f099440 a800b000 7f07cd3c 80b81100 8040003f a800b000 00000000
fdc0: 00000000 a8e20000 7f099440 a9270000 a9273000 a9270000 00000000 7f099440
fde0: a800b000 7f02df4c 00000001 a8e20000 7f099440 a8eec200 00000000 a916e008
fe00: 00000000 a90bfb00 a800b000 7f074cbc a9270000 7f099440 a8e20000 00000000
fe20: a8f81610 7f0765ec 7f0765b0 a8eeccc0 a855df40 7f069310 a916a800 a8eec200
fe40: 7f09b414 7f06a950 7f06a908 a8f81608 a8f81600 8050e8b8 a8f81608 7f09b414
fe60: 80b22c70 80379744 a974af80 a8f8163c a8f81608 803797d4 00000005 a81ce930
fe80: a8f81608 8037923c a8f81608 a8f81608 80b93cf4 80376504 a846fea0 800e0e3c
fea0: 00000000 00000000 a8f81608 000000bd a833f000 00000000 00000000 8050ed04
fec0: 00000001 8050dd8c 400f8c0f a833f000 ffffff92 a833f000 a81ce600 8050de30
fee0: 8050ddbc a833f240 a833f1dc 80506048 a90bfb00 a833f240 a800b000 a81ce600
ff00: 00000000 800462f0 a81ce600 80043c94 00000000 a800b000 a90bfb18 a800b014
ff20: a846e000 00000088 80b39379 a90bfb00 a800b000 8004654c 80ad4100 a800b164
ff40: a90bfb00 00000000 a84856c0 a90bfb00 80046500 00000000 00000000 00000000
ff60: 00000000 8004b1e8 2df9acc7 00000000 b5f3ff89 a90bfb00 00000000 00000000
ff80: a846ff80 a846ff80 00000000 00000000 a846ff90 a846ff90 a846ffac a84856c0
ffa0: 8004b10c 00000000 00000000 8000f568 00000000 00000000 00000000 00000000
ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 ecd61557 f82769f5
[<8077b9d4>] (_raw_spin_lock_irqsave) from [<80061808>] (add_wait_queue+0x20/0x48)
[<80061808>] (add_wait_queue) from [<805037fc>] (__mmc_claim_host+0x58/0x1b0)
[<805037fc>] (__mmc_claim_host) from [<7f0698a4>] (sdioh_request_byte+0x1cc/0x2a4 [bcmdhd])
[<7f0698a4>] (sdioh_request_byte [bcmdhd]) from [<7f0699c4>] (sdioh_cfg_write+0x20/0x28 [bcmdhd])
[<7f0699c4>] (sdioh_cfg_write [bcmdhd]) from [<7f068834>] (bcmsdh_cfg_write+0x90/0xdc [bcmdhd])
[<7f068834>] (bcmsdh_cfg_write [bcmdhd]) from [<7f071f08>] (dhdsdio_clk_kso_enab+0x38/0x168 [bcmdhd])
[<7f071f08>] (dhdsdio_clk_kso_enab [bcmdhd]) from [<7f072f4c>] (dhdsdio_clk_devsleep_iovar+0xf4/0x5f4 [bcmdhd])
[<7f072f4c>] (dhdsdio_clk_devsleep_iovar [bcmdhd]) from [<7f073744>] (dhdsdio_bussleep+0x2f8/0x4dc [bcmdhd])
[<7f073744>] (dhdsdio_bussleep [bcmdhd]) from [<7f07cd3c>] (dhd_bus_stop+0x2e8/0x3f0 [bcmdhd])
[<7f07cd3c>] (dhd_bus_stop [bcmdhd]) from [<7f02df4c>] (dhd_detach+0x2a4/0x438 [bcmdhd])
[<7f02df4c>] (dhd_detach [bcmdhd]) from [<7f074cbc>] (dhdsdio_release+0x4c/0x1dc [bcmdhd])
[<7f074cbc>] (dhdsdio_release [bcmdhd]) from [<7f0765ec>] (dhdsdio_disconnect+0x3c/0xa0 [bcmdhd])
[<7f0765ec>] (dhdsdio_disconnect [bcmdhd]) from [<7f069310>] (bcmsdh_remove+0x3c/0x60 [bcmdhd])
[<7f069310>] (bcmsdh_remove [bcmdhd]) from [<7f06a950>] (bcmsdh_sdmmc_remove+0x48/0x60 [bcmdhd])
[<7f06a950>] (bcmsdh_sdmmc_remove [bcmdhd]) from [<8050e8b8>] (sdio_bus_remove+0x30/0xf8)
[<8050e8b8>] (sdio_bus_remove) from [<80379744>] (__device_release_driver+0x70/0xe4)
[<80379744>] (__device_release_driver) from [<803797d4>] (device_release_driver+0x1c/0x28)
[<803797d4>] (device_release_driver) from [<8037923c>] (bus_remove_device+0xd8/0x104)
[<8037923c>] (bus_remove_device) from [<80376504>] (device_del+0x10c/0x210)
[<80376504>] (device_del) from [<8050ed04>] (sdio_remove_func+0x1c/0x28)
[<8050ed04>] (sdio_remove_func) from [<8050dd8c>] (mmc_sdio_remove+0x40/0x70)
[<8050dd8c>] (mmc_sdio_remove) from [<8050de30>] (mmc_sdio_detect+0x74/0x100)
[<8050de30>] (mmc_sdio_detect) from [<80506048>] (mmc_rescan+0xb8/0x314)
[<80506048>] (mmc_rescan) from [<800462f0>] (process_one_work+0x120/0x330)
[<800462f0>] (process_one_work) from [<8004654c>] (worker_thread+0x4c/0x480)
[<8004654c>] (worker_thread) from [<8004b1e8>] (kthread+0xdc/0xf4)
[<8004b1e8>] (kthread) from [<8000f568>] (ret_from_fork+0x14/0x2c)
Code: f10c0080 e3a00001 ebe359b1 f594f000 (e1943f9f)
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
198 lines
6.3 KiB
C
198 lines
6.3 KiB
C
/*
|
|
* include/linux/mmc/sdio.h
|
|
*
|
|
* Copyright 2006-2007 Pierre Ossman
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or (at
|
|
* your option) any later version.
|
|
*/
|
|
|
|
#ifndef LINUX_MMC_SDIO_H
|
|
#define LINUX_MMC_SDIO_H
|
|
|
|
#include <linux/mmc/host.h>
|
|
|
|
/* SDIO commands type argument response */
|
|
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
|
|
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
|
|
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
|
|
|
|
/*
|
|
* SD_IO_RW_DIRECT argument format:
|
|
*
|
|
* [31] R/W flag
|
|
* [30:28] Function number
|
|
* [27] RAW flag
|
|
* [25:9] Register address
|
|
* [7:0] Data
|
|
*/
|
|
|
|
/*
|
|
* SD_IO_RW_EXTENDED argument format:
|
|
*
|
|
* [31] R/W flag
|
|
* [30:28] Function number
|
|
* [27] Block mode
|
|
* [26] Increment address
|
|
* [25:9] Register address
|
|
* [8:0] Byte/block count
|
|
*/
|
|
|
|
#define R4_18V_PRESENT (1<<24)
|
|
#define R4_MEMORY_PRESENT (1 << 27)
|
|
|
|
/*
|
|
SDIO status in R5
|
|
Type
|
|
e : error bit
|
|
s : status bit
|
|
r : detected and set for the actual command response
|
|
x : detected and set during command execution. the host must poll
|
|
the card by sending status command in order to read these bits.
|
|
Clear condition
|
|
a : according to the card state
|
|
b : always related to the previous command. Reception of
|
|
a valid command will clear it (with a delay of one command)
|
|
c : clear by read
|
|
*/
|
|
|
|
#define R5_COM_CRC_ERROR (1 << 15) /* er, b */
|
|
#define R5_ILLEGAL_COMMAND (1 << 14) /* er, b */
|
|
#define R5_ERROR (1 << 11) /* erx, c */
|
|
#define R5_FUNCTION_NUMBER (1 << 9) /* er, c */
|
|
#define R5_OUT_OF_RANGE (1 << 8) /* er, c */
|
|
#define R5_STATUS(x) (x & 0xCB00)
|
|
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */
|
|
|
|
/*
|
|
* Card Common Control Registers (CCCR)
|
|
*/
|
|
|
|
#define SDIO_CCCR_CCCR 0x00
|
|
|
|
#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */
|
|
#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */
|
|
#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */
|
|
#define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 3.00 */
|
|
|
|
#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */
|
|
#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */
|
|
#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */
|
|
#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */
|
|
#define SDIO_SDIO_REV_3_00 4 /* SDIO Spec Version 3.00 */
|
|
|
|
#define SDIO_CCCR_SD 0x01
|
|
|
|
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
|
|
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
|
|
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
|
|
#define SDIO_SD_REV_3_00 3 /* SD Physical Spev Version 3.00 */
|
|
|
|
#define SDIO_CCCR_IOEx 0x02
|
|
#define SDIO_CCCR_IORx 0x03
|
|
|
|
#define SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */
|
|
#define SDIO_CCCR_INTx 0x05 /* Function Interrupt Pending */
|
|
|
|
#define SDIO_CCCR_ABORT 0x06 /* function abort/card reset */
|
|
|
|
#define SDIO_CCCR_IF 0x07 /* bus interface controls */
|
|
|
|
#define SDIO_BUS_WIDTH_MASK 0x03 /* data bus width setting */
|
|
#define SDIO_BUS_WIDTH_1BIT 0x00
|
|
#define SDIO_BUS_WIDTH_RESERVED 0x01
|
|
#define SDIO_BUS_WIDTH_4BIT 0x02
|
|
#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */
|
|
#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */
|
|
|
|
#define SDIO_BUS_ASYNC_INT 0x20
|
|
|
|
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
|
|
|
|
#define SDIO_CCCR_CAPS 0x08
|
|
|
|
#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */
|
|
#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */
|
|
#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */
|
|
#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */
|
|
#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */
|
|
#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */
|
|
#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */
|
|
#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */
|
|
|
|
#define SDIO_CCCR_CIS 0x09 /* common CIS pointer (3 bytes) */
|
|
|
|
/* Following 4 regs are valid only if SBS is set */
|
|
#define SDIO_CCCR_SUSPEND 0x0c
|
|
#define SDIO_CCCR_SELx 0x0d
|
|
#define SDIO_CCCR_EXECx 0x0e
|
|
#define SDIO_CCCR_READYx 0x0f
|
|
|
|
#define SDIO_CCCR_BLKSIZE 0x10
|
|
|
|
#define SDIO_CCCR_POWER 0x12
|
|
|
|
#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */
|
|
#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */
|
|
|
|
#define SDIO_CCCR_SPEED 0x13
|
|
|
|
#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */
|
|
#define SDIO_SPEED_BSS_SHIFT 1
|
|
#define SDIO_SPEED_BSS_MASK (7<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_SDR12 (0<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_SDR25 (1<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_SDR50 (2<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_SDR104 (3<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_DDR50 (4<<SDIO_SPEED_BSS_SHIFT)
|
|
#define SDIO_SPEED_EHS SDIO_SPEED_SDR25 /* Enable High-Speed */
|
|
|
|
#define SDIO_CCCR_UHS 0x14
|
|
#define SDIO_UHS_SDR50 0x01
|
|
#define SDIO_UHS_SDR104 0x02
|
|
#define SDIO_UHS_DDR50 0x04
|
|
|
|
#define SDIO_CCCR_DRIVE_STRENGTH 0x15
|
|
#define SDIO_SDTx_MASK 0x07
|
|
#define SDIO_DRIVE_SDTA (1<<0)
|
|
#define SDIO_DRIVE_SDTC (1<<1)
|
|
#define SDIO_DRIVE_SDTD (1<<2)
|
|
#define SDIO_DRIVE_DTSx_MASK 0x03
|
|
#define SDIO_DRIVE_DTSx_SHIFT 4
|
|
#define SDIO_DTSx_SET_TYPE_B (0 << SDIO_DRIVE_DTSx_SHIFT)
|
|
#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT)
|
|
#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT)
|
|
#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT)
|
|
/*
|
|
* Function Basic Registers (FBR)
|
|
*/
|
|
|
|
#define SDIO_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */
|
|
|
|
#define SDIO_FBR_STD_IF 0x00
|
|
|
|
#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */
|
|
#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */
|
|
|
|
#define SDIO_FBR_STD_IF_EXT 0x01
|
|
|
|
#define SDIO_FBR_POWER 0x02
|
|
|
|
#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */
|
|
#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */
|
|
|
|
#define SDIO_FBR_CIS 0x09 /* CIS pointer (3 bytes) */
|
|
|
|
|
|
#define SDIO_FBR_CSA 0x0C /* CSA pointer (3 bytes) */
|
|
|
|
#define SDIO_FBR_CSA_DATA 0x0F
|
|
|
|
#define SDIO_FBR_BLKSIZE 0x10 /* block size (2 bytes) */
|
|
|
|
void mmc_sdio_force_remove(struct mmc_host *host);
|
|
|
|
#endif /* LINUX_MMC_SDIO_H */
|