summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ralink
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:03 +0000
commit01a69402cf9d38ff180345d55c2ee51c7e89fbc7 (patch)
treeb406c5242a088c4f59c6e4b719b783f43aca6ae9 /drivers/net/wireless/ralink
parentAdding upstream version 6.7.12. (diff)
downloadlinux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.tar.xz
linux-01a69402cf9d38ff180345d55c2ee51c7e89fbc7.zip
Adding upstream version 6.8.9.upstream/6.8.9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/net/wireless/ralink')
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800.h4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c86
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h5
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00queue.c3
5 files changed, 79 insertions, 21 deletions
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h
index 48521e4557..8930589b49 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
@@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word {
*/
#define BCN_TBTT_OFFSET 64
+/* Watchdog type mask */
+#define RT2800_WATCHDOG_HANG BIT(0)
+#define RT2800_WATCHDOG_DMA_BUSY BIT(1)
+
#endif /* RT2800_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 1926ffdffb..aaf31857ae 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -30,9 +30,10 @@
#include "rt2800lib.h"
#include "rt2800.h"
-static bool modparam_watchdog;
-module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
-MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
+static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY;
+module_param_named(watchdog, modparam_watchdog, uint, 0444);
+MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n"
+ "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)");
/*
* Register access.
@@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
}
-void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
bool hung_tx = false;
bool hung_rx = false;
- if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
- return;
-
rt2800_update_survey(rt2x00dev);
queue_for_each(rt2x00dev, queue) {
@@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
}
}
+ if (!hung_tx && !hung_rx)
+ return false;
+
if (hung_tx)
rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
if (hung_rx)
rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
- if (hung_tx || hung_rx) {
- queue_for_each(rt2x00dev, queue)
- queue->wd_count = 0;
+ queue_for_each(rt2x00dev, queue)
+ queue->wd_count = 0;
+
+ return true;
+}
+
+static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev)
+{
+ bool busy_rx, busy_tx;
+ u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
+ u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR);
+
+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) &&
+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT))
+ rt2x00dev->rxdma_busy++;
+ else
+ rt2x00dev->rxdma_busy = 0;
+
+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT))
+ rt2x00dev->txdma_busy++;
+ else
+ rt2x00dev->txdma_busy = 0;
+
+ busy_rx = rt2x00dev->rxdma_busy > 30;
+ busy_tx = rt2x00dev->txdma_busy > 30;
+
+ if (!busy_rx && !busy_tx)
+ return false;
+
+ if (busy_rx)
+ rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n");
+
+ if (busy_tx)
+ rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n");
+
+ rt2x00dev->rxdma_busy = 0;
+ rt2x00dev->txdma_busy = 0;
+
+ return true;
+}
+
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ bool reset = false;
+
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
+ if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_DMA_BUSY)
+ reset = rt2800_watchdog_dma_busy(rt2x00dev);
+ if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_HANG)
+ reset = rt2800_watchdog_hung(rt2x00dev) || reset;
+
+ if (reset)
ieee80211_restart_hw(rt2x00dev->hw);
- }
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);
@@ -6048,7 +6100,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
- rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 0);
rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG);
@@ -6061,7 +6113,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
- rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 0);
rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG);
@@ -12013,11 +12065,13 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
- if (modparam_watchdog) {
+ rt2x00dev->link.watchdog = modparam_watchdog;
+ /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */
+ if (rt2x00_is_usb(rt2x00dev))
+ rt2x00dev->link.watchdog &= ~RT2800_WATCHDOG_DMA_BUSY;
+ if (rt2x00dev->link.watchdog) {
__set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
- } else {
- rt2x00dev->link.watchdog_disabled = true;
}
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index aaaf993319..82af01448a 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -334,7 +334,7 @@ struct link {
*/
struct delayed_work watchdog_work;
unsigned int watchdog_interval;
- bool watchdog_disabled;
+ unsigned int watchdog;
/*
* Work structure for scheduling periodic AGC adjustments.
@@ -926,6 +926,9 @@ struct rt2x00_dev {
*/
u16 beacon_int;
+ /* Rx/Tx DMA busy watchdog counter */
+ u16 rxdma_busy, txdma_busy;
+
/**
* Timestamp of last received beacon
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
index 6cf7e7c997..fb23d409fb 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -384,7 +384,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
+ rt2x00dev->ops->lib->watchdog && link->watchdog)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
index 98df0aef81..013003777f 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -416,9 +416,6 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
else
__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
- if (tx_info->control.rts_cts_rate_idx >= 0)
- rate =
- ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
}
/*