aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-core.c
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2010-12-03 09:41:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-06 16:01:29 -0500
commit22de94de7de78b8de2fb1f2df5aa85b5556cfcfd (patch)
treef965d5f907ffc039ca146c22a5c2e87744cbc604 /drivers/net/wireless/iwlwifi/iwl-core.c
parentabc471dc31be15f9fee5ec77f25d31b927d334b9 (diff)
iwlwifi: jiffies based tx queues watchdog
This patch replace monitor/recover timer by watchdog based on time stamp. New code allow to discover hangs more precisely. Timeout values are currently doubled monitoring period values of previous timer. This have to be tuned based of firmware timing capabilities. Tested on 3945, 4965, 5300, 6300. Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-core.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c111
1 files changed, 49 insertions, 62 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c41f5a87821..d62b9251841 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1894,77 +1894,58 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1894} 1894}
1895EXPORT_SYMBOL(iwl_mac_change_interface); 1895EXPORT_SYMBOL(iwl_mac_change_interface);
1896 1896
1897/**
1898 * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
1899 *
1900 * During normal condition (no queue is stuck), the timer is continually set to
1901 * execute every monitor_recover_period milliseconds after the last timer
1902 * expired. When the queue read_ptr is at the same place, the timer is
1903 * shorten to 100mSecs. This is
1904 * 1) to reduce the chance that the read_ptr may wrap around (not stuck)
1905 * 2) to detect the stuck queues quicker before the station and AP can
1906 * disassociate each other.
1907 *
1908 * This function monitors all the tx queues and recover from it if any
1909 * of the queues are stuck.
1910 * 1. It first check the cmd queue for stuck conditions. If it is stuck,
1911 * it will recover by resetting the firmware and return.
1912 * 2. Then, it checks for station association. If it associates it will check
1913 * other queues. If any queue is stuck, it will recover by resetting
1914 * the firmware.
1915 * Note: It the number of times the queue read_ptr to be at the same place to
1916 * be MAX_REPEAT+1 in order to consider to be stuck.
1917 */
1918/* 1897/*
1919 * The maximum number of times the read pointer of the tx queue at the 1898 * On every watchdog tick we check (latest) time stamp. If it does not
1920 * same place without considering to be stuck. 1899 * change during timeout period and queue is not empty we reset firmware.
1921 */ 1900 */
1922#define MAX_REPEAT (2)
1923static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) 1901static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
1924{ 1902{
1925 struct iwl_tx_queue *txq; 1903 struct iwl_tx_queue *txq = &priv->txq[cnt];
1926 struct iwl_queue *q; 1904 struct iwl_queue *q = &txq->q;
1905 unsigned long timeout;
1906 int ret;
1927 1907
1928 txq = &priv->txq[cnt]; 1908 if (q->read_ptr == q->write_ptr) {
1929 q = &txq->q; 1909 txq->time_stamp = jiffies;
1930 /* queue is empty, skip */
1931 if (q->read_ptr == q->write_ptr)
1932 return 0; 1910 return 0;
1911 }
1933 1912
1934 if (q->read_ptr == q->last_read_ptr) { 1913 timeout = txq->time_stamp +
1935 /* a queue has not been read from last time */ 1914 msecs_to_jiffies(priv->cfg->base_params->wd_timeout);
1936 if (q->repeat_same_read_ptr > MAX_REPEAT) { 1915
1937 IWL_ERR(priv, 1916 if (time_after(jiffies, timeout)) {
1938 "queue %d stuck %d time. Fw reload.\n", 1917 IWL_ERR(priv, "Queue %d stuck for %u ms.\n",
1939 q->id, q->repeat_same_read_ptr); 1918 q->id, priv->cfg->base_params->wd_timeout);
1940 q->repeat_same_read_ptr = 0; 1919 ret = iwl_force_reset(priv, IWL_FW_RESET, false);
1941 iwl_force_reset(priv, IWL_FW_RESET, false); 1920 return (ret == -EAGAIN) ? 0 : 1;
1942 } else {
1943 q->repeat_same_read_ptr++;
1944 IWL_DEBUG_RADIO(priv,
1945 "queue %d, not read %d time\n",
1946 q->id,
1947 q->repeat_same_read_ptr);
1948 mod_timer(&priv->monitor_recover,
1949 jiffies + msecs_to_jiffies(
1950 IWL_ONE_HUNDRED_MSECS));
1951 return 1;
1952 }
1953 } else {
1954 q->last_read_ptr = q->read_ptr;
1955 q->repeat_same_read_ptr = 0;
1956 } 1921 }
1922
1957 return 0; 1923 return 0;
1958} 1924}
1959 1925
1960void iwl_bg_monitor_recover(unsigned long data) 1926/*
1927 * Making watchdog tick be a quarter of timeout assure we will
1928 * discover the queue hung between timeout and 1.25*timeout
1929 */
1930#define IWL_WD_TICK(timeout) ((timeout) / 4)
1931
1932/*
1933 * Watchdog timer callback, we check each tx queue for stuck, if if hung
1934 * we reset the firmware. If everything is fine just rearm the timer.
1935 */
1936void iwl_bg_watchdog(unsigned long data)
1961{ 1937{
1962 struct iwl_priv *priv = (struct iwl_priv *)data; 1938 struct iwl_priv *priv = (struct iwl_priv *)data;
1963 int cnt; 1939 int cnt;
1940 unsigned long timeout;
1964 1941
1965 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 1942 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
1966 return; 1943 return;
1967 1944
1945 timeout = priv->cfg->base_params->wd_timeout;
1946 if (timeout == 0)
1947 return;
1948
1968 /* monitor and check for stuck cmd queue */ 1949 /* monitor and check for stuck cmd queue */
1969 if (iwl_check_stuck_queue(priv, priv->cmd_queue)) 1950 if (iwl_check_stuck_queue(priv, priv->cmd_queue))
1970 return; 1951 return;
@@ -1979,17 +1960,23 @@ void iwl_bg_monitor_recover(unsigned long data)
1979 return; 1960 return;
1980 } 1961 }
1981 } 1962 }
1982 if (priv->cfg->base_params->monitor_recover_period) { 1963
1983 /* 1964 mod_timer(&priv->watchdog, jiffies +
1984 * Reschedule the timer to occur in 1965 msecs_to_jiffies(IWL_WD_TICK(timeout)));
1985 * priv->cfg->base_params->monitor_recover_period
1986 */
1987 mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
1988 priv->cfg->base_params->monitor_recover_period));
1989 }
1990} 1966}
1991EXPORT_SYMBOL(iwl_bg_monitor_recover); 1967EXPORT_SYMBOL(iwl_bg_watchdog);
1968
1969void iwl_setup_watchdog(struct iwl_priv *priv)
1970{
1971 unsigned int timeout = priv->cfg->base_params->wd_timeout;
1992 1972
1973 if (timeout)
1974 mod_timer(&priv->watchdog,
1975 jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
1976 else
1977 del_timer(&priv->watchdog);
1978}
1979EXPORT_SYMBOL(iwl_setup_watchdog);
1993 1980
1994/* 1981/*
1995 * extended beacon time format 1982 * extended beacon time format