Commit 9fe9c37c authored by Troy Tan's avatar Troy Tan Committed by Greg Kroah-Hartman

rtlwifi: rtl8192ee: Fix handling of new style descriptors

commit d0311314 upstream.

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, and the linkage into the appropriate
rtl8192ee routine.
Signed-off-by: default avatarTroy Tan <troy_tan@realsil.com.cn>
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org> [V3.18]
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 014275c8
...@@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) ...@@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
else else
entry = (u8 *)(&ring->desc[ring->idx]); 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)) if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
return; return;
ring->idx = (ring->idx + 1) % ring->entries; ring->idx = (ring->idx + 1) % ring->entries;
...@@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) ...@@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
ieee80211_tx_status_irqsafe(hw, skb); ieee80211_tx_status_irqsafe(hw, skb);
if ((ring->entries - skb_queue_len(&ring->queue)) if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) {
== 2) {
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", "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
prio, ring->idx, prio, ring->idx,
skb_queue_len(&ring->queue)); skb_queue_len(&ring->queue));
...@@ -793,7 +799,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) ...@@ -793,7 +799,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rx_remained_cnt = rx_remained_cnt =
rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
hw_queue); hw_queue);
if (rx_remained_cnt < 1) if (rx_remained_cnt == 0)
return; return;
} else { /* rx descriptor */ } else { /* rx descriptor */
...@@ -845,18 +851,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) ...@@ -845,18 +851,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
else else
skb_reserve(skb, stats.rx_drvinfo_size + skb_reserve(skb, stats.rx_drvinfo_size +
stats.rx_bufshift); stats.rx_bufshift);
} else { } else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"skb->end - skb->tail = %d, len is %d\n", "skb->end - skb->tail = %d, len is %d\n",
skb->end - skb->tail, len); skb->end - skb->tail, len);
break; dev_kfree_skb_any(skb);
goto new_trx_end;
} }
/* handle command packet here */ /* handle command packet here */
if (rtlpriv->cfg->ops->rx_command_packet && if (rtlpriv->cfg->ops->rx_command_packet &&
rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
dev_kfree_skb_any(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) ...@@ -906,6 +912,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
} else { } else {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
new_trx_end:
if (rtlpriv->use_new_trx_flow) { if (rtlpriv->use_new_trx_flow) {
rtlpci->rx_ring[hw_queue].next_rx_rp += 1; rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
rtlpci->rx_ring[hw_queue].next_rx_rp %= rtlpci->rx_ring[hw_queue].next_rx_rp %=
...@@ -921,7 +928,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) ...@@ -921,7 +928,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rtlpriv->enter_ps = false; rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work); schedule_work(&rtlpriv->works.lps_change_work);
} }
end:
skb = new_skb; skb = new_skb;
no_new: no_new:
if (rtlpriv->use_new_trx_flow) { if (rtlpriv->use_new_trx_flow) {
...@@ -1695,6 +1701,15 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, ...@@ -1695,6 +1701,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)) { if (ieee80211_is_data_qos(fc)) {
tid = rtl_get_tid(skb); tid = rtl_get_tid(skb);
if (sta) { if (sta) {
......
...@@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) ...@@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
RCR_HTC_LOC_CTRL | RCR_HTC_LOC_CTRL |
RCR_AMF | RCR_AMF |
RCR_ACF | RCR_ACF |
RCR_ADF |
RCR_AICV |
RCR_ACRC32 | RCR_ACRC32 |
RCR_AB | RCR_AB |
RCR_AM | RCR_AM |
...@@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { ...@@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = {
.set_desc = rtl92ee_set_desc, .set_desc = rtl92ee_set_desc,
.get_desc = rtl92ee_get_desc, .get_desc = rtl92ee_get_desc,
.is_tx_desc_closed = rtl92ee_is_tx_desc_closed, .is_tx_desc_closed = rtl92ee_is_tx_desc_closed,
.get_available_desc = rtl92ee_get_available_desc,
.tx_polling = rtl92ee_tx_polling, .tx_polling = rtl92ee_tx_polling,
.enable_hw_sec = rtl92ee_enable_hw_security_config, .enable_hw_sec = rtl92ee_enable_hw_security_config,
.set_key = rtl92ee_set_key, .set_key = rtl92ee_set_key,
......
...@@ -707,7 +707,7 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index) ...@@ -707,7 +707,7 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index)
return desc_address; return desc_address;
} }
void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
{ {
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
...@@ -721,11 +721,12 @@ void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) ...@@ -721,11 +721,12 @@ void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
current_tx_write_point = (u16)((tmp_4byte) & 0x0fff); current_tx_write_point = (u16)((tmp_4byte) & 0x0fff);
point_diff = ((current_tx_read_point > current_tx_write_point) ? point_diff = ((current_tx_read_point > current_tx_write_point) ?
(current_tx_read_point - current_tx_write_point) : (current_tx_read_point - current_tx_write_point - 1) :
(TX_DESC_NUM_92E - current_tx_write_point + (TX_DESC_NUM_92E - 1 - current_tx_write_point +
current_tx_read_point)); current_tx_read_point));
rtlpci->tx_ring[q_idx].avl_desc = point_diff; rtlpci->tx_ring[q_idx].avl_desc = point_diff;
return point_diff;
} }
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
......
...@@ -831,7 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, ...@@ -831,7 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc,
u8 queue_index); u8 queue_index);
u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw,
u8 queue_index); u8 queue_index);
void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index);
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
u8 *tx_bd_desc, u8 *desc, u8 queue_index, u8 *tx_bd_desc, u8 *desc, u8 queue_index,
struct sk_buff *skb, dma_addr_t addr); struct sk_buff *skb, dma_addr_t addr);
......
...@@ -2161,6 +2161,7 @@ struct rtl_hal_ops { ...@@ -2161,6 +2161,7 @@ struct rtl_hal_ops {
void (*add_wowlan_pattern)(struct ieee80211_hw *hw, void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
struct rtl_wow_pattern *rtl_pattern, struct rtl_wow_pattern *rtl_pattern,
u8 index); u8 index);
u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);
}; };
struct rtl_intf_ops { struct rtl_intf_ops {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment