ath6kl: cold reset target after host warm boot
[cascardo/linux.git] / drivers / net / wireless / ath / ath6kl / htc_pipe.c
index ba6bd49..67aa924 100644 (file)
@@ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet)
 {
        struct sk_buff *skb;
        skb = packet->skb;
-       if (skb != NULL)
-               dev_kfree_skb(skb);
-
+       dev_kfree_skb(skb);
        kfree(packet);
 }
 
@@ -969,13 +967,27 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
        u16 payload_len;
        int status = 0;
 
+       /*
+        * ar->htc_target can be NULL due to a race condition that can occur
+        * during driver initialization(we do 'ath6kl_hif_power_on' before
+        * initializing 'ar->htc_target' via 'ath6kl_htc_create').
+        * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
+        * usb_complete_t/callback function for 'usb_fill_bulk_urb'.
+        * Thus the possibility of ar->htc_target being NULL
+        * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
+        */
+       if (WARN_ON_ONCE(!target)) {
+               ath6kl_err("Target not yet initialized\n");
+               status = -EINVAL;
+               goto free_skb;
+       }
+
+
        netdata = skb->data;
        netlen = skb->len;
 
        htc_hdr = (struct htc_frame_hdr *) netdata;
 
-       ep = &target->endpoint[htc_hdr->eid];
-
        if (htc_hdr->eid >= ENDPOINT_MAX) {
                ath6kl_dbg(ATH6KL_DBG_HTC,
                           "HTC Rx: invalid EndpointID=%d\n",
@@ -983,6 +995,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
                status = -EINVAL;
                goto free_skb;
        }
+       ep = &target->endpoint[htc_hdr->eid];
 
        payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
 
@@ -1054,6 +1067,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
 
                dev_kfree_skb(skb);
                skb = NULL;
+
                goto free_skb;
        }
 
@@ -1089,8 +1103,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
        skb = NULL;
 
 free_skb:
-       if (skb != NULL)
-               dev_kfree_skb(skb);
+       dev_kfree_skb(skb);
 
        return status;
 
@@ -1154,8 +1167,8 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target)
        }
 
        if (count <= 0) {
-               ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Timeout!\n", __func__);
-               return -ECOMM;
+               ath6kl_warn("htc pipe control receive timeout!\n");
+               return -ETIMEDOUT;
        }
 
        return 0;
@@ -1184,7 +1197,7 @@ static void reset_endpoint_states(struct htc_target *target)
                INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
                INIT_LIST_HEAD(&ep->rx_bufq);
                ep->target = target;
-               ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */
+               ep->pipe.tx_credit_flow_enabled = true;
        }
 }
 
@@ -1568,16 +1581,16 @@ static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
                return status;
 
        if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
-               ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg len:%d!\n",
-                          target->pipe.ctrl_response_len);
+               ath6kl_warn("invalid htc pipe ready msg len: %d\n",
+                           target->pipe.ctrl_response_len);
                return -ECOMM;
        }
 
        ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;
 
        if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
-               ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg : 0x%X !\n",
-                          ready_msg->ver2_0_info.msg_id);
+               ath6kl_warn("invalid htc pipe ready msg: 0x%x\n",
+                           ready_msg->ver2_0_info.msg_id);
                return -ECOMM;
        }