msm: sdio: Check card state before accessing sdio functions.

When there is a modem reset due to HW watchdog, the card structure
is removed. Hence check the card state before accessing any sdio
function including lpm_func.

Change-Id: Ia119cc4cb6439f82a547297e5886fac868b03ceb
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
index 8fff2461..891d655 100644
--- a/arch/arm/mach-msm/sdio_al.c
+++ b/arch/arm/mach-msm/sdio_al.c
@@ -878,8 +878,7 @@
  */
 static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
 {
-	struct sdio_func *lpm_func =
-		sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
+	struct sdio_func *lpm_func = NULL;
 	int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
 		sizeof(struct peer_sdioc_channel_config) *
 		sdio_al_dev->lpm_chan+
@@ -893,6 +892,14 @@
 		return -EINVAL;
 	}
 
+	if (!sdio_al_dev->card ||
+		!sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or lpm_func\n");
+		return -ENODEV;
+	}
+	lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
+
 	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->host->index);
@@ -1900,8 +1907,7 @@
 		ch->poll_delay_msec = 0;
 
 		ch->num = i;
-
-		ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
+		ch->func = NULL;
 		ch->rx_pipe_index = ch->num*2;
 		ch->tx_pipe_index = ch->num*2+1;
 
@@ -1916,6 +1922,15 @@
 
 			ch->state = SDIO_CHANNEL_STATE_IDLE;
 			ch->sdio_al_dev = sdio_al_dev;
+			if (sdio_al_dev->card->sdio_func[ch->num+1]) {
+				ch->func =
+				sdio_al_dev->card->sdio_func[ch->num+1];
+			} else {
+				sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+					": NULL func for channel %s\n",
+					ch->name);
+				goto exit_err;
+			}
 		} else {
 			ch->state = SDIO_CHANNEL_STATE_INVALID;
 		}
@@ -2802,18 +2817,19 @@
 {
 	int ret;
 	int offset;
-	struct sdio_func *wk_func;
+	struct sdio_func *wk_func = NULL;
 	u32 peer_operation;
 	int loop_count = 0;
 
-	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
-	if (!wk_func) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL "
-				"wakeup func:%d\n", __func__,
-				SDIO_AL_WAKEUP_FUNC);
+	if (!sdio_al_dev->card ||
+	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
+		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
+				": NULL card or wk_func\n");
 		ret = -ENODEV;
 		goto exit;
 	}
+	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
+
 	/* calculate offset of peer_operation field in sw mailbox struct */
 	offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
 		sizeof(struct peer_sdioc_channel_config) * ch->num +
@@ -3440,7 +3456,6 @@
 							*sdio_al_dev)
 {
 	int ret = 0;
-	struct sdio_func *func1 = NULL;
 	struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
 	int j;
 
@@ -3449,13 +3464,6 @@
 	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_loge(&sdio_al->gen_log, MODULE_NAME ": %s: "
-			"NULL func1 for card %d", __func__,
-			sdio_al_dev->host->index);
-		goto exit_err;
-	}
-
 	if (sdio_al_dev->state == CARD_REMOVED) {
 		sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
 			"card %d is already removed", __func__,
@@ -3487,13 +3495,13 @@
 		ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
 	}
 
-	if (!ret && (!sdio_al_dev->is_err)) {
-		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
+	if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
+		sdio_al_dev->card->sdio_func[0]) {
+			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]);
+			sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
 	}
 
 	memset(pdev_arr, 0, sizeof(pdev_arr));