Skip to content

Commit

Permalink
MLK-12077-3 bcmdhd: fix bcmdhd system resume crash issue.
Browse files Browse the repository at this point in the history
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 a90bfb0 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 803797d 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 a90bfb0 a833f240 a800b000 a81ce600
ff00: 00000000 800462f0 a81ce600 80043c94 00000000 a800b000 a90bfb18 a800b014
ff20: a846e000 00000088 80b39379 a90bfb0 a800b000 8004654c 80ad4100 a800b164
ff40: a90bfb0 00000000 a84856c0 a90bfb0 80046500 00000000 00000000 00000000
ff60: 00000000 8004b1e8 2df9acc7 00000000 b5f3ff89 a90bfb0 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 <[email protected]>
  • Loading branch information
Dong Aisheng committed Feb 16, 2016
1 parent ae26852 commit 8f998ca
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 11 deletions.
2 changes: 2 additions & 0 deletions Documentation/devicetree/bindings/mmc/mmc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Only one of the properties in this section should be supplied:
- broken-cd: There is no card detection available; polling must be used.
- cd-gpios: Specify GPIOs for card detection, see gpio binding
- non-removable: non-removable slot (like eMMC); assume always present.
- cd-post: postone card detect from start host for non-removable cards
and let client driver to start it when ready

Optional properties:
- bus-width: Number of data lines, can be <1>, <4>, or <8>. The default
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/boot/dts/imx7d-sdb.dts
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,8 @@
pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
enable-sdio-wakeup;
keep-power-in-suspend;
non-removable;
cd-post;
wifi-host;
status = "okay";
};
Expand Down
3 changes: 2 additions & 1 deletion drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2638,7 +2638,8 @@ void mmc_start_host(struct mmc_host *host)
else
mmc_power_up(host, host->ocr_avail);
mmc_gpiod_request_cd_irq(host);
_mmc_detect_change(host, 0, false);
if (!(host->caps2 & MMC_CAP2_CD_POST))
_mmc_detect_change(host, 0, false);
}

void mmc_stop_host(struct mmc_host *host)
Expand Down
2 changes: 2 additions & 0 deletions drivers/mmc/core/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ int mmc_of_parse(struct mmc_host *host)
/* Parse Card Detection */
if (of_property_read_bool(np, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
if (of_property_read_bool(np, "cd-post"))
host->caps2 |= MMC_CAP2_CD_POST;
} else {
cd_cap_invert = of_property_read_bool(np, "cd-inverted");

Expand Down
13 changes: 13 additions & 0 deletions drivers/mmc/core/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,22 @@ static void mmc_sdio_remove(struct mmc_host *host)
}

mmc_remove_card(host->card);
/* clear rescan_entered in case force remove */
host->rescan_entered = 0;
host->card = NULL;
}

void mmc_sdio_force_remove(struct mmc_host *host)
{
mmc_sdio_remove(host);

mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
}
EXPORT_SYMBOL_GPL(mmc_sdio_force_remove);

/*
* Card detection - card is alive.
*/
Expand Down
7 changes: 5 additions & 2 deletions drivers/mmc/host/sdhci-esdhc-imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@
#define ESDHC_STROBE_DLL_CLK_FREQ 100000000

static struct mmc_host *wifi_mmc_host;
void wifi_card_detect(void)
void wifi_card_detect(bool on)
{
WARN_ON(!wifi_mmc_host);
mmc_detect_change(wifi_mmc_host, 0);
if (on)
mmc_detect_change(wifi_mmc_host, 0);
else
mmc_sdio_force_remove(wifi_mmc_host);
}
EXPORT_SYMBOL(wifi_card_detect);

Expand Down
20 changes: 12 additions & 8 deletions drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,11 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
}

#if 1
extern void wifi_card_detect(void);
/* Murata debug: this function is re-worked because "wifi_plat_data" is NULL. */
/* Need to investigate how this pointer/data is being passed into probe function. */
/* "wifi_plat_data" used to be "wifi_ctrl". */
/* All this code is done for only one reason -- calling mmc_detect_change() in /drivers/mmc/core/core.c. */
extern void wifi_card_detect(bool);
int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present)
{
int err = 0;
Expand All @@ -222,13 +226,13 @@ int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_presen

DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present));

if (!adapter->wifi_plat_data) {
wifi_card_detect(); /* hook for card_detect */
} else {
plat_data = adapter->wifi_plat_data;
if (plat_data->set_carddetect)
err = plat_data->set_carddetect(device_present);
}
if (!adapter->wifi_plat_data) {
wifi_card_detect(device_present); /* hook for card_detect */
} else {
plat_data = adapter->wifi_plat_data;
if (plat_data->set_carddetect)
err = plat_data->set_carddetect(device_present);
}

return 0; /* force success status returned */
}
Expand Down
1 change: 1 addition & 0 deletions include/linux/mmc/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ struct mmc_host {
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
#define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */
#define MMC_CAP2_CD_POST (1 << 19) /* post card rescan, let client driver to start */

mmc_pm_flag_t pm_caps; /* supported pm features */

Expand Down
2 changes: 2 additions & 0 deletions include/linux/mmc/sdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,6 @@

#define SDIO_FBR_BLKSIZE 0x10 /* block size (2 bytes) */

void mmc_sdio_force_remove(struct mmc_host *host);

#endif /* LINUX_MMC_SDIO_H */

0 comments on commit 8f998ca

Please sign in to comment.