msm: sdio: fix modem reset and card removal race condition
In cases where the modem HW watchdog causes a modem reset
we can get a card removal event in the middle of modem
reset event.
Change-Id: Ieef2f463f916054b16c8c0d02bf5cf775852ac06
Signed-off-by: Maya Erez <merez@codeaurora.org>
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
index 1a05449..3acd4a4 100644
--- a/arch/arm/mach-msm/sdio_al.c
+++ b/arch/arm/mach-msm/sdio_al.c
@@ -405,6 +405,7 @@
struct sdio_al_device {
struct sdio_al_local_log *dev_log;
struct mmc_card *card;
+ struct mmc_host *host;
struct sdio_mailbox *mailbox;
struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
@@ -511,6 +512,7 @@
static void sdio_al_print_info(void);
static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
+static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
#define SDIO_AL_ERR(func) \
do { \
@@ -698,6 +700,13 @@
"sdio_al_dev\n", func);
return -ENODEV;
}
+
+ if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+ "signature\n", func);
+ return -ENODEV;
+ }
+
if (!sdio_al_dev->card) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
"card\n", func);
@@ -711,22 +720,72 @@
return 0;
}
-
-static int sdio_al_verify_dev(struct sdio_al_device *sdio_al_dev,
- char const *func)
+static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
+ char const *func)
{
- int ret;
-
- ret = sdio_al_verify_func1(sdio_al_dev, func);
- if (ret)
- return ret;
-
- if ((sdio_al_dev->state == MODEM_RESTART) ||
- (sdio_al_dev->state == CARD_REMOVED)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: device "
- "state %d\n", func, sdio_al_dev->state);
+ if (!sdio_al_dev) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+ "device\n", func);
return -ENODEV;
}
+
+ if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+ "device signature\n", func);
+ return -ENODEV;
+ }
+
+ if (!sdio_al_dev->host) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+ "host\n", func);
+ return -ENODEV;
+ }
+
+ mmc_claim_host(sdio_al_dev->host);
+
+ return 0;
+}
+
+static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
+ char const *func)
+{
+ if (!sdio_al_dev) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+ "device\n", func);
+ return -ENODEV;
+ }
+
+ if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+ "device signature\n", func);
+ return -ENODEV;
+ }
+
+ if (!sdio_al_dev->host) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
+ "host\n", func);
+ return -ENODEV;
+ }
+
+ mmc_release_host(sdio_al_dev->host);
+
+ return 0;
+}
+
+static int sdio_al_claim_mutex_and_verify_dev(
+ struct sdio_al_device *sdio_al_dev,
+ char const *func)
+{
+ if (sdio_al_claim_mutex(sdio_al_dev, __func__))
+ return -ENODEV;
+
+ if (sdio_al_dev->state != CARD_INSERTED) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
+ "device state %d\n", func, sdio_al_dev->state);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return -ENODEV;
+ }
+
return 0;
}
@@ -761,7 +820,7 @@
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
"registered for wakeup callback\n", __func__,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
void sdio_al_unregister_lpm_cb(void *device_handle)
@@ -778,7 +837,7 @@
sdio_al_dev->lpm_callback = NULL;
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
"unregister for wakeup callback\n", __func__,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
@@ -806,7 +865,7 @@
"is_vote_for_sleep=%d for card#%d, "
"calling callback...", __func__,
is_vote_for_sleep,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
sdio_al_dev->lpm_callback((void *)sdio_al_dev,
is_vote_for_sleep);
}
@@ -829,20 +888,20 @@
if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
"lpm_chan for card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
return -EINVAL;
}
pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
sdio_al_dev->is_ok_to_sleep,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
&sdio_al_dev->is_ok_to_sleep, sizeof(u32));
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
"write lpm info for card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
return ret;
}
@@ -878,7 +937,7 @@
u32 offset = 0;
u32 masked_user_irq = 0;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return 0;
func1 = sdio_al_dev->card->sdio_func[0];
@@ -915,8 +974,7 @@
pr_debug(MODULE_NAME ":Inactivity timer expired."
" Going to sleep\n");
/* Stop mailbox timer */
- sdio_al_dev->poll_delay_msec = 0;
- del_timer_sync(&sdio_al_dev->timer);
+ stop_and_del_timer(sdio_al_dev);
/* Make sure we get interrupt for non-packet-mode right away */
for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
struct sdio_channel *ch = &sdio_al_dev->channel[i];
@@ -943,7 +1001,7 @@
msmsdcc_lpm_enable(host);
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
" for card %d. Sleep now.\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
/* Release wakelock */
sdio_al_vote_for_sleep(sdio_al_dev, 1);
}
@@ -963,16 +1021,16 @@
* This function should run from a workqueue context since it
* notifies the clients.
*
- * This function assumes that sdio_claim_host was called before
+ * This function assumes that sdio_al_claim_mutex was called before
* calling it.
*
*/
static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
{
int ret;
- struct sdio_func *func1 = sdio_al_dev->card->sdio_func[0];
+ struct sdio_func *func1 = NULL;
struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
- struct mmc_host *host = func1->card->host;
+ struct mmc_host *host = sdio_al_dev->host;
u32 new_write_avail = 0;
u32 old_write_avail = 0;
u32 any_read_avail = 0;
@@ -992,8 +1050,12 @@
return 0;
}
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
+ return -ENODEV;
+ func1 = sdio_al_dev->card->sdio_func[0];
+
pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
- , __func__, from_isr, sdio_al_dev->card->host->index);
+ , __func__, from_isr, sdio_al_dev->host->index);
pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
memset(mailbox, 0, sizeof(struct sdio_mailbox));
@@ -1003,10 +1065,8 @@
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
"Mailbox for card %d, goto error state\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
sdio_al_get_into_err_state(sdio_al_dev);
- /* Stop the timer to stop reading the mailbox */
- sdio_al_dev->poll_delay_msec = 0;
goto exit_err;
}
@@ -1033,13 +1093,13 @@
if (sdio_al_dev->state != CARD_INSERTED) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
" (card %d) is in invalid state %d\n",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
sdio_al_dev->state);
return -ENODEV;
}
pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
eot_pipe, thresh_pipe);
/* Scan for Rx Packets available and update read available bytes */
@@ -1083,7 +1143,7 @@
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
":Interrupt on ch %s, "
"card %d", ch->name,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
new_packet_size = check_pending_rx_packet(ch, eot_pipe);
} else {
@@ -1092,7 +1152,7 @@
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
":Interrupt on ch %s, "
"card %d", ch->name,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
ch->read_avail = read_avail;
/* Restore default thresh for non packet channels */
@@ -1172,7 +1232,7 @@
!any_read_avail && !any_write_pending) {
DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
"Notify for card %d, is_closing=%d\n",
- sdio_al_dev->card->host->index, is_closing);
+ sdio_al_dev->host->index, is_closing);
if (is_closing)
restart_inactive_time(sdio_al_dev);
else if (is_inactive_time_expired(sdio_al_dev))
@@ -1180,7 +1240,7 @@
} else {
DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
" for card %d rx=0x%x, tx=0x%x.\n",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
rx_notify_bitmask, tx_notify_bitmask);
/* Restart inactivity timer if any activity on the channel */
restart_inactive_time(sdio_al_dev);
@@ -1216,7 +1276,7 @@
pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
"rx_pending=0x%x\n",
- ch->rx_pipe_index, sdio_al_dev->card->host->index, rx_avail,
+ ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
rx_pending);
@@ -1332,33 +1392,32 @@
"event..\n");
/* Do polling until MDM is up */
for (i = 0; i < 5000; ++i) {
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
if (is_user_irq_enabled(sdio_al_dev, func_num)) {
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
sdio_al_dev->bootloader_done = 0;
ret = sdio_al_client_setup(sdio_al_dev);
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": sdio_al_client_setup failed, "
"for card %d ret=%d\n",
- sdio_al_dev->card->host->index, ret);
+ sdio_al_dev->host->index, ret);
sdio_al_get_into_err_state(sdio_al_dev);
}
goto done;
}
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
msleep(100);
}
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
"user_irq for card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
sdio_al_get_into_err_state(sdio_al_dev);
done:
pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
/**
@@ -1391,23 +1450,22 @@
while ((sdio_al_dev->is_ready) && (ret == 0)) {
pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- break;
if (!sdio_al_dev->is_ready)
break;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ break;
if (sdio_al_dev->is_ok_to_sleep) {
ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
if (ret) {
- sdio_release_host(
- sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return;
}
}
ret = read_mailbox(sdio_al_dev, false);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
sdio_al_dev->ask_mbox = false;
}
+
pr_debug(MODULE_NAME ":Worker Exit!\n");
}
@@ -1546,7 +1604,7 @@
MODULE_NAME ":%s: sdio_memcpy_toio "
"failed for channel %s\n",
__func__, ch->name);
- ch->sdio_al_dev->is_err = true;
+ sdio_al_get_into_err_state(ch->sdio_al_dev);
return ret;
}
}
@@ -1593,13 +1651,9 @@
{
int ret = 0;
- struct sdio_func *func1;
-
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
/*
* Enable function 0 interrupt mask to allow 9k to raise this interrupt
* in power-up. When sdio_downloader will notify its completion
@@ -1610,12 +1664,12 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": Enable_mask_irq for card %d failed, "
"ret=%d\n",
- sdio_al_dev->card->host->index, ret);
- sdio_release_host(func1);
+ sdio_al_dev->host->index, ret);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
- sdio_release_host(func1);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
/*
* Start bootloader worker that will wait for the bootloader
@@ -1632,38 +1686,34 @@
static int sdio_al_bootloader_setup(void)
{
int ret = 0;
- struct sdio_func *func1;
struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
+ struct sdio_func *func1 = NULL;
- if (bootloader_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ": No bootloader_dev\n");
+ if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
return -ENODEV;
- }
if (bootloader_dev->flashless_boot_on) {
sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
"in boot process.\n");
+ sdio_al_release_mutex(bootloader_dev, __func__);
return 0;
}
- func1 = bootloader_dev->card->sdio_func[0];
- if (!func1) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
- ": %s: NULL func1\n", __func__);
- return -ENODEV;
- }
-
bootloader_dev->sdioc_boot_sw_header
= kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
GFP_KERNEL);
if (bootloader_dev->sdioc_boot_sw_header == NULL) {
sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
"allocate sdioc boot sw header.\n");
+ sdio_al_release_mutex(bootloader_dev, __func__);
return -ENOMEM;
}
- sdio_claim_host(func1);
+ if (sdio_al_verify_func1(bootloader_dev, __func__)) {
+ sdio_al_release_mutex(bootloader_dev, __func__);
+ goto exit_err;
+ }
+ func1 = bootloader_dev->card->sdio_func[0];
ret = sdio_memcpy_fromio(func1,
bootloader_dev->sdioc_boot_sw_header,
@@ -1672,7 +1722,7 @@
if (ret) {
sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
"read sdioc boot sw header.\n");
- sdio_release_host(func1);
+ sdio_al_release_mutex(bootloader_dev, __func__);
goto exit_err;
}
@@ -1681,7 +1731,7 @@
sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
"mailbox signature 0x%x.\n",
bootloader_dev->sdioc_boot_sw_header->signature);
- sdio_release_host(func1);
+ sdio_al_release_mutex(bootloader_dev, __func__);
ret = -EINVAL;
goto exit_err;
}
@@ -1694,7 +1744,7 @@
((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
sdio_al->pdata->peer_sdioc_boot_version_minor),
bootloader_dev->sdioc_boot_sw_header->version);
- sdio_release_host(func1);
+ sdio_al_release_mutex(bootloader_dev, __func__);
ret = -EIO;
goto exit_err;
}
@@ -1705,7 +1755,7 @@
bootloader_dev->flashless_boot_on = true;
- sdio_release_host(func1);
+ sdio_al_release_mutex(bootloader_dev, __func__);
ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
if (ret) {
@@ -1751,13 +1801,16 @@
int i;
int test_version = 0;
int sdioc_test_version = 0;
+ struct sdio_func *func1 = NULL;
pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return -ENODEV;
- ret = sdio_memcpy_fromio(sdio_al_dev->card->sdio_func[0], header,
+ func1 = sdio_al_dev->card->sdio_func[0];
+
+ ret = sdio_memcpy_fromio(func1, header,
SDIOC_SW_HEADER_ADDR, sizeof(*header));
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
@@ -1970,7 +2023,7 @@
u32 pipe_mask;
u32 addr;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return -ENODEV;
func1 = sdio_al_dev->card->sdio_func[0];
@@ -2014,7 +2067,7 @@
u32 addr = 0;
u32 offset = 0;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return -ENODEV;
func1 = sdio_al_dev->card->sdio_func[0];
@@ -2061,7 +2114,7 @@
u32 pipe_mask;
u32 addr;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return -ENODEV;
func1 = sdio_al_dev->card->sdio_func[0];
@@ -2102,7 +2155,7 @@
int ret = 0;
struct sdio_func *func1;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
return -ENODEV;
func1 = sdio_al_dev->card->sdio_func[0];
@@ -2247,7 +2300,7 @@
{
if (!sdio_al_dev->ask_mbox) {
pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
sdio_al_dev->ask_mbox = true;
wake_up(&sdio_al_dev->wait_mbox);
}
@@ -2280,6 +2333,17 @@
}
/**
+ * Stop and delete the timer
+ */
+static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
+{
+ if (sdio_al_dev->is_timer_initialized) {
+ sdio_al_dev->poll_delay_msec = 0;
+ del_timer_sync(&sdio_al_dev->timer);
+ }
+}
+
+/**
* Do the wakup sequence.
* This function should be called after claiming the host!
* The caller is responsible for releasing the host.
@@ -2306,16 +2370,9 @@
}
if (!sdio_al_dev->is_ok_to_sleep) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d already"
- " awake, no need to wake up\n",
- sdio_al_dev->card->host->index);
- return 0;
- }
-
- if (!sdio_al_dev->is_ok_to_sleep) {
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
"already awake, no need to wake up\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
return 0;
}
@@ -2324,17 +2381,17 @@
if (ch) {
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
" card %d (not by interrupt), ch %s",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
ch->name);
} else {
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
" card %d (not by interrupt)",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
}
} else {
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
"%d by interrupt",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
sdio_al_dev->print_after_interrupt = 1;
}
@@ -2383,7 +2440,7 @@
start_timer(sdio_al_dev);
LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
- " for card %d", sdio_al_dev->card->host->index);
+ " for card %d", sdio_al_dev->host->index);
msmsdcc_set_pwrsave(sdio_al_dev->card->host, 1);
pr_debug(MODULE_NAME ":Turn clock off\n");
@@ -2478,7 +2535,7 @@
sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
- "card %d\n", sdio_al_dev->card->host->index);
+ "card %d\n", sdio_al_dev->host->index);
func1 = card->sdio_func[0];
@@ -2510,7 +2567,7 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
" IRQ for card %d\n",
card->host->index);
- goto exit_err;
+ return ret;
}
sdio_al_dev->is_ready = true;
@@ -2523,12 +2580,6 @@
pr_debug(MODULE_NAME ":Ready.\n");
return 0;
-
-exit_err:
- sdio_release_host(func1);
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Setup Failure.\n");
-
- return ret;
}
/**
@@ -2537,7 +2588,7 @@
*/
static void sdio_al_tear_down(void)
{
- int i;
+ int i, j;
struct sdio_al_device *sdio_al_dev = NULL;
struct sdio_func *func1;
@@ -2558,19 +2609,31 @@
sdio_al_vote_for_sleep(sdio_al_dev, 1);
- if (sdio_al_verify_func1(sdio_al_dev, __func__)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s: Invalid func1",
- __func__);
- return;
+ if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
+ __func__)) {
+ if (!sdio_al_dev->card ||
+ !sdio_al_dev->card->sdio_func[0]) {
+ sdio_al_loge(sdio_al_dev->dev_log,
+ MODULE_NAME
+ ": %s: Invalid func1",
+ __func__);
+ return;
+ }
+ func1 = sdio_al_dev->card->sdio_func[0];
+ sdio_release_irq(func1);
+ sdio_disable_func(func1);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
}
- func1 = sdio_al_dev->card->sdio_func[0];
-
- sdio_claim_host(func1);
- sdio_release_irq(func1);
- sdio_disable_func(func1);
- sdio_release_host(func1);
}
+
+ for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
+ sdio_al_dev->channel[j].signature = 0x0;
+ sdio_al_dev->signature = 0;
+
+ kfree(sdio_al_dev->sdioc_sw_header);
+ kfree(sdio_al_dev->mailbox);
+ kfree(sdio_al_dev->rx_flush_buf);
+ kfree(sdio_al_dev);
}
sdio_al->pdata->config_mdm2ap_status(0);
@@ -2656,11 +2719,9 @@
}
sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
-
if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
(ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
@@ -2669,14 +2730,6 @@
goto exit_err;
}
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "sdio_al_dev is in invalid state %d\n",
- __func__, sdio_al_dev->state);
- ret = -ENODEV;
- goto exit_err;
- }
-
if (sdio_al_dev->is_err) {
SDIO_AL_ERR(__func__);
ret = -ENODEV;
@@ -2719,7 +2772,7 @@
}
exit_err:
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
EXPORT_SYMBOL(sdio_open);
@@ -2819,7 +2872,6 @@
{
int ret;
struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_func *func1 = NULL;
int flush_len;
ulong flush_expires;
@@ -2828,37 +2880,30 @@
"channel\n", __func__);
return -ENODEV;
}
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (!sdio_al_dev->ch_close_supported) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
- "supported by mdm, ch %s\n",
- __func__, ch->name);
- return -ENOTSUPP;
- }
if (!ch->func) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
" on channel:%d\n", __func__, ch->num);
return -ENODEV;
}
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
+
+ sdio_al_dev = ch->sdio_al_dev;
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return -ENODEV;
+
+ if (!sdio_al_dev->ch_close_supported) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
+ "supported by mdm, ch %s\n",
+ __func__, ch->name);
+ ret = -ENOTSUPP;
+ goto error_exit;
+ }
if (sdio_al_dev->is_err) {
SDIO_AL_ERR(__func__);
ret = -ENODEV;
goto error_exit;
}
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "sdio_al_dev is in invalid state %d\n",
- __func__, sdio_al_dev->state);
- ret = -ENODEV;
- goto error_exit;
- }
if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
sdio_al_loge(sdio_al_dev->dev_log,
MODULE_NAME ":%s: ch %s is not in "
@@ -2881,7 +2926,7 @@
sdio_al_dev->poll_delay_msec =
get_min_poll_time_msec(sdio_al_dev);
}
- sdio_release_host(func1);
+ sdio_al_release_mutex(ch->sdio_al_dev, __func__);
flush_expires = jiffies +
msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
@@ -2920,9 +2965,9 @@
ch->signature);
return -ENODEV;
}
- if (sdio_al_verify_dev(ch->sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
+ __func__))
return -ENODEV;
- sdio_claim_host(func1);
ret = read_mailbox(sdio_al_dev, false);
if (ret) {
@@ -2931,10 +2976,12 @@
" read mailbox", __func__);
goto error_exit;
}
- sdio_release_host(func1);
+ sdio_al_release_mutex(ch->sdio_al_dev, __func__);
} while (ch->read_avail > 0);
}
- sdio_claim_host(func1);
+ if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
+ __func__))
+ return -ENODEV;
/* disable function to be able to open the channel again */
ret = sdio_disable_func(ch->func);
if (ret) {
@@ -2948,7 +2995,7 @@
"successfully\n", __func__, ch->name);
error_exit:
- sdio_release_host(func1);
+ sdio_al_release_mutex(ch->sdio_al_dev, __func__);
return ret;
}
@@ -3035,8 +3082,8 @@
}
sdio_al_dev = ch->sdio_al_dev;
-
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return -ENODEV;
ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
PIPE_RX_FIFO_ADDR, len);
@@ -3046,13 +3093,13 @@
MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
ch->name, __func__, -ret, len);
sdio_al_dev->is_err = true;
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
restart_inactive_time(sdio_al_dev);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return 0;
}
@@ -3092,23 +3139,13 @@
}
sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
-
if (sdio_al_dev->is_err) {
SDIO_AL_ERR(__func__);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENODEV;
- }
-
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "sdio_al_dev is in invalid state %d\n",
- __func__, sdio_al_dev->state);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENODEV;
+ ret = -ENODEV;
+ goto exit;
}
/* lpm policy says we can't go to sleep when we have pending rx data,
@@ -3130,8 +3167,8 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
"channel %s state %d\n",
__func__, ch->name, ch->state);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
@@ -3142,16 +3179,16 @@
if ((ch->is_packet_mode) && (len != ch->read_avail)) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
"%s len != read_avail\n", ch->name);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
if (len > ch->read_avail) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
"reading more bytes (%d) than the avail(%d).\n",
ch->name, len, ch->read_avail);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit;
}
ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
@@ -3163,9 +3200,8 @@
ch->name, -ret, len, ch->read_avail,
ch->statistics.last_read_avail,
ch->statistics.last_old_read_avail);
- sdio_al_dev->is_err = true;
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return ret;
+ sdio_al_get_into_err_state(sdio_al_dev);
+ goto exit;
}
ch->statistics.total_read_times++;
@@ -3184,7 +3220,8 @@
if ((ch->read_avail == 0) && !(ch->is_packet_mode))
ask_reading_mailbox(sdio_al_dev);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+exit:
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
@@ -3251,40 +3288,28 @@
}
sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
-
-
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":%s: sdio_al_dev is in invalid state %d\n",
- __func__, sdio_al_dev->state);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENODEV;
- }
WARN_ON(len > ch->write_avail);
if (sdio_al_dev->is_err) {
SDIO_AL_ERR(__func__);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENODEV;
+ ret = -ENODEV;
+ goto exit;
}
if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
"closed channel %s\n", ch->name);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
if (sdio_al_dev->is_ok_to_sleep) {
ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret) {
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return ret;
- }
+ if (ret)
+ goto exit;
} else {
restart_inactive_time(sdio_al_dev);
}
@@ -3296,16 +3321,15 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
"write more bytes (%d) than available %d.\n",
ch->name, len, ch->write_avail);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit;
}
ret = sdio_ch_write(ch, data, len);
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
"on channel %s err=%d\n", ch->name, -ret);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
- return ret;
+ goto exit;
}
ch->total_tx_bytes += len;
@@ -3322,7 +3346,8 @@
if (ch->write_avail < ch->min_write_avail)
ask_reading_mailbox(sdio_al_dev);
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+exit:
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
@@ -3379,99 +3404,106 @@
}
}
-static void sdio_al_modem_reset_dev_operations(struct sdio_al_device
+static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
+ struct platform_device **pdev_arr)
+{
+ int j;
+
+ pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
+ __func__, sdio_al_dev->host->index);
+ for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
+ if (sdio_al_dev->channel[j].state ==
+ SDIO_CHANNEL_STATE_INVALID)
+ continue;
+ pdev_arr[j] = sdio_al_dev->channel[j].pdev;
+ sdio_al_dev->channel[j].signature = 0x0;
+ sdio_al_dev->channel[j].state =
+ SDIO_CHANNEL_STATE_INVALID;
+ }
+}
+
+static void sdio_al_modem_reset_operations(struct sdio_al_device
*sdio_al_dev)
{
+ int ret = 0;
+ struct sdio_func *func1 = NULL;
+ struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
+ int j;
+
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
- if (!sdio_al_dev) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: NULL device", __func__);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return;
- }
- if (sdio_al_dev->state == CARD_REMOVED) {
- sdio_al_logi(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: card %d is already removed",
- __func__, sdio_al_dev->card->host->index);
- return;
- }
- if (sdio_al_dev->state == MODEM_RESTART) {
- sdio_al_logi(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: card %d was already "
- "notified for modem reset",
- __func__, sdio_al_dev->card->host->index);
- return;
+
+ if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: "
+ "NULL func1 for card %d", __func__,
+ sdio_al_dev->host->index);
+ goto exit_err;
}
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
- "state to MODEM_RESTART for card %d",
- __func__, sdio_al_dev->card->host->index);
+ if (sdio_al_dev->state == CARD_REMOVED) {
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
+ "card %d is already removed", __func__,
+ sdio_al_dev->host->index);
+ goto exit_err;
+ }
+
+ if (sdio_al_dev->state == MODEM_RESTART) {
+ sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
+ "card %d was already notified for modem reset",
+ __func__, sdio_al_dev->host->index);
+ goto exit_err;
+ }
+
+ sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
+ "state to MODEM_RESTART for card %d",
+ __func__, sdio_al_dev->host->index);
sdio_al_dev->state = MODEM_RESTART;
sdio_al_dev->is_ready = false;
/* Stop mailbox timer */
- if (sdio_al_dev->is_timer_initialized) {
- sdio_al_logi(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: Stop timer for card %d",
- __func__, sdio_al_dev->card->host->index);
- sdio_al_dev->poll_delay_msec = 0;
- del_timer_sync(&sdio_al_dev->timer);
- sdio_al_dev->is_timer_initialized = false;
- } else {
- sdio_al_logi(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: No timer. Nothing to do for card %d",
- __func__, sdio_al_dev->card->host->index);
- }
- return;
-}
+ stop_and_del_timer(sdio_al_dev);
-static int sdio_al_modem_reset_bus_operations(struct sdio_al_device
- *sdio_al_dev)
-{
- int j;
- int ret;
- struct sdio_func *func1 = NULL;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- func1 = sdio_al_dev->card->sdio_func[0];
if ((sdio_al_dev->is_ok_to_sleep) &&
- (!sdio_al_dev->is_err)) {
- sdio_al_logi(&sdio_al->gen_log,
- MODULE_NAME ": %s: wakeup modem for "
- "card %d", __func__,
- sdio_al_dev->card->host->index);
+ (!sdio_al_dev->is_err)) {
+ pr_debug(MODULE_NAME ": %s: wakeup modem for "
+ "card %d", __func__,
+ sdio_al_dev->host->index);
ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
- if (ret == 0) {
- sdio_al_logi(&sdio_al->gen_log,
- MODULE_NAME ": %s: "
- "sdio_release_irq"
- " for card %d",
- __func__,
- sdio_al_dev->card->host->index);
- sdio_release_irq(func1);
- }
- } else {
- sdio_al_logi(&sdio_al->gen_log,
- MODULE_NAME ": %s: sdio_release_irq"
- " for card %d",
- __func__,
- sdio_al_dev->card->host->index);
- sdio_release_irq(func1);
}
- sdio_al_logi(&sdio_al->gen_log,
- MODULE_NAME ": %s: Notifying SDIO clients for card %d",
- __func__, sdio_al_dev->card->host->index);
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- if (sdio_al_dev->channel[j].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- platform_device_unregister(
- sdio_al_dev->channel[j].pdev);
- sdio_al_dev->channel[j].signature = 0x0;
+ if (!ret && (!sdio_al_dev->is_err)) {
+ sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
+ ": %s: sdio_release_irq for card %d",
+ __func__,
+ sdio_al_dev->host->index);
+ func1 = sdio_al_dev->card->sdio_func[0];
+ sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
}
- return 0;
+
+ memset(pdev_arr, 0, sizeof(pdev_arr));
+ sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
+
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
+ "clients for card %d",
+ __func__, sdio_al_dev->host->index);
+ for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
+ if (!pdev_arr[j])
+ continue;
+ platform_device_unregister(pdev_arr[j]);
+ }
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
+ "SDIO clients for card %d",
+ __func__, sdio_al_dev->host->index);
+
+ return;
+
+exit_err:
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return;
}
#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
@@ -3479,13 +3511,9 @@
{
int i;
struct sdio_al_device *sdio_al_dev;
- struct sdio_func *func1 = NULL;
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++)
- sdio_al_modem_reset_dev_operations(sdio_al->devices[i]);
-
for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
if (sdio_al->devices[i] == NULL) {
pr_debug(MODULE_NAME ": %s: NULL device in index %d",
@@ -3493,34 +3521,16 @@
continue;
}
sdio_al_dev = sdio_al->devices[i];
-
- if (!sdio_al_verify_func1(sdio_al_dev, __func__)) {
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
-
- sdio_al_modem_reset_bus_operations(sdio_al_dev);
-
- if (!sdio_al_verify_func1(sdio_al_dev, __func__))
- sdio_release_host(func1);
-
-
- pr_debug(MODULE_NAME ": %s: Allows sleep for card %d",
- __func__,
- sdio_al_dev->card->host->index);
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
- } else {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
- ":%s bad function i=%d\n", __func__, i);
- }
+ sdio_al_modem_reset_operations(sdio_al->devices[i]);
}
- return;
+
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
}
#endif
static void msm_sdio_al_shutdown(struct platform_device *pdev)
{
int i;
- struct sdio_func *func1 = NULL;
struct sdio_al_device *sdio_al_dev;
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
@@ -3534,26 +3544,15 @@
}
sdio_al_dev = sdio_al->devices[i];
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return;
- if (!sdio_al_verify_func1(sdio_al_dev, __func__)) {
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
+ if (sdio_al_dev->ch_close_supported)
+ sdio_al_close_all_channels(sdio_al_dev);
- if (sdio_al_dev->ch_close_supported)
- sdio_al_close_all_channels(sdio_al_dev);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
- sdio_al_modem_reset_dev_operations(sdio_al_dev);
-
- sdio_al_modem_reset_bus_operations(sdio_al_dev);
-
- if (!sdio_al_verify_func1(sdio_al_dev, __func__))
- sdio_release_host(func1);
-
- pr_debug(MODULE_NAME ": %s: Allows sleep for card %d",
- __func__,
- sdio_al_dev->card->host->index);
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
- }
+ sdio_al_modem_reset_operations(sdio_al_dev);
}
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
"msm_sdio_al_shutdown complete.", __func__);
@@ -3577,11 +3576,9 @@
int ret = 0;
int i;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
-
ret = read_sdioc_software_header(sdio_al_dev,
sdio_al_dev->sdioc_sw_header);
if (ret)
@@ -3636,7 +3633,7 @@
}
exit:
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
@@ -3653,17 +3650,22 @@
struct sdio_func *func1;
int signature = 0;
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
+ if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
+ "func1\n");
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return -ENODEV;
+ }
+ func1 = sdio_al_dev->card->sdio_func[0];
/* Read the header signature to determine the status of the MDM
* SDIO Client
*/
signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
- sdio_release_host(func1);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
"signature from sw header.\n");
@@ -3675,13 +3677,13 @@
if (sdio_al_dev == sdio_al->bootloader_dev) {
sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
"bootloader on card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
return sdio_al_bootloader_setup();
} else {
sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
"for bootloader completion "
"on card %d\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
}
case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
@@ -3696,6 +3698,27 @@
return 0;
}
+static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
+{
+ sdio_al_dev->is_ready = 0;
+ sdio_al_dev->bootloader_done = 0;
+ sdio_al_dev->lpm_chan = 0;
+ sdio_al_dev->is_ok_to_sleep = 0;
+ sdio_al_dev->inactivity_time = 0;
+ sdio_al_dev->poll_delay_msec = 0;
+ sdio_al_dev->is_timer_initialized = 0;
+ sdio_al_dev->is_err = 0;
+ sdio_al_dev->is_suspended = 0;
+ sdio_al_dev->flashless_boot_on = 0;
+ sdio_al_dev->ch_close_supported = 0;
+ sdio_al_dev->print_after_interrupt = 0;
+ memset(sdio_al_dev->sdioc_sw_header, 0,
+ sizeof(*sdio_al_dev->sdioc_sw_header));
+ memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
+ memset(sdio_al_dev->rx_flush_buf, 0,
+ sizeof(*sdio_al_dev->rx_flush_buf));
+}
+
/*
* SDIO driver functions
*/
@@ -3720,6 +3743,13 @@
return -ENODEV;
}
+ if (!card->sdio_func[0]) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+ "func1\n",
+ __func__);
+ return -ENODEV;
+ }
+
if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
dev_info(&card->dev,
"SDIO-functions# %d less than expected.\n",
@@ -3731,39 +3761,48 @@
for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
if (sdio_al->devices[i] == NULL)
continue;
- if (sdio_al->devices[i]->card == card)
- return 0;
+ if (sdio_al->devices[i]->host == card->host) {
+ sdio_al_dev = sdio_al->devices[i];
+ if (sdio_al_dev->state == CARD_INSERTED)
+ return 0;
+ clean_sdio_al_device_data(sdio_al_dev);
+ break;
+ }
+ }
+
+ if (!sdio_al_dev) {
+ sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
+ GFP_KERNEL);
+ if (sdio_al_dev == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
+ if (sdio_al->devices[i] == NULL) {
+ sdio_al->devices[i] = sdio_al_dev;
+ sdio_al_dev->dev_log = &sdio_al->device_log[i];
+ spin_lock_init(&sdio_al_dev->dev_log->log_lock);
+ #ifdef CONFIG_DEBUG_FS
+ sdio_al_dbgfs_log[i].data =
+ sdio_al_dev->dev_log->buffer;
+ sdio_al_dbgfs_log[i].size =
+ SDIO_AL_DEBUG_LOG_SIZE;
+ #endif
+ break;
+ }
+ if (i == MAX_NUM_OF_SDIO_DEVICES) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
+ "in devices array for the device\n");
+ return -ENOMEM;
+ }
}
dev_info(&card->dev, "SDIO Card claimed.\n");
- sdio_al_dev = kzalloc(sizeof(struct sdio_al_device), GFP_KERNEL);
- if (sdio_al_dev == NULL)
- return -ENOMEM;
-
sdio_al_dev->state = CARD_INSERTED;
if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
sdio_al->bootloader_dev = sdio_al_dev;
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- if (sdio_al->devices[i] == NULL) {
- sdio_al->devices[i] = sdio_al_dev;
- sdio_al_dev->dev_log = &sdio_al->device_log[i];
- spin_lock_init(&sdio_al_dev->dev_log->log_lock);
-#ifdef CONFIG_DEBUG_FS
- sdio_al_dbgfs_log[i].data =
- sdio_al_dev->dev_log->buffer;
- sdio_al_dbgfs_log[i].size = SDIO_AL_DEBUG_LOG_SIZE;
-#endif
- break;
- }
- if (i == MAX_NUM_OF_SDIO_DEVICES) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space in "
- "devices array for the device\n");
- return -ENOMEM;
- }
-
sdio_al_dev->is_ready = false;
sdio_al_dev->signature = SDIO_AL_SIGNATURE;
@@ -3774,24 +3813,33 @@
sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
sdio_al_dev->card = card;
+ sdio_al_dev->host = card->host;
- sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox), GFP_KERNEL);
- if (sdio_al_dev->mailbox == NULL)
- return -ENOMEM;
+ if (!sdio_al_dev->mailbox) {
+ sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
+ GFP_KERNEL);
+ if (sdio_al_dev->mailbox == NULL)
+ return -ENOMEM;
+ }
- sdio_al_dev->sdioc_sw_header
- = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header), GFP_KERNEL);
- if (sdio_al_dev->sdioc_sw_header == NULL)
- return -ENOMEM;
+ if (!sdio_al_dev->sdioc_sw_header) {
+ sdio_al_dev->sdioc_sw_header
+ = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
+ GFP_KERNEL);
+ if (sdio_al_dev->sdioc_sw_header == NULL)
+ return -ENOMEM;
+ }
-
- sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE, GFP_KERNEL);
- if (sdio_al_dev->rx_flush_buf == NULL) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":Fail to allocate rx_flush_buf "
- "for card %d\n",
- card->host->index);
- return -ENOMEM;
+ if (!sdio_al_dev->rx_flush_buf) {
+ sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (sdio_al_dev->rx_flush_buf == NULL) {
+ sdio_al_loge(&sdio_al->gen_log,
+ MODULE_NAME ":Fail to allocate "
+ "rx_flush_buf for card %d\n",
+ card->host->index);
+ return -ENOMEM;
+ }
}
sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
@@ -3800,7 +3848,8 @@
/* Don't allow sleep until all required clients register */
sdio_al_vote_for_sleep(sdio_al_dev, 0);
- sdio_claim_host(card->sdio_func[0]);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return -ENODEV;
/* Init Func#1 */
ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
@@ -3826,7 +3875,7 @@
ret = sdio_al_client_setup(sdio_al_dev);
exit:
- sdio_release_host(card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
return ret;
}
@@ -3834,8 +3883,8 @@
{
struct sdio_al_device *sdio_al_dev = NULL;
int i;
- int state;
struct mmc_card *card = NULL;
+ struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
if (!func) {
sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
@@ -3856,7 +3905,6 @@
continue;
if (sdio_al->devices[i]->card == card) {
sdio_al_dev = sdio_al->devices[i];
- sdio_al->devices[i] = NULL;
break;
}
}
@@ -3866,23 +3914,28 @@
return;
}
+ if (sdio_al_claim_mutex(sdio_al_dev, __func__))
+ return;
+
+ if (sdio_al_dev->state == CARD_REMOVED) {
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return;
+ }
+
+ if (!card->sdio_func[0]) {
+ sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
+ "func1\n", __func__);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return;
+ }
+
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
__func__, card->host->index);
- if (card->sdio_func[0])
- sdio_claim_host(card->sdio_func[0]);
- else
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL func1 "
- "for card %d\n", __func__, card->host->index);
-
- if (sdio_al_dev->state == CARD_REMOVED)
- return;
-
- state = sdio_al_dev->state;
sdio_al_dev->state = CARD_REMOVED;
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
- sdio_al_dev->channel[i].signature = 0x0;
+ memset(pdev_arr, 0, sizeof(pdev_arr));
+ sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
"for card %d\n", __func__, card->host->index);
@@ -3890,29 +3943,21 @@
sdio_al_dev->ask_mbox = false;
ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
- if (state != MODEM_RESTART) {
- if (sdio_al_dev->is_timer_initialized) {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Stop"
- " timer for card %d", __func__,
- sdio_al_dev->card->host->index);
- sdio_al_dev->poll_delay_msec = 0;
- del_timer_sync(&sdio_al_dev->timer);
- }
+ stop_and_del_timer(sdio_al_dev);
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "notifying clients for card %d\n",
- __func__, card->host->index);
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (sdio_al_dev->channel[i].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- platform_device_unregister(
- sdio_al_dev->channel[i].pdev);
- sdio_al_dev->channel[i].signature = 0x0;
- }
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
+ "clients for card %d",
+ __func__, sdio_al_dev->host->index);
+ for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
+ if (!pdev_arr[i])
+ continue;
+ platform_device_unregister(pdev_arr[i]);
}
- if (card->sdio_func[0])
- sdio_release_host(card->sdio_func[0]);
+ sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
+ "SDIO clients for card %d",
+ __func__, sdio_al_dev->host->index);
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
"card %d\n", __func__, card->host->index);
@@ -3924,14 +3969,6 @@
destroy_workqueue(sdio_al_dev->workqueue);
wake_lock_destroy(&sdio_al_dev->wake_lock);
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: delete data "
- "structures for card %d\n", __func__,
- card->host->index);
- kfree(sdio_al_dev->sdioc_sw_header);
- kfree(sdio_al_dev->mailbox);
- kfree(sdio_al_dev->rx_flush_buf);
- kfree(sdio_al_dev);
-
sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
"\n", __func__, card->host->index);
}
@@ -4008,14 +4045,14 @@
continue;
}
- if (!sdio_al_dev->card && !sdio_al_dev->card->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card"
- " or Host fields are NULL\n);");
+ if (!sdio_al_dev->host) {
+ sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
+ " is NULL\n);");
continue;
}
snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
/* printing Shadowing HW Mailbox*/
mailbox = sdio_al_dev->mailbox;
@@ -4023,13 +4060,13 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
"is_ok_to_sleep=%d\n",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
sdio_al_dev->is_ok_to_sleep);
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
"Shadow channels SW MB:",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
/* printing Shadowing SW Mailbox per channel*/
for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
@@ -4073,10 +4110,10 @@
for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- return;
+ if (sdio_al_verify_func1(sdio_al_dev, __func__))
+ continue;
- if (!sdio_al_dev->card->host) {
+ if (!sdio_al_dev->host) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": Host is NULL");
continue;
@@ -4086,7 +4123,7 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": %s - for Card#%d, is lpm_chan=="
"INVALID_SDIO_CHAN. continuing...",
- __func__, sdio_al_dev->card->host->index);
+ __func__, sdio_al_dev->host->index);
continue;
}
@@ -4101,66 +4138,63 @@
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": %s - lpm_func is NULL for card#%d"
" continuing...\n", __func__,
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
continue;
}
- sdio_claim_host(sdio_al_dev->card->sdio_func[0]);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return;
ret = sdio_memcpy_fromio(lpm_func,
&is_ok_to_sleep,
SDIOC_SW_MAILBOX_ADDR+offset,
sizeof(int));
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- return;
- sdio_release_host(sdio_al_dev->card->sdio_func[0]);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
if (ret)
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": %s - fail to read "
"is_HOST_ok_to_sleep from mailbox for card %d",
- __func__, sdio_al_dev->card->host->index);
+ __func__, sdio_al_dev->host->index);
else
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": Card#%d: "
"is_HOST_ok_to_sleep=%d\n",
- sdio_al_dev->card->host->index,
+ sdio_al_dev->host->index,
is_ok_to_sleep);
}
for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (!sdio_al_dev->card->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Host is NULL");
+ if (!sdio_al_dev)
continue;
- }
/* Reading HW Mailbox */
hw_mailbox = sdio_al_dev->mailbox;
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_claim_host(func1);
+ if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
+ return;
+
+ if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
+ sdio_al_release_mutex(sdio_al_dev, __func__);
+ return;
+ }
+ func1 = sdio_al_dev->card->sdio_func[0];
ret = sdio_memcpy_fromio(func1, hw_mailbox,
HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
- if (sdio_al_verify_dev(sdio_al_dev, __func__))
- return;
- sdio_release_host(func1);
+ sdio_al_release_mutex(sdio_al_dev, __func__);
if (ret) {
sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
": fail to read "
"mailbox for card#%d. "
"continuing...\n",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
continue;
}
snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
- sdio_al_dev->card->host->index);
+ sdio_al_dev->host->index);
/* Printing HW Mailbox */
sdio_print_mailbox(buf, hw_mailbox);