commit b04cebfdf1788804d0578f818ed102de04a5614c Author: Jiri Slaby Date: Tue Jul 24 13:02:23 2007 +0200 IBSS mode diff --git a/ath.c b/ath.c index 5a7fc36..686d850 100644 --- a/ath.c +++ b/ath.c @@ -63,8 +63,9 @@ DPRINTF(struct ath_softc *sc, unsigned int m, const char *fmt, ...) enum { ATH_DEBUG_RESET = 0x00000020, /* reset processing */ ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */ - ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */ + ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */ ATH_DEBUG_INTR = 0x00001000, /* ISR */ + ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */ ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */ ATH_DEBUG_LED = 0x00100000, /* led management */ ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */ @@ -158,6 +159,17 @@ static inline void ath_dump_skb(struct sk_buff *skb, const char *prefix) static inline void ath_dump_skb(struct sk_buff *skb, const char *prefix) {} #endif +static inline void ath_cleanup_txbuf(struct ath_softc *sc, struct ath_buf *bf) +{ + BUG_ON(!bf); + if (!bf->skb) + return; + pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(bf->skb); + bf->skb = NULL; +} + static void ath_tasklet_reset(unsigned long data) { struct ath_softc *sc = (void *)data; @@ -451,6 +463,245 @@ next: } /* + * Setup the beacon frame for transmit. + */ +static int ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf, + struct ieee80211_tx_control *ctl) +{ + struct sk_buff *skb = bf->skb; + struct ath_hw *ah = sc->ah; + struct ath_desc *ds; + int ret, antenna = 0; + u32 flags; + + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: skb %p [data %p len %u] " + "skbaddr %llx\n", __func__, skb, skb->data, skb->len, + (unsigned long long)bf->skbaddr); + if (pci_dma_mapping_error(bf->skbaddr)) { + printk(KERN_ERR "ath: beacon DMA mapping failed\n"); + return -EIO; + } + + ds = bf->desc; + + flags = AR5K_TXDESC_NOACK; + if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) { + ds->ds_link = bf->daddr; /* self-linked */ + flags |= AR5K_TXDESC_VEOL; + /* + * Let hardware handle antenna switching if txantenna is not set + */ + } else { + ds->ds_link = 0; + /* + * Switch antenna every 4 beacons if txantenna is not set + * XXX assumes two antenna + */ + if (antenna == 0) { + antenna = (sc->stats.ast_be_xmit & 4 ? 2 : 1); + } + } + + ds->ds_data = bf->skbaddr; + ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN, + ieee80211_get_hdrlen_from_skb(skb), + AR5K_PKT_TYPE_BEACON, 0xffff, ctl->tx_rate, 1, + AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); + if (ret) + goto err_unmap; + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + ret = ah->ah_fill_tx_desc(ah, ds, roundup(skb->len, 4), true, true); + if (ret) + goto err_unmap; + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; +} + +/* + * Transmit a beacon frame at SWBA. Dynamic updates to the + * frame contents are done as needed and the slot time is + * also adjusted based on current state. + * + * this is usually called from interrupt context (ath_intr()) + * but also from ath_beacon_config() in IBSS mode which in turn + * can be called from a tasklet and user context + */ +static void ath_beacon_send(struct ath_softc *sc) +{ + struct ath_buf *bf = sc->bbuf; + struct ath_hw *ah = sc->ah; + + DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s\n", __func__); + + if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA || + sc->opmode == IEEE80211_IF_TYPE_MNTR)) { + DPRINTF(sc, ATH_DEBUG_ANY, "%s: bf=%p bf_skb=%p\n", + __func__, bf, bf ? bf->skb : NULL); + return; + } + /* + * Check if the previous beacon has gone out. If + * not don't don't try to post another, skip this + * period and wait for the next. Missed beacons + * indicate a problem and should not occur. If we + * miss too many consecutive beacons reset the device. + */ + if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) { + sc->bmisscount++; + DPRINTF(sc, ATH_DEBUG_BEACON_PROC, + "%s: missed %u consecutive beacons\n", + __func__, sc->bmisscount); + if (sc->bmisscount > 3) { /* NB: 3 is a guess */ + DPRINTF(sc, ATH_DEBUG_BEACON_PROC, + "%s: stuck beacon time (%u missed)\n", + __func__, sc->bmisscount); + tasklet_schedule(&sc->restq); + } + return; + } + if (unlikely(sc->bmisscount != 0)) { + DPRINTF(sc, ATH_DEBUG_BEACON_PROC, + "%s: resume beacon xmit after %u misses\n", + __func__, sc->bmisscount); + sc->bmisscount = 0; + } + + /* + * Stop any current dma and put the new frame on the queue. + * This should never fail since we check above that no frames + * are still pending on the queue. + */ + if (unlikely(!ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { + DPRINTF(sc, ATH_DEBUG_ANY, "%s: beacon queue %u didn't stop?\n", + __func__, sc->bhalq); + /* NB: the HAL still stops DMA, so proceed */ + } + pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len, + PCI_DMA_TODEVICE); + + ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); + ath5k_hw_tx_start(ah, sc->bhalq); + DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: TXDP[%u] = %llx (%p)\n", + __func__, sc->bhalq, (unsigned long long)bf->daddr, bf->desc); + + sc->stats.ast_be_xmit++; +} + +static int ath_beaconq_config(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->ah; + struct ath5k_txq_info qi; + int ret; + + ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) + return ret; + if (sc->opmode == IEEE80211_IF_TYPE_AP || + sc->opmode == IEEE80211_IF_TYPE_IBSS) { + /* + * Always burst out beacon and CAB traffic. + */ + qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; + qi.tqi_cw_min = ATH_BEACON_CWMIN_DEFAULT; + qi.tqi_cw_max = ATH_BEACON_CWMAX_DEFAULT; + } + + ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) { + printk(KERN_ERR "%s: unable to update parameters for beacon " + "hardware queue!\n", __func__); + return ret; + } + + return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; +} + +/* + * Configure the beacon and sleep timers. + * + * When operating as an AP this resets the TSF and sets + * up the hardware to notify us when we need to issue beacons. + * + * When operating in station mode this sets up the beacon + * timers according to the timestamp of the last received + * beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware + * will wakeup in time to receive beacons, and configures + * the beacon miss handling so we'll receive a BMISS + * interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +static void ath_beacon_config(struct ath_softc *sc) +{ +#define TSF_TO_TU(_h,_l) (((_h) << 22) | ((_l) >> 10)) + struct ath_hw *ah = sc->ah; + u32 uninitialized_var(nexttbtt), intval, tsftu; + u64 tsf; + + intval = sc->bintval & AR5K_BEACON_PERIOD; + if (WARN_ON(!intval)) + return; + + /* current TSF converted to TU */ + tsf = ath5k_hw_get_tsf64(ah); + tsftu = TSF_TO_TU((u32)(tsf >> 32), (u32)tsf); + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: intval %u hw tsftu %u\n", __func__, + intval, tsftu); + + if (sc->opmode == IEEE80211_IF_TYPE_STA) { + ath5k_hw_set_intr(ah, 0); + sc->imask |= AR5K_INT_BMISS; + sc->bmisscount = 0; + ath5k_hw_set_intr(ah, sc->imask); + } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS /* TODO || AP */) { + ath5k_hw_set_intr(ah, 0); + if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + /* + * Pull nexttbtt forward to reflect the current + * TSF. Add one intval otherwise the timespan + * can be too short for ibss merges. + */ + nexttbtt = tsftu + 2 * intval; + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u " + "intval %u\n", __func__, nexttbtt, intval); + + /* + * In IBSS mode enable the beacon timers but only + * enable SWBA interrupts if we need to manually + * prepare beacon frames. Otherwise we use a + * self-linked tx descriptor and let the hardware + * deal with things. + */ + if (!ath5k_hw_hasveol(ah)) + sc->imask |= AR5K_INT_SWBA; + } /* TODO else AP */ + + intval |= AR5K_BEACON_ENA; + + ath_beaconq_config(sc); + ath5k_hw_init_beacon(ah, nexttbtt, intval); + + sc->bmisscount = 0; + ath5k_hw_set_intr(ah, sc->imask); + /* + * When using a self-linked beacon descriptor in + * ibss mode load it once here. + */ + if (sc->opmode == IEEE80211_IF_TYPE_IBSS && + ath5k_hw_hasveol(ah)) + ath_beacon_send(sc); + } +#undef TSF_TO_TU +} + +/* * Calculate the receive filter according to the * operating mode and state: * @@ -660,10 +911,7 @@ static void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) ath_printtxbuf(bf, !sc->ah->ah_proc_tx_desc(sc->ah, bf->desc)); #endif - pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(bf->skb); - bf->skb = NULL; + ath_cleanup_txbuf(sc, bf); spin_lock_bh(&sc->txbuflock); sc->tx_stats.data[txq->qnum].len--; @@ -685,12 +933,10 @@ static void ath_draintxq(struct ath_softc *sc) /* XXX return value */ if (likely(!sc->invalid)) { -#ifdef BEACON /* don't touch the hardware if marked invalid */ (void)ath5k_hw_stop_tx_dma(ah, sc->bhalq); DPRINTF(sc, ATH_DEBUG_RESET, "%s: beacon queue %x\n", __func__, ath5k_hw_get_tx_buf(ah, sc->bhalq)); -#endif for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) { ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); @@ -788,6 +1034,7 @@ static int ath_stop_hw(struct ath_softc *sc) ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); } } + ath_cleanup_txbuf(sc, sc->bbuf); mutex_unlock(&sc->lock); del_timer_sync(&sc->calib_tim); @@ -1059,7 +1306,8 @@ static int ath_reset(struct ieee80211_hw *hw) * might change as a result. */ // ath_chan_change(sc, c); - ath5k_hw_set_intr(ah, sc->imask); + ath_beacon_config(sc); + /* intrs are started by ath_beacon_config */ ieee80211_wake_queues(hw); @@ -1078,15 +1326,81 @@ static int ath_stop(struct ieee80211_hw *hw) return ath_stop_hw(hw->priv); } +static int ath_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath_softc *sc = hw->priv; + int ret; + + mutex_lock(&sc->lock); + if (sc->iface_id) { + ret = 0; + goto end; + } + + sc->iface_id = conf->if_id; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sc->opmode = conf->type; + break; + default: + ret = -EOPNOTSUPP; + goto end; + } + ret = 0; +end: + mutex_unlock(&sc->lock); + return ret; +} + +static void ath_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->lock); + if (sc->iface_id != conf->if_id) { + goto end; + } + + sc->iface_id = 0; +end: + mutex_unlock(&sc->lock); +} + static int ath_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct ath_softc *sc = hw->priv; + sc->bintval = conf->beacon_int * 1000 / 1024; ath_setcurmode(sc, conf->phymode); return ath_chan_set(sc, conf->chan); } +static int ath_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct ath_softc *sc = hw->priv; + int ret; + + mutex_lock(&sc->lock); + if (sc->iface_id != if_id) { + ret = -EIO; + goto unlock; + } + if (conf->bssid) + ath5k_hw_set_associd(sc->ah, conf->bssid, 0 /* FIXME: aid */); + mutex_unlock(&sc->lock); + + return ath_reset(hw); +unlock: + mutex_unlock(&sc->lock); + return ret; +} + static void ath_set_multicast_list(struct ieee80211_hw *hw, unsigned short flags, int mc_count) { @@ -1183,15 +1497,41 @@ static void ath_reset_tsf(struct ieee80211_hw *hw) ath5k_hw_reset_tsf(sc->ah); } +static int ath_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct ath_softc *sc = hw->priv; + int ret; + + ath_dump_skb(skb, "b"); + + mutex_lock(&sc->lock); + + if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { + ret = -EIO; + goto end; + } + + ath_cleanup_txbuf(sc, sc->bbuf); + sc->bbuf->skb = skb; + ret = ath_beacon_setup(sc, sc->bbuf, ctl); + if (ret) + sc->bbuf->skb = NULL; + +end: + mutex_unlock(&sc->lock); + return ret; +} + static struct ieee80211_ops ath_hw_ops = { .tx = ath_tx, .reset = ath_reset, .open = ath_open, .stop = ath_stop, - .add_interface = NULL, - .remove_interface = NULL, + .add_interface = ath_add_interface, + .remove_interface = ath_remove_interface, .config = ath_config, - .config_interface = NULL, + .config_interface = ath_config_interface, .set_multicast_list = ath_set_multicast_list, .set_key = ath_set_key, .get_stats = ath_get_stats, @@ -1199,7 +1539,7 @@ static struct ieee80211_ops ath_hw_ops = { .get_tx_stats = ath_get_tx_stats, .get_tsf = ath_get_tsf, .reset_tsf = ath_reset_tsf, - .beacon_update = NULL, + .beacon_update = ath_beacon_update, }; /* @@ -1280,7 +1620,7 @@ static void ath_led_event(struct ath_softc *sc, int event) } } -static irqreturn_t ath_intr(int irq, void *dev_id) +static irqreturn_t ath_intr(int irq, void *dev_id) { struct ath_softc *sc = dev_id; struct ath_hw *ah = sc->ah; @@ -1289,7 +1629,7 @@ static irqreturn_t ath_intr(int irq, void *dev_id) if (unlikely(sc->invalid || !ath5k_hw_is_intr_pending(ah))) return IRQ_NONE; - + do { /* * Figure out the reason(s) for the interrupt. Note @@ -1321,7 +1661,7 @@ static irqreturn_t ath_intr(int irq, void *dev_id) * this is too slow to meet timing constraints * under load. */ -// ath_beacon_send(dev); + ath_beacon_send(sc); } if (status & AR5K_INT_RXEOL) { /* @@ -1341,10 +1681,10 @@ static irqreturn_t ath_intr(int irq, void *dev_id) tasklet_schedule(&sc->rxtq); if (status & AR5K_INT_TX) tasklet_schedule(&sc->txtq); -/* if (status & AR5K_INT_BMISS) { + if (status & AR5K_INT_BMISS) { sc->stats.ast_bmiss++; - tasklet_schedule(&sc->bmisstq); - }*/ +/* tasklet_schedule(&sc->bmisstq);*/ + } if (status & AR5K_INT_MIB) { sc->stats.ast_mib++; /* TODO */ @@ -1355,7 +1695,7 @@ static irqreturn_t ath_intr(int irq, void *dev_id) if (unlikely(!counter && net_ratelimit())) printk(KERN_WARNING "ath: too many interrupts, giving up for " "now\n"); - + return IRQ_HANDLED; } @@ -1582,11 +1922,7 @@ static int ath_desc_alloc(struct ath_softc *sc, struct pci_dev *pdev) DPRINTF(sc, ATH_DEBUG_ANY, "%s: DMA map: %p (%zu) -> %llx\n", __func__, ds, sc->desc_len, (unsigned long long)sc->desc_daddr); - bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF -#ifdef BEACON - + ATH_BCBUF -#endif - , + bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, sizeof(struct ath_buf), GFP_KERNEL); if (bf == NULL) { dev_err(&pdev->dev, "can't allocate bufptr\n"); @@ -1610,14 +1946,11 @@ static int ath_desc_alloc(struct ath_softc *sc, struct pci_dev *pdev) bf->daddr = da; list_add_tail(&bf->list, &sc->txbuf); } -#ifdef BEACON - INIT_LIST_HEAD(&sc->bbuf); - for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) { - bf->desc = ds; - bf->daddr = da; - list_add_tail(&bf->list, &sc->bbuf); - } -#endif + + /* beacon buffer */ + bf->desc = ds; + bf->daddr = da; + sc->bbuf = bf; return 0; err_free: @@ -1627,26 +1960,15 @@ err: return ret; } -static void ath_descdma_cleanup(struct ath_softc *sc, struct pci_dev *pdev, - struct list_head *head) +static void ath_desc_free(struct ath_softc *sc, struct pci_dev *pdev) { struct ath_buf *bf; - list_for_each_entry(bf, head, list) { - if (bf->skb) { - pci_unmap_single(pdev, bf->skbaddr, sc->rxbufsize, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(bf->skb); - bf->skb = NULL; - } - } -} - -static void ath_desc_free(struct ath_softc *sc, struct pci_dev *pdev) -{ -// ath_descdma_cleanup(sc, pdev, &sc->bbuf); - ath_descdma_cleanup(sc, pdev, &sc->txbuf); - ath_descdma_cleanup(sc, pdev, &sc->rxbuf); + ath_cleanup_txbuf(sc, sc->bbuf); + list_for_each_entry(bf, &sc->txbuf, list) + ath_cleanup_txbuf(sc, bf); + list_for_each_entry(bf, &sc->rxbuf, list) + ath_cleanup_txbuf(sc, bf); /* Free memory associated with all descriptors */ pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); @@ -1654,34 +1976,33 @@ static void ath_desc_free(struct ath_softc *sc, struct pci_dev *pdev) kfree(sc->bufptr); sc->bufptr = NULL; } -#ifdef BEACON + static int ath_beaconq_setup(struct ath_hw *ah) { - struct ath5k_txq_info qi; - - memset(&qi, 0, sizeof(qi)); - qi.tqi_aifs = AR5K_TXQ_USEDEFAULT; - qi.tqi_cw_min = AR5K_TXQ_USEDEFAULT; - qi.tqi_cw_max = AR5K_TXQ_USEDEFAULT; - /* NB: for dynamic turbo, don't enable any other interrupts */ - qi.tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE; + struct ath5k_txq_info qi = { + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT, + /* NB: for dynamic turbo, don't enable any other interrupts */ + .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE + }; return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); } -#endif + static struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { struct ath_hw *ah = sc->ah; struct ath_txq *txq; - struct ath5k_txq_info qi; + struct ath5k_txq_info qi = { + .tqi_subtype = subtype, + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT + }; int qnum; - memset(&qi, 0, sizeof(qi)); - qi.tqi_subtype = subtype; - qi.tqi_aifs = AR5K_TXQ_USEDEFAULT; - qi.tqi_cw_min = AR5K_TXQ_USEDEFAULT; - qi.tqi_cw_max = AR5K_TXQ_USEDEFAULT; /* * Enable interrupts only for EOL and DESC conditions. * We mark tx descriptors to receive a DESC interrupt @@ -1786,7 +2107,6 @@ static int ath_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err; } -#ifdef BEACON /* * Allocate hardware transmit queues: one queue for * beacon frames and one data queue for each QoS @@ -1800,19 +2120,11 @@ static int ath_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) } sc->bhalq = ret; - sc->cabq = ath_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); - if (IS_ERR(sc->cabq)) { - dev_err(&pdev->dev, "can't setup CAB xmit queue\n"); - ret = PTR_ERR(sc->cabq); - sc->cabq = NULL; - goto err_queues; - } -#endif sc->txq = ath_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); if (IS_ERR(sc->txq)) { dev_err(&pdev->dev, "can't setup xmit queue\n"); ret = PTR_ERR(sc->txq); - goto err_queues; + goto err_bhal; } tasklet_init(&sc->rxtq, ath_tasklet_rx, (unsigned long)sc); @@ -1842,13 +2154,6 @@ static int ath_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) ath5k_hw_set_gpio_output(ah, sc->led_pin); ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); } -#ifdef BEACON - /* - * Not all chips have the VEOL support we want to - * use with IBSS beacons; check here for it. - */ - sc->sc_hasveol = ath_hal_hasveol(ah); -#endif ath5k_hw_get_lladdr(ah, mac); SET_IEEE80211_PERM_ADDR(hw, mac); @@ -1866,6 +2171,9 @@ static int ath_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) return 0; err_queues: ath_tx_cleanup(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: ath_desc_free(sc, pdev); err: return ret; @@ -1890,6 +2198,7 @@ static void ath_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) ieee80211_unregister_hw(hw); ath_desc_free(sc, pdev); ath_tx_cleanup(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); /* * NB: can't reclaim these until after ieee80211_ifdetach diff --git a/ath.h b/ath.h index 613db78..c61119c 100644 --- a/ath.h +++ b/ath.h @@ -155,6 +155,8 @@ struct ath_softc { unsigned int curmode; /* current phy mode */ struct ieee80211_channel *curchan; /* current h/w channel */ + int iface_id; /* add/remove_interface id */ + struct { u8 rxflags; /* radiotap rx flags */ u8 txflags; /* radiotap tx flags */ @@ -202,16 +204,15 @@ struct ath_softc { struct ath_txq *txq; /* beacon and tx*/ struct tasklet_struct txtq; /* tx intr tasklet */ + struct ath_buf *bbuf; /* beacon buffer */ + unsigned int bhalq, /* HAL q for outgoing beacons */ + bmisscount, /* missed beacon transmits */ + bintval; /* beacon interval */ #ifdef BEACON - struct list_head bbuf; /* beacon buffers */ - unsigned int bhalq; /* HAL q for outgoing beacons */ - u_int sc_bmisscount; /* missed beacon transmits */ u32 sc_ant_tx[8]; /* recent tx frames/antenna */ - struct ieee80211_beacon_offsets boff; /* dynamic update state */ struct ath_txq *cabq; /* tx q for cab frames */ struct tasklet_struct bmisstq; /* bmiss intr tasklet */ - struct tasklet_struct sc_bstuckq; /* stuck beacon processing */ #endif #ifdef UNUSED struct ctl_table_header *sc_sysctl_header; diff --git a/ath/if_ath.c b/ath/if_ath.c index 661f571..acc4e2b 100644 --- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -1,7 +1,3 @@ -/* unaligned little endian access */ -#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) -#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) - static int ath_dwelltime = 200; /* 5 channels/second */ static int ath_calinterval = 30; /* calibrate every 30 secs */ static int ath_countrycode = CTRY_DEFAULT; /* country code */ @@ -650,547 +646,6 @@ ath_updateslot(struct net_device *dev) else ath_setslottime(sc); } -/* - * Setup the transmit queue parameters for the beacon queue. - */ -static int -ath_beaconq_config(struct ath_softc *sc) -{ -#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1) -// struct ieee80211com *ic = &sc->sc_ic; - struct ath_hal *ah = sc->sc_ah; - struct ath5k_txq_info qi; - - ath5k_hw_get_tx_queueprops(ah, sc->sc_bhalq, &qi); - if (sc->sc_opmode == IEEE80211_IF_TYPE_AP) { - /* - * Always burst out beacon and CAB traffic. - */ - qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT; - qi.tqi_cw_min = ATH_BEACON_CWMIN_DEFAULT; - qi.tqi_cw_max = ATH_BEACON_CWMAX_DEFAULT; - } else { - struct wmeParams *wmep = - &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE]; - /* - * Adhoc mode; important thing is to use 2x cwmin. - */ - qi.tqi_aifs = wmep->wmep_aifsn; - qi.tqi_cw_min = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); - qi.tqi_cw_max = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); - } - - if (!ath5k_hw_setup_tx_queueprops(ah, sc->sc_bhalq, &qi)) { - printk("%s: unable to update parameters for " - "beacon hardware queue! (%s)\n", __func__, sc->sc_dev.name); - return 0; - } else { - ath5k_hw_reset_tx_queue(ah, sc->sc_bhalq); /* push to h/w */ - return 1; - } -#undef ATH_EXPONENT_TO_VALUE -} - -/* - * Allocate and setup an initial beacon frame. - */ -static int -ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ath_buf *bf; - struct sk_buff *skb; - - bf = STAILQ_FIRST(&sc->sc_bbuf); - if (bf == NULL) { - DPRINTF(sc, ATH_DEBUG_BEACON, "%s: no dma buffers\n", __func__); - sc->sc_stats.ast_be_nobuf++; /* XXX */ - return ENOMEM; /* XXX */ - } - /* - * NB: the beacon data buffer must be 32-bit aligned; - * we assume the mbuf routines will return us something - * with this alignment (perhaps should assert). - */ - skb = ieee80211_beacon_alloc(ic, ni, &sc->sc_boff); - if (skb == NULL) { - DPRINTF(sc, ATH_DEBUG_BEACON, "%s: cannot get sk_buff\n", - __func__); - sc->sc_stats.ast_be_nobuf++; - return ENOMEM; - } - - if (bf->bf_skb != NULL) { - bus_unmap_single(sc->sc_bdev, - bf->bf_skbaddr, bf->bf_skb->len, BUS_DMA_TODEVICE); - dev_kfree_skb(bf->bf_skb); - bf->bf_skb = NULL; - bf->bf_node = NULL; - } - bf->bf_skb = skb; - bf->bf_node = ieee80211_ref_node(ni); - - return 0; // TODO: return value -} - -/* - * Setup the beacon frame for transmit. - */ -static void -ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf, - struct ieee80211_tx_control *ctl) -{ -#define USE_SHPREAMBLE(_ic) \ - (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\ - == IEEE80211_F_SHPREAMBLE) - struct sk_buff *skb = bf->bf_skb; - struct ath_hal *ah = sc->sc_ah; - struct ath_desc *ds; - int antenna = sc->sc_txantenna; - int flags; - u_int8_t rate; - - bf->bf_skbaddr = bus_map_single(sc->sc_bdev, - skb->data, skb->len, BUS_DMA_TODEVICE); - DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: skb %p [data %p len %u] skbaddr %llx\n", - __func__, skb, skb->data, skb->len, - (unsigned long long)bf->bf_skbaddr); - if (BUS_DMA_MAP_ERROR(bf->bf_skbaddr)) { - printk(KERN_ERR "%s: DMA mapping failed\n", __func__); - return; - } - - /* setup descriptors */ - ds = bf->bf_desc; - - flags = AR5K_TXDESC_NOACK; - if (sc->sc_opmode == IEEE80211_IF_TYPE_IBSS && sc->sc_hasveol) { - ds->ds_link = bf->bf_daddr; /* self-linked */ - flags |= AR5K_TXDESC_VEOL; - /* - * Let hardware handle antenna switching if txantenna is not set - */ - } else { - ds->ds_link = 0; - /* - * Switch antenna every 4 beacons if txantenna is not set - * XXX assumes two antenna - */ - if (antenna == 0) { - antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1); - } - } - - ds->ds_data = bf->bf_skbaddr; - /* - * Calculate rate code. - * XXX everything at min xmit rate - */ - if (USE_SHPREAMBLE(ic)) - rate = an->an_tx_mgtratesp; - else - rate = an->an_tx_mgtrate; - rate = 0; - ah->ah_setup_tx_desc(ah, ds - , skb->len + FCS_LEN /* frame length */ - , ieee80211_get_hdrlen_from_skb(skb) /* header length */ - , AR5K_PKT_TYPE_BEACON /* Atheros packet type */ - , min((u8)60u, ctl->power_level) /* txpower XXX */ - , rate, 1 /* series 0 rate/tries */ - , AR5K_TXKEYIX_INVALID /* no encryption */ - , antenna /* antenna mode */ - , flags /* no ack, veol for beacons */ - , 0 /* rts/cts rate */ - , 0 /* rts/cts duration */ - ); - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ah->ah_fill_tx_desc(ah, ds - , roundup(skb->len, 4) /* buffer length */ - , true /* first segment */ - , true /* last segment */ - , ds /* first descriptor */ - ); -#undef USE_SHPREAMBLE -} - -/* - * Transmit a beacon frame at SWBA. Dynamic updates to the - * frame contents are done as needed and the slot time is - * also adjusted based on current state. - * - * this is usually called from interrupt context (ath_intr()) - * but also from ath_beacon_config() in IBSS mode which in turn - * can be called from a tasklet and user context - */ -static void -ath_beacon_send(struct net_device *dev) -{ - struct ieee80211_tx_control ctl; - struct ath_softc *sc = dev->priv; - struct ath_buf *bf = NULL;//STAILQ_FIRST(&sc->sc_bbuf); - struct ath_hal *ah = sc->sc_ah; - struct sk_buff *skb; - int ncabq, otherant; - - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s\n", __func__); - - if (sc->sc_opmode == IEEE80211_IF_TYPE_STA || - sc->sc_opmode == IEEE80211_IF_TYPE_MNTR || - bf == NULL || bf->bf_skb == NULL) { - DPRINTF(sc, ATH_DEBUG_ANY, "%s: bf=%p bf_skb=%p\n", - __func__, bf, bf ? bf->bf_skb : NULL); - return; - } - /* - * Check if the previous beacon has gone out. If - * not don't don't try to post another, skip this - * period and wait for the next. Missed beacons - * indicate a problem and should not occur. If we - * miss too many consecutive beacons reset the device. - */ - if (ath5k_hw_num_tx_pending(ah, sc->sc_bhalq) != 0) { - sc->sc_bmisscount++; - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); - if (sc->sc_bmisscount > 3) { /* NB: 3 is a guess */ - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, - "%s: stuck beacon time (%u missed)\n", - __func__, sc->sc_bmisscount); - tasklet_schedule(&sc->sc_bstuckq); - } - return; - } - if (sc->sc_bmisscount != 0) { - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); - sc->sc_bmisscount = 0; - } - - /* - * Update dynamic beacon contents. If this returns - * non-zero then we need to remap the memory because - * the beacon frame changed size (probably because - * of the TIM bitmap). - */ - skb = bf->bf_skb; - ncabq = sc->sc_cabq->axq_depth; - if (ieee80211_beacon_update(ic, bf->bf_node, &sc->sc_boff, skb, ncabq)) { - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, - "%s: update, beacon len changed %d to %d\n", - __func__, bf->bf_skb->len, skb->len); - - /* XXX too conservative? */ - bus_unmap_single(sc->sc_bdev, - bf->bf_skbaddr, bf->bf_skb->len, BUS_DMA_TODEVICE); - - bf->bf_skbaddr = bus_map_single(sc->sc_bdev, - skb->data, skb->len, BUS_DMA_TODEVICE); - if (BUS_DMA_MAP_ERROR(bf->bf_skbaddr)) { - if_printf(dev, "%s: DMA mapping failed\n", __func__); - return; - } - } - - /* - * Handle slot time change when a non-ERP station joins/leaves - * an 11g network. The 802.11 layer notifies us via callback, - * we mark updateslot, then wait one beacon before effecting - * the change. This gives associated stations at least one - * beacon interval to note the state change. - */ - /* XXX locking */ - if (sc->sc_updateslot == UPDATE) - sc->sc_updateslot = COMMIT; /* commit next beacon */ - else if (sc->sc_updateslot == COMMIT) - ath_setslottime(sc); /* commit change to h/w */ - - /* - * Check recent per-antenna transmit statistics and flip - * the default antenna if noticeably more frames went out - * on the non-default antenna. - * XXX assumes 2 anntenae - */ - otherant = sc->sc_defant & 1 ? 2 : 1; - if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2) - ath_setdefantenna(sc, otherant); - sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0; - - /* - * Construct tx descriptor. - */ - ath_beacon_setup(sc, bf, &ctl); - - /* - * Stop any current dma and put the new frame on the queue. - * This should never fail since we check above that no frames - * are still pending on the queue. - */ - if (!ath5k_hw_stop_tx_dma(ah, sc->sc_bhalq)) { - DPRINTF(sc, ATH_DEBUG_ANY, - "%s: beacon queue %u did not stop?\n", - __func__, sc->sc_bhalq); - /* NB: the HAL still stops DMA, so proceed */ - } - bus_dma_sync_single(sc->sc_bdev, - bf->bf_skbaddr, bf->bf_skb->len, BUS_DMA_TODEVICE); - - /* - * Enable the CAB queue before the beacon queue to - * insure CAB frames are triggered by this beacon. - * The CAB queue holds multicast traffic for stations in - * power-save mode. - * - * NB: only at DTIM - */ - if (sc->sc_opmode == IEEE80211_IF_TYPE_AP && - ncabq > 0 && sc->sc_boff.bo_tim[4] & 1) - ath5k_hw_tx_start(ah, sc->sc_cabq->axq_qnum); - - ath5k_hw_put_tx_buf(ah, sc->sc_bhalq, bf->bf_daddr); - ath5k_hw_tx_start(ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DEBUG_BEACON_PROC, - "%s: TXDP[%u] = %llx (%p)\n", __func__, - sc->sc_bhalq, (unsigned long long)bf->bf_daddr, bf->bf_desc); - - sc->sc_stats.ast_be_xmit++; -} - -/* - * Reset the hardware after detecting beacons have stopped. - */ -static void -ath_bstuck_tasklet(unsigned long data) -{ - struct ieee80211_hw *hw = (void *)data; - struct ath_softc *sc = hw->priv; - - printk(KERN_WARNING "stuck beacon; resetting (bmiss count %u)\n", - sc->sc_bmisscount); - ath_reset(hw); -} - -/* - * Reclaim beacon resources. - */ -static void -ath_beacon_free(struct ath_softc *sc) -{ - struct ath_buf *bf; - - bf = NULL; - STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { - if (bf->bf_skb != NULL) { - bus_unmap_single(sc->sc_bdev, bf->bf_skbaddr, - bf->bf_skb->len, BUS_DMA_TODEVICE); - dev_kfree_skb(bf->bf_skb); - bf->bf_skb = NULL; - } - - if (bf->bf_node != NULL) { - ieee80211_free_node(bf->bf_node); - bf->bf_node = NULL; - } - } -} - -/* - * Configure the beacon and sleep timers. - * - * When operating as an AP this resets the TSF and sets - * up the hardware to notify us when we need to issue beacons. - * - * When operating in station mode this sets up the beacon - * timers according to the timestamp of the last received - * beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware - * will wakeup in time to receive beacons, and configures - * the beacon miss handling so we'll receive a BMISS - * interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void -ath_beacon_config(struct ath_softc *sc) -{ -#define TSF_TO_TU(_h,_l) (((_h) << 22) | ((_l) >> 10)) - struct ath_hal *ah = sc->sc_ah; - u_int32_t nexttbtt, intval; - u_int64_t tsf; - u_int32_t tsftu; - - /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), - LE_READ_4(ni->ni_tstamp.data)); - /* NB: the beacon interval is kept internally in TU's */ - intval = ni->ni_intval & AR5K_BEACON_PERIOD; - /* current TSF converted to TU */ - tsf = ath5k_hw_get_tsf64(ah); - tsftu = TSF_TO_TU((u_int32_t)(tsf>>32), (u_int32_t)tsf); - - DPRINTF(sc, ATH_DEBUG_BEACON, "%s: last beacon %u intval %u (%u) hw tsftu %u\n", - __func__, nexttbtt, intval, ni->ni_intval, tsftu); - - if (ic->ic_opmode == IEEE80211_M_STA) { - AR5K_BEACON_STATE bs; - int dtimperiod, dtimcount; - int cfpperiod, cfpcount; - - /* - * Setup dtim and cfp parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = ni->ni_dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = ni->ni_dtim_count; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; /* XXX? */ - cfpperiod = 1; /* NB: no PCF support yet */ - cfpcount = 0; -#define FUDGE 2 - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim+cfp state for the result. - */ - do { - nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; - } - } while (nexttbtt < tsftu + FUDGE); -#undef FUDGE - memset(&bs, 0, sizeof(bs)); - bs.bs_interval = intval; - bs.bs_next_beacon = nexttbtt; - bs.bs_dtim_period = dtimperiod*intval; - bs.bs_next_dtim = bs.bs_next_beacon + dtimcount*intval; - bs.bs_cfp_period = cfpperiod*bs.bs_dtim_period; - bs.bs_cfp_next = bs.bs_next_dtim + cfpcount*bs.bs_dtim_period; - bs.bs_cfp_max_duration = 0; -#if 0 - /* - * The 802.11 layer records the offset to the DTIM - * bitmap while receiving beacons; use it here to - * enable h/w detection of our AID being marked in - * the bitmap vector (to indicate frames for us are - * pending at the AP). - * XXX do DTIM handling in s/w to WAR old h/w bugs - * XXX enable based on h/w rev for newer chips - */ - bs.bs_tim_offset = ni->ni_timoff; -#endif - /* - * Calculate the number of consecutive beacons to miss - * before taking a BMISS interrupt. The configuration - * is specified in ms, so we need to convert that to - * TU's and then calculate based on the beacon interval. - * Note that we clamp the result to at most 10 beacons. - */ - bs.bs_bmiss_threshold = howmany(ic->ic_bmisstimeout, intval); - if (bs.bs_bmiss_threshold > 10) - bs.bs_bmiss_threshold = 10; - else if (bs.bs_bmiss_threshold <= 0) - bs.bs_bmiss_threshold = 1; - - /* - * Calculate sleep duration. The configuration is - * given in ms. We insure a multiple of the beacon - * period is used. Also, if the sleep duration is - * greater than the DTIM period then it makes senses - * to make it a multiple of that. - * - * XXX fixed at 100ms - */ - bs.bs_sleep_duration = - roundup(IEEE80211_MS_TO_TU(100), bs.bs_interval); - if (bs.bs_sleep_duration > bs.bs_dtim_period) - bs.bs_sleep_duration = roundup(bs.bs_sleep_duration, bs.bs_dtim_period); - - DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: tsf %llx tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n" - , __func__ - , tsf, tsftu - , bs.bs_interval - , bs.bs_next_beacon - , bs.bs_dtim_period - , bs.bs_next_dtim - , bs.bs_bmiss_threshold - , bs.bs_sleep_duration - , bs.bs_cfp_period - , bs.bs_cfp_max_duration - , bs.bs_cfp_next - , bs.bs_tim_offset - ); - ath5k_hw_set_intr(ah, 0); - ath5k_hw_set_beacon_timers(ah, &bs); - sc->sc_imask |= AR5K_INT_BMISS; - sc->sc_bmisscount = 0; - ath5k_hw_set_intr(ah, sc->sc_imask); - } else { /* IBSS or HOSTAP */ - ath5k_hw_set_intr(ah, 0); - - if (ic->ic_opmode == IEEE80211_M_IBSS) { - /* - * Pull nexttbtt forward to reflect the current - * TSF. Add one intval otherwise the timespan - * can be too short for ibss merges. - */ - do { - nexttbtt += intval; - } while (nexttbtt < tsftu+intval); - nexttbtt += intval; - - DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u\n", - __func__, nexttbtt, intval & AR5K_BEACON_PERIOD ); - - /* - * In IBSS mode enable the beacon timers but only - * enable SWBA interrupts if we need to manually - * prepare beacon frames. Otherwise we use a - * self-linked tx descriptor and let the hardware - * deal with things. - */ - if (!sc->sc_hasveol) - sc->sc_imask |= AR5K_INT_SWBA; - - } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) { - if (nexttbtt == 0) { - /* - * starting a new BSS: we can reset the TSF - * and start with zero - */ - nexttbtt = intval; - intval |= AR5K_BEACON_RESET_TSF; - } else { - nexttbtt += intval; - } - /* - * In AP mode we enable the beacon timers and - * SWBA interrupts to prepare beacon frames. - */ - sc->sc_imask |= AR5K_INT_SWBA; /* beacon prepare */ - } - - intval |= AR5K_BEACON_ENA; - - ath_beaconq_config(sc); - ath5k_hw_init_beacon(ah, nexttbtt, intval); - - sc->sc_bmisscount = 0; - ath5k_hw_set_intr(ah, sc->sc_imask); - /* - * When using a self-linked beacon descriptor in - * ibss mode load it once here. - */ - if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) - ath_beacon_send(&sc->sc_dev); - } -#undef TSF_TO_TU -} /* * Set the default antenna. diff --git a/ath5k.h b/ath5k.h index cbab742..a62ecc5 100644 --- a/ath5k.h +++ b/ath5k.h @@ -1017,9 +1017,9 @@ int ath5k_hw_set_key_lladdr(struct ath_hw *hal, u16 entry, const u8 *mac); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_setup_tx_queue(struct ath_hw *hal, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); int ath5k_hw_setup_tx_queueprops(struct ath_hw *hal, int queue, const struct ath5k_txq_info *queue_info); -bool ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, struct ath5k_txq_info *queue_info); +int ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, struct ath5k_txq_info *queue_info); void ath5k_hw_release_tx_queue(struct ath_hw *hal, unsigned int queue); -bool ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue); +int ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue); u32 ath5k_hw_num_tx_pending(struct ath_hw *hal, unsigned int queue); bool ath5k_hw_set_slot_time(struct ath_hw *hal, unsigned int slot_time); unsigned int ath5k_hw_get_slot_time(struct ath_hw *hal); diff --git a/ath5k_hw.c b/ath5k_hw.c index 0dae6a4..501d85c 100644 --- a/ath5k_hw.c +++ b/ath5k_hw.c @@ -1200,9 +1200,10 @@ int ath5k_hw_reset(struct ath_hw *hal, enum ieee80211_if_types op_mode, if (hal->ah_version != AR5K_AR5210) AR5K_REG_WRITE_Q(hal, AR5K_QUEUE_QCUMASK(i), i); - if (ath5k_hw_reset_tx_queue(hal, i) == false) { + ret = ath5k_hw_reset_tx_queue(hal, i); + if (ret) { AR5K_PRINTF("failed to reset TX queue #%d\n", i); - return -EINVAL; + return ret; } } @@ -2560,8 +2561,7 @@ ath5k_hw_set_lladdr(struct ath_hw *hal, const u8 *mac) * Set BSSID */ void -ath5k_hw_set_associd(struct ath_hw *hal, const u8 *bssid, - u16 assoc_id) +ath5k_hw_set_associd(struct ath_hw *hal, const u8 *bssid, u16 assoc_id) { u32 low_id, high_id; u16 tim_offset = 0; @@ -2797,9 +2797,7 @@ void ath5k_hw_reset_tsf(struct ath_hw *hal) /* * Initialize beacon timers */ -void -ath5k_hw_init_beacon(struct ath_hw *hal, u32 next_beacon, - u32 interval) +void ath5k_hw_init_beacon(struct ath_hw *hal, u32 next_beacon, u32 interval) { u32 timer1, timer2, timer3; @@ -3331,12 +3329,12 @@ int ath5k_hw_setup_tx_queueprops(struct ath_hw *hal, int queue, /* * Get properties for a specific transmit queue */ -bool -ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, struct ath5k_txq_info *queue_info) +int ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, + struct ath5k_txq_info *queue_info) { AR5K_TRACE; memcpy(queue_info, &hal->ah_txq[queue], sizeof(struct ath5k_txq_info)); - return true; + return 0; } /* @@ -3345,10 +3343,8 @@ ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, struct ath5k_txq_info void ath5k_hw_release_tx_queue(struct ath_hw *hal, unsigned int queue) { AR5K_TRACE; - if (queue >= hal->ah_capabilities.cap_queues.q_tx_num) { - WARN_ON(1); + if (WARN_ON(queue >= hal->ah_capabilities.cap_queues.q_tx_num)) return; - } /* This queue will be skipped in further operations */ hal->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; @@ -3359,8 +3355,7 @@ void ath5k_hw_release_tx_queue(struct ath_hw *hal, unsigned int queue) /* * Set DFS params for a transmit queue */ -bool -ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue) +int ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue) { u32 cw_min, cw_max, retry_lg, retry_sh; struct ath5k_txq_info *tq = &hal->ah_txq[queue]; @@ -3374,12 +3369,12 @@ ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue) tq = &hal->ah_txq[queue]; if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) - return true; + return 0; if (hal->ah_version == AR5K_AR5210) { /* Only handle data queues, others will be ignored */ if (tq->tqi_type != AR5K_TX_QUEUE_DATA) - return true; + return -EINVAL; /* * Write initial mode register settings @@ -3577,7 +3572,7 @@ ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue) AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); } - return true; + return 0; } /*