root/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mt76x02_pre_tbtt_tasklet
  2. mt76x02e_pre_tbtt_enable
  3. mt76x02e_beacon_enable
  4. mt76x02e_init_beacon_config
  5. mt76x02_init_tx_queue
  6. mt76x02_init_rx_queue
  7. mt76x02_process_tx_status_fifo
  8. mt76x02_tx_tasklet
  9. mt76x02_poll_tx
  10. mt76x02_dma_init
  11. mt76x02_rx_poll_complete
  12. mt76x02_irq_handler
  13. mt76x02_dma_enable
  14. mt76x02_dma_cleanup
  15. mt76x02_dma_disable
  16. mt76x02_mac_start
  17. mt76x02_tx_hang
  18. mt76x02_key_sync
  19. mt76x02_reset_state
  20. mt76x02_watchdog_reset
  21. mt76x02_check_tx_hang
  22. mt76x02_wdt_work

   1 // SPDX-License-Identifier: ISC
   2 /*
   3  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
   4  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
   5  */
   6 
   7 #include <linux/kernel.h>
   8 #include <linux/irq.h>
   9 
  10 #include "mt76x02.h"
  11 #include "mt76x02_mcu.h"
  12 #include "mt76x02_trace.h"
  13 
  14 static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
  15 {
  16         struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
  17         struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD].q;
  18         struct beacon_bc_data data = {};
  19         struct sk_buff *skb;
  20         int i;
  21 
  22         if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL)
  23                 return;
  24 
  25         mt76x02_resync_beacon_timer(dev);
  26 
  27         ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
  28                 IEEE80211_IFACE_ITER_RESUME_ALL,
  29                 mt76x02_update_beacon_iter, dev);
  30 
  31         mt76_csa_check(&dev->mt76);
  32 
  33         if (dev->mt76.csa_complete)
  34                 return;
  35 
  36         mt76x02_enqueue_buffered_bc(dev, &data, 8);
  37 
  38         if (!skb_queue_len(&data.q))
  39                 return;
  40 
  41         for (i = 0; i < ARRAY_SIZE(data.tail); i++) {
  42                 if (!data.tail[i])
  43                         continue;
  44 
  45                 mt76_skb_set_moredata(data.tail[i], false);
  46         }
  47 
  48         spin_lock_bh(&q->lock);
  49         while ((skb = __skb_dequeue(&data.q)) != NULL) {
  50                 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  51                 struct ieee80211_vif *vif = info->control.vif;
  52                 struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
  53 
  54                 mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, &mvif->group_wcid,
  55                                   NULL);
  56         }
  57         spin_unlock_bh(&q->lock);
  58 }
  59 
  60 static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
  61 {
  62         if (en)
  63                 tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
  64         else
  65                 tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
  66 }
  67 
  68 static void mt76x02e_beacon_enable(struct mt76x02_dev *dev, bool en)
  69 {
  70         mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
  71         if (en)
  72                 mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
  73         else
  74                 mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
  75 }
  76 
  77 void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
  78 {
  79         static const struct mt76x02_beacon_ops beacon_ops = {
  80                 .nslots = 8,
  81                 .slot_size = 1024,
  82                 .pre_tbtt_enable = mt76x02e_pre_tbtt_enable,
  83                 .beacon_enable = mt76x02e_beacon_enable,
  84         };
  85 
  86         dev->beacon_ops = &beacon_ops;
  87 
  88         /* Fire a pre-TBTT interrupt 8 ms before TBTT */
  89         mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT,
  90                        8 << 4);
  91         mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER,
  92                        MT_DFS_GP_INTERVAL);
  93         mt76_wr(dev, MT_INT_TIMER_EN, 0);
  94 
  95         mt76x02_init_beacon_config(dev);
  96 }
  97 EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config);
  98 
  99 static int
 100 mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_sw_queue *q,
 101                       int idx, int n_desc)
 102 {
 103         struct mt76_queue *hwq;
 104         int err;
 105 
 106         hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
 107         if (!hwq)
 108                 return -ENOMEM;
 109 
 110         err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
 111         if (err < 0)
 112                 return err;
 113 
 114         INIT_LIST_HEAD(&q->swq);
 115         q->q = hwq;
 116 
 117         mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
 118 
 119         return 0;
 120 }
 121 
 122 static int
 123 mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
 124                       int idx, int n_desc, int bufsize)
 125 {
 126         int err;
 127 
 128         err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize,
 129                                MT_RX_RING_BASE);
 130         if (err < 0)
 131                 return err;
 132 
 133         mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx));
 134 
 135         return 0;
 136 }
 137 
 138 static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev)
 139 {
 140         struct mt76x02_tx_status stat;
 141         u8 update = 1;
 142 
 143         while (kfifo_get(&dev->txstatus_fifo, &stat))
 144                 mt76x02_send_tx_status(dev, &stat, &update);
 145 }
 146 
 147 static void mt76x02_tx_tasklet(unsigned long data)
 148 {
 149         struct mt76x02_dev *dev = (struct mt76x02_dev *)data;
 150 
 151         mt76x02_mac_poll_tx_status(dev, false);
 152         mt76x02_process_tx_status_fifo(dev);
 153 
 154         mt76_txq_schedule_all(&dev->mt76);
 155 }
 156 
 157 static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
 158 {
 159         struct mt76x02_dev *dev = container_of(napi, struct mt76x02_dev,
 160                                                mt76.tx_napi);
 161         int i;
 162 
 163         mt76x02_mac_poll_tx_status(dev, false);
 164 
 165         for (i = MT_TXQ_MCU; i >= 0; i--)
 166                 mt76_queue_tx_cleanup(dev, i, false);
 167 
 168         if (napi_complete_done(napi, 0))
 169                 mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL);
 170 
 171         for (i = MT_TXQ_MCU; i >= 0; i--)
 172                 mt76_queue_tx_cleanup(dev, i, false);
 173 
 174         tasklet_schedule(&dev->mt76.tx_tasklet);
 175 
 176         return 0;
 177 }
 178 
 179 int mt76x02_dma_init(struct mt76x02_dev *dev)
 180 {
 181         struct mt76_txwi_cache __maybe_unused *t;
 182         int i, ret, fifo_size;
 183         struct mt76_queue *q;
 184         void *status_fifo;
 185 
 186         BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
 187 
 188         fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status));
 189         status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL);
 190         if (!status_fifo)
 191                 return -ENOMEM;
 192 
 193         tasklet_init(&dev->mt76.tx_tasklet, mt76x02_tx_tasklet,
 194                      (unsigned long)dev);
 195         tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
 196                      (unsigned long)dev);
 197 
 198         spin_lock_init(&dev->txstatus_fifo_lock);
 199         kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
 200 
 201         mt76_dma_attach(&dev->mt76);
 202 
 203         mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
 204 
 205         for (i = 0; i < IEEE80211_NUM_ACS; i++) {
 206                 ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[i],
 207                                             mt76_ac_to_hwq(i),
 208                                             MT_TX_RING_SIZE);
 209                 if (ret)
 210                         return ret;
 211         }
 212 
 213         ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
 214                                     MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
 215         if (ret)
 216                 return ret;
 217 
 218         ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
 219                                     MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
 220         if (ret)
 221                 return ret;
 222 
 223         ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
 224                                     MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
 225         if (ret)
 226                 return ret;
 227 
 228         q = &dev->mt76.q_rx[MT_RXQ_MAIN];
 229         q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi);
 230         ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE,
 231                                     MT_RX_BUF_SIZE);
 232         if (ret)
 233                 return ret;
 234 
 235         ret = mt76_init_queues(dev);
 236         if (ret)
 237                 return ret;
 238 
 239         netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
 240                           mt76x02_poll_tx, NAPI_POLL_WEIGHT);
 241         napi_enable(&dev->mt76.tx_napi);
 242 
 243         return 0;
 244 }
 245 EXPORT_SYMBOL_GPL(mt76x02_dma_init);
 246 
 247 void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
 248 {
 249         struct mt76x02_dev *dev;
 250 
 251         dev = container_of(mdev, struct mt76x02_dev, mt76);
 252         mt76x02_irq_enable(dev, MT_INT_RX_DONE(q));
 253 }
 254 EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete);
 255 
 256 irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
 257 {
 258         struct mt76x02_dev *dev = dev_instance;
 259         u32 intr;
 260 
 261         intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
 262         mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
 263 
 264         if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
 265                 return IRQ_NONE;
 266 
 267         trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask);
 268 
 269         intr &= dev->mt76.mmio.irqmask;
 270 
 271         if (intr & MT_INT_RX_DONE(0)) {
 272                 mt76x02_irq_disable(dev, MT_INT_RX_DONE(0));
 273                 napi_schedule(&dev->mt76.napi[0]);
 274         }
 275 
 276         if (intr & MT_INT_RX_DONE(1)) {
 277                 mt76x02_irq_disable(dev, MT_INT_RX_DONE(1));
 278                 napi_schedule(&dev->mt76.napi[1]);
 279         }
 280 
 281         if (intr & MT_INT_PRE_TBTT)
 282                 tasklet_schedule(&dev->mt76.pre_tbtt_tasklet);
 283 
 284         /* send buffered multicast frames now */
 285         if (intr & MT_INT_TBTT) {
 286                 if (dev->mt76.csa_complete)
 287                         mt76_csa_finish(&dev->mt76);
 288                 else
 289                         mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD].q);
 290         }
 291 
 292         if (intr & MT_INT_TX_STAT)
 293                 mt76x02_mac_poll_tx_status(dev, true);
 294 
 295         if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) {
 296                 mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL);
 297                 napi_schedule(&dev->mt76.tx_napi);
 298         }
 299 
 300         if (intr & MT_INT_GPTIMER) {
 301                 mt76x02_irq_disable(dev, MT_INT_GPTIMER);
 302                 tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
 303         }
 304 
 305         return IRQ_HANDLED;
 306 }
 307 EXPORT_SYMBOL_GPL(mt76x02_irq_handler);
 308 
 309 static void mt76x02_dma_enable(struct mt76x02_dev *dev)
 310 {
 311         u32 val;
 312 
 313         mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
 314         mt76x02_wait_for_wpdma(&dev->mt76, 1000);
 315         usleep_range(50, 100);
 316 
 317         val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) |
 318               MT_WPDMA_GLO_CFG_TX_DMA_EN |
 319               MT_WPDMA_GLO_CFG_RX_DMA_EN;
 320         mt76_set(dev, MT_WPDMA_GLO_CFG, val);
 321         mt76_clear(dev, MT_WPDMA_GLO_CFG,
 322                    MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
 323 }
 324 
 325 void mt76x02_dma_cleanup(struct mt76x02_dev *dev)
 326 {
 327         tasklet_kill(&dev->mt76.tx_tasklet);
 328         mt76_dma_cleanup(&dev->mt76);
 329 }
 330 EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup);
 331 
 332 void mt76x02_dma_disable(struct mt76x02_dev *dev)
 333 {
 334         u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
 335 
 336         val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
 337                MT_WPDMA_GLO_CFG_BIG_ENDIAN |
 338                MT_WPDMA_GLO_CFG_HDR_SEG_LEN;
 339         val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE;
 340         mt76_wr(dev, MT_WPDMA_GLO_CFG, val);
 341 }
 342 EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
 343 
 344 void mt76x02_mac_start(struct mt76x02_dev *dev)
 345 {
 346         mt76x02_dma_enable(dev);
 347         mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
 348         mt76_wr(dev, MT_MAC_SYS_CTRL,
 349                 MT_MAC_SYS_CTRL_ENABLE_TX |
 350                 MT_MAC_SYS_CTRL_ENABLE_RX);
 351         mt76x02_irq_enable(dev,
 352                            MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
 353                            MT_INT_TX_STAT);
 354 }
 355 EXPORT_SYMBOL_GPL(mt76x02_mac_start);
 356 
 357 static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
 358 {
 359         u32 dma_idx, prev_dma_idx;
 360         struct mt76_queue *q;
 361         int i;
 362 
 363         for (i = 0; i < 4; i++) {
 364                 q = dev->mt76.q_tx[i].q;
 365 
 366                 if (!q->queued)
 367                         continue;
 368 
 369                 prev_dma_idx = dev->mt76.tx_dma_idx[i];
 370                 dma_idx = readl(&q->regs->dma_idx);
 371                 dev->mt76.tx_dma_idx[i] = dma_idx;
 372 
 373                 if (prev_dma_idx == dma_idx)
 374                         break;
 375         }
 376 
 377         return i < 4;
 378 }
 379 
 380 static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 381                              struct ieee80211_sta *sta,
 382                              struct ieee80211_key_conf *key, void *data)
 383 {
 384         struct mt76x02_dev *dev = hw->priv;
 385         struct mt76_wcid *wcid;
 386 
 387         if (!sta)
 388                 return;
 389 
 390         wcid = (struct mt76_wcid *)sta->drv_priv;
 391 
 392         if (wcid->hw_key_idx != key->keyidx || wcid->sw_iv)
 393                 return;
 394 
 395         mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key);
 396 }
 397 
 398 static void mt76x02_reset_state(struct mt76x02_dev *dev)
 399 {
 400         int i;
 401 
 402         lockdep_assert_held(&dev->mt76.mutex);
 403 
 404         clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
 405 
 406         rcu_read_lock();
 407         ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL);
 408         rcu_read_unlock();
 409 
 410         for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
 411                 struct ieee80211_sta *sta;
 412                 struct ieee80211_vif *vif;
 413                 struct mt76x02_sta *msta;
 414                 struct mt76_wcid *wcid;
 415                 void *priv;
 416 
 417                 wcid = rcu_dereference_protected(dev->mt76.wcid[i],
 418                                         lockdep_is_held(&dev->mt76.mutex));
 419                 if (!wcid)
 420                         continue;
 421 
 422                 priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
 423                 sta = container_of(priv, struct ieee80211_sta, drv_priv);
 424 
 425                 priv = msta->vif;
 426                 vif = container_of(priv, struct ieee80211_vif, drv_priv);
 427 
 428                 __mt76_sta_remove(&dev->mt76, vif, sta);
 429                 memset(msta, 0, sizeof(*msta));
 430         }
 431 
 432         dev->vif_mask = 0;
 433         dev->mt76.beacon_mask = 0;
 434 }
 435 
 436 static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
 437 {
 438         u32 mask = dev->mt76.mmio.irqmask;
 439         bool restart = dev->mt76.mcu_ops->mcu_restart;
 440         int i;
 441 
 442         ieee80211_stop_queues(dev->mt76.hw);
 443         set_bit(MT76_RESET, &dev->mt76.state);
 444 
 445         tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
 446         tasklet_disable(&dev->mt76.tx_tasklet);
 447         napi_disable(&dev->mt76.tx_napi);
 448 
 449         for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++)
 450                 napi_disable(&dev->mt76.napi[i]);
 451 
 452         mutex_lock(&dev->mt76.mutex);
 453 
 454         if (restart)
 455                 mt76x02_reset_state(dev);
 456 
 457         if (dev->mt76.beacon_mask)
 458                 mt76_clear(dev, MT_BEACON_TIME_CFG,
 459                            MT_BEACON_TIME_CFG_BEACON_TX |
 460                            MT_BEACON_TIME_CFG_TBTT_EN);
 461 
 462         mt76x02_irq_disable(dev, mask);
 463 
 464         /* perform device reset */
 465         mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
 466         mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
 467         mt76_clear(dev, MT_WPDMA_GLO_CFG,
 468                    MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN);
 469         usleep_range(5000, 10000);
 470         mt76_wr(dev, MT_INT_SOURCE_CSR, 0xffffffff);
 471 
 472         /* let fw reset DMA */
 473         mt76_set(dev, 0x734, 0x3);
 474 
 475         if (restart)
 476                 mt76_mcu_restart(dev);
 477 
 478         for (i = 0; i < ARRAY_SIZE(dev->mt76.q_tx); i++)
 479                 mt76_queue_tx_cleanup(dev, i, true);
 480 
 481         for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++)
 482                 mt76_queue_rx_reset(dev, i);
 483 
 484         mt76x02_mac_start(dev);
 485 
 486         if (dev->ed_monitor)
 487                 mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
 488 
 489         if (dev->mt76.beacon_mask && !restart)
 490                 mt76_set(dev, MT_BEACON_TIME_CFG,
 491                          MT_BEACON_TIME_CFG_BEACON_TX |
 492                          MT_BEACON_TIME_CFG_TBTT_EN);
 493 
 494         mt76x02_irq_enable(dev, mask);
 495 
 496         mutex_unlock(&dev->mt76.mutex);
 497 
 498         clear_bit(MT76_RESET, &dev->mt76.state);
 499 
 500         tasklet_enable(&dev->mt76.tx_tasklet);
 501         napi_enable(&dev->mt76.tx_napi);
 502         napi_schedule(&dev->mt76.tx_napi);
 503 
 504         tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
 505 
 506         for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) {
 507                 napi_enable(&dev->mt76.napi[i]);
 508                 napi_schedule(&dev->mt76.napi[i]);
 509         }
 510 
 511         if (restart) {
 512                 mt76x02_mcu_function_select(dev, Q_SELECT, 1);
 513                 ieee80211_restart_hw(dev->mt76.hw);
 514         } else {
 515                 ieee80211_wake_queues(dev->mt76.hw);
 516                 mt76_txq_schedule_all(&dev->mt76);
 517         }
 518 }
 519 
 520 static void mt76x02_check_tx_hang(struct mt76x02_dev *dev)
 521 {
 522         if (mt76x02_tx_hang(dev)) {
 523                 if (++dev->tx_hang_check >= MT_TX_HANG_TH)
 524                         goto restart;
 525         } else {
 526                 dev->tx_hang_check = 0;
 527         }
 528 
 529         if (dev->mcu_timeout)
 530                 goto restart;
 531 
 532         return;
 533 
 534 restart:
 535         mt76x02_watchdog_reset(dev);
 536 
 537         mutex_lock(&dev->mt76.mmio.mcu.mutex);
 538         dev->mcu_timeout = 0;
 539         mutex_unlock(&dev->mt76.mmio.mcu.mutex);
 540 
 541         dev->tx_hang_reset++;
 542         dev->tx_hang_check = 0;
 543         memset(dev->mt76.tx_dma_idx, 0xff,
 544                sizeof(dev->mt76.tx_dma_idx));
 545 }
 546 
 547 void mt76x02_wdt_work(struct work_struct *work)
 548 {
 549         struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
 550                                                wdt_work.work);
 551 
 552         mt76x02_check_tx_hang(dev);
 553 
 554         ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work,
 555                                      MT_WATCHDOG_TIME);
 556 }

/* [<][>][^][v][top][bottom][index][help] */