diff mbox

[for,3.19,2/3] rtlwifi: Fix handling of new style descriptors

Message ID 1421257036-5382-3-git-send-email-Larry.Finger@lwfinger.net (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Larry Finger Jan. 14, 2015, 5:37 p.m. UTC
From: Troy Tan <troy_tan@realsil.com.cn>

The hardware and firmware for the RTL8192EE utilize a FIFO list of
descriptors. There were some problems with the initial implementation.
The worst of these failed to detect that the FIFO was becoming full,
which led to the device needing to be power cycled. As this condition
is not relevant to most of the devices supported by rtlwifi, a callback
routine was added to detect this situation. This patch implements the
necessary changes in the pci handler.

Signed-off-by: Troy Tan <troy_tan@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
 drivers/net/wireless/rtlwifi/pci.c  | 31 +++++++++++++++++++++++--------
 drivers/net/wireless/rtlwifi/wifi.h |  1 +
 2 files changed, 24 insertions(+), 8 deletions(-)

Comments

Kalle Valo Jan. 15, 2015, 11:44 a.m. UTC | #1
Larry Finger <Larry.Finger@lwfinger.net> writes:

> From: Troy Tan <troy_tan@realsil.com.cn>
>
> The hardware and firmware for the RTL8192EE utilize a FIFO list of
> descriptors. There were some problems with the initial implementation.
> The worst of these failed to detect that the FIFO was becoming full,
> which led to the device needing to be power cycled. As this condition
> is not relevant to most of the devices supported by rtlwifi, a callback
> routine was added to detect this situation. This patch implements the
> necessary changes in the pci handler.
>
> Signed-off-by: Troy Tan <troy_tan@realsil.com.cn>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>

[...]

> --- a/drivers/net/wireless/rtlwifi/wifi.h
> +++ b/drivers/net/wireless/rtlwifi/wifi.h
> @@ -2172,6 +2172,7 @@ struct rtl_hal_ops {
>  	void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
>  				   struct rtl_wow_pattern *rtl_pattern,
>  				   u8 index);
> +	u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);

I don't see this op set anywhere within the patch. Is that correct or
did I miss something?
Kalle Valo Jan. 15, 2015, noon UTC | #2
Hi Troy,

please avoid top-posting.

??? <troy_tan@realsil.com.cn> writes:

> You can find get_available_desc here:
>
> diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/
> pci.c
> index e25faac..a62170e 100644
> --- a/drivers/net/wireless/rtlwifi/pci.c
> +++ b/drivers/net/wireless/rtlwifi/pci.c
> @@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int
> prio)
>                 else
>                         entry = (u8 *)(&ring->desc[ring->idx]);
>
> +               if (rtlpriv->cfg->ops->get_available_desc &&
> +                   rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
> +                       RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
> +                                "no available desc!\n");
> +                       return;
> +               }

I don't see rtlpriv->cfg->ops->get_available_desc set here, only being
called?
Larry Finger Jan. 15, 2015, 5:14 p.m. UTC | #3
On 01/15/2015 06:00 AM, Kalle Valo wrote:
> Hi Troy,
>
> please avoid top-posting.
>
> ??? <troy_tan@realsil.com.cn> writes:
>
>> You can find get_available_desc here:
>>
>> diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/
>> pci.c
>> index e25faac..a62170e 100644
>> --- a/drivers/net/wireless/rtlwifi/pci.c
>> +++ b/drivers/net/wireless/rtlwifi/pci.c
>> @@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int
>> prio)
>>                  else
>>                          entry = (u8 *)(&ring->desc[ring->idx]);
>>
>> +               if (rtlpriv->cfg->ops->get_available_desc &&
>> +                   rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
>> +                       RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
>> +                                "no available desc!\n");
>> +                       return;
>> +               }
>
> I don't see rtlpriv->cfg->ops->get_available_desc set here, only being
> called?

Only one of the drivers (rtl8192ee) needs to implement that routine, which is 
the reason it is checked for non-NULL before it is called. The implementation is 
in patch 3 in file rtl8192ee/sw.c where it says:

@@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = {
  	.set_desc = rtl92ee_set_desc,
  	.get_desc = rtl92ee_get_desc,
  	.is_tx_desc_closed = rtl92ee_is_tx_desc_closed,
+	.get_available_desc = rtl92ee_get_available_desc,
  	.tx_polling = rtl92ee_tx_polling,
  	.enable_hw_sec = rtl92ee_enable_hw_security_config,
  	.init_sw_leds = rtl92ee_init_sw_leds,

Larry



--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Larry Finger Jan. 15, 2015, 8:10 p.m. UTC | #4
On 01/15/2015 06:00 AM, Kalle Valo wrote:
> Hi Troy,
>
> please avoid top-posting.
>
> ??? <troy_tan@realsil.com.cn> writes:
>
>> You can find get_available_desc here:
>>
>> diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/
>> pci.c
>> index e25faac..a62170e 100644
>> --- a/drivers/net/wireless/rtlwifi/pci.c
>> +++ b/drivers/net/wireless/rtlwifi/pci.c
>> @@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int
>> prio)
>>                  else
>>                          entry = (u8 *)(&ring->desc[ring->idx]);
>>
>> +               if (rtlpriv->cfg->ops->get_available_desc &&
>> +                   rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
>> +                       RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
>> +                                "no available desc!\n");
>> +                       return;
>> +               }
>
> I don't see rtlpriv->cfg->ops->get_available_desc set here, only being
> called?

Kalle,

Troy and I will try to prepare a patch that only fixes the bugs, and we will 
submit the cleanup for -next.

Sorry for the noise,

Larry


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kalle Valo Jan. 16, 2015, 6:40 a.m. UTC | #5
Larry Finger <Larry.Finger@lwfinger.net> writes:

> Troy and I will try to prepare a patch that only fixes the bugs, and
> we will submit the cleanup for -next.

That's great, thank you.
diff mbox

Patch

diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index e25faac..a62170e 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -578,6 +578,13 @@  static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 		else
 			entry = (u8 *)(&ring->desc[ring->idx]);
 
+		if (rtlpriv->cfg->ops->get_available_desc &&
+		    rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
+			RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
+				 "no available desc!\n");
+			return;
+		}
+
 		if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
 			return;
 		ring->idx = (ring->idx + 1) % ring->entries;
@@ -641,10 +648,9 @@  static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 
 		ieee80211_tx_status_irqsafe(hw, skb);
 
-		if ((ring->entries - skb_queue_len(&ring->queue))
-				== 2) {
+		if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) {
 
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
 				 "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
 				 prio, ring->idx,
 				 skb_queue_len(&ring->queue));
@@ -793,7 +799,7 @@  static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 			rx_remained_cnt =
 				rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
 								      hw_queue);
-			if (rx_remained_cnt < 1)
+			if (rx_remained_cnt == 0)
 				return;
 
 		} else {	/* rx descriptor */
@@ -845,18 +851,18 @@  static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 			else
 				skb_reserve(skb, stats.rx_drvinfo_size +
 					    stats.rx_bufshift);
-
 		} else {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 				 "skb->end - skb->tail = %d, len is %d\n",
 				 skb->end - skb->tail, len);
-			break;
+			dev_kfree_skb_any(skb);
+			goto new_trx_end;
 		}
 		/* handle command packet here */
 		if (rtlpriv->cfg->ops->rx_command_packet &&
 		    rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
 				dev_kfree_skb_any(skb);
-				goto end;
+				goto new_trx_end;
 		}
 
 		/*
@@ -906,6 +912,7 @@  static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 		} else {
 			dev_kfree_skb_any(skb);
 		}
+new_trx_end:
 		if (rtlpriv->use_new_trx_flow) {
 			rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
 			rtlpci->rx_ring[hw_queue].next_rx_rp %=
@@ -921,7 +928,6 @@  static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 			rtlpriv->enter_ps = false;
 			schedule_work(&rtlpriv->works.lps_change_work);
 		}
-end:
 		skb = new_skb;
 no_new:
 		if (rtlpriv->use_new_trx_flow) {
@@ -1685,6 +1691,15 @@  static int rtl_pci_tx(struct ieee80211_hw *hw,
 		}
 	}
 
+	if (rtlpriv->cfg->ops->get_available_desc &&
+	    rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) {
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+				 "get_available_desc fail\n");
+			spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+					       flags);
+			return skb->len;
+	}
+
 	if (ieee80211_is_data_qos(fc)) {
 		tid = rtl_get_tid(skb);
 		if (sta) {
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 3b3453a..413c2ab 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -2172,6 +2172,7 @@  struct rtl_hal_ops {
 	void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
 				   struct rtl_wow_pattern *rtl_pattern,
 				   u8 index);
+	u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);
 };
 
 struct rtl_intf_ops {