commit 09f4238c9cd1b7460cd615a659f78acdf086f094 Author: Jiri Slaby Date: Sat Jul 7 11:49:51 2007 +0200 implement rx diff --git a/ath/if_ath_pci.c b/ath/if_ath_pci.c index 4665fa4..534b868 100644 --- a/ath/if_ath_pci.c +++ b/ath/if_ath_pci.c @@ -181,7 +181,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ieee80211_tx_status(sc->hw, skb, &txs); - printk(KERN_DEBUG "DONE skb: %p, rssi: %d, stat: %x, seq: %u, stamp: %u\n", skb, ds->ds_txstat.ts_rssi, ds->ds_txstat.ts_status, ds->ds_txstat.ts_seqnum, ds->ds_txstat.ts_tstamp); +// printk(KERN_DEBUG "DONE skb: %p, rssi: %d, stat: %x, seq: %u, stamp: %u\n", skb, ds->ds_txstat.ts_rssi, ds->ds_txstat.ts_status, ds->ds_txstat.ts_seqnum, ds->ds_txstat.ts_tstamp); spin_lock(&sc->txbuflock); list_move_tail(&bf->list, &sc->txbuf); @@ -271,6 +271,113 @@ static int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) return 0; } +static void ath_tasklet_rx(unsigned long data) +{ + struct ieee80211_rx_status rxs = {}; + struct sk_buff *skb; + struct ath_softc *sc = (void *)data; + struct ath_buf *bf; + struct ath_desc *ds; + u16 len; + u8 stat; + int ret; + + spin_lock(&sc->rxbuflock); + do { + if (list_empty(&sc->rxbuf)) { + if (net_ratelimit()) + printk(KERN_WARNING "ath: empty rx buf pool\n"); + break; + } + bf = list_first_entry(&sc->rxbuf, struct ath_buf, list); + BUG_ON(bf->skb == NULL); + skb = bf->skb; + ds = bf->desc; + if (ds->ds_link == bf->daddr) /* this is the end */ + break; + + ret = sc->ah->ah_proc_rx_desc(sc->ah, ds); + if (ret == -EINPROGRESS) + break; + else if (ret) { + if (net_ratelimit()) + printk(KERN_ERR "ath: error in processing rx " + "descriptor\n"); + return; + } + + if (ds->ds_rxstat.rs_more) { + if (net_ratelimit()) + printk(KERN_INFO "ath: unsupported jumbo\n"); + goto next; + } + + stat = ds->ds_rxstat.rs_status; + if (stat) { + if (stat & AR5K_RXERR_CRC) + sc->stats.ast_rx_crcerr++; + if (stat & AR5K_RXERR_FIFO) + sc->stats.ast_rx_fifoerr++; + if (stat & AR5K_RXERR_PHY) { + sc->stats.ast_rx_phyerr++; + sc->stats.ast_rx_phy + [ds->ds_rxstat.rs_phyerr & 0x1f]++; + goto next; + } + if (stat & AR5K_RXERR_DECRYPT) { + /* + * Decrypt error. If the error occurred + * because there was no hardware key, then + * let the frame through so the upper layers + * can process it. This is necessary for 5210 + * parts which have no way to setup a ``clear'' + * key cache entry. + * + * XXX do key cache faulting + */ + if (ds->ds_rxstat.rs_keyix == + AR5K_RXKEYIX_INVALID) + goto accept; + sc->stats.ast_rx_badcrypt++; + } + if (stat & AR5K_RXERR_MIC) { + rxs.flag |= RX_FLAG_MMIC_ERROR; + sc->stats.ast_rx_badmic++; + goto accept; + } + + printk(KERN_DEBUG "throwing away: %x\n", stat); + goto next; + } +accept: + len = ds->ds_rxstat.rs_datalen; + pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + PCI_DMA_FROMDEVICE); + bf->skb = NULL; + + skb_put(skb, len); + + sc->stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++; + + rxs.mactime = ds->ds_rxstat.rs_tstamp; + rxs.freq = sc->curchan->freq; + rxs.channel = sc->curchan->chan; + rxs.phymode = sc->curmode; + rxs.ssi = ds->ds_rxstat.rs_rssi; + rxs.antenna = ds->ds_rxstat.rs_antenna; + rxs.rate = ds->ds_rxstat.rs_rate; + rxs.flag |= RX_FLAG_DECRYPTED; + +// printk(KERN_DEBUG "stat: %x, dlen: %u (hdr: %u), rssi: %d, rate: %u\n", ds->ds_rxstat.rs_status, len, ieee80211_get_hdrlen_from_skb(skb), ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_rate); + __ieee80211_rx(sc->hw, skb, &rxs); +next: + list_move_tail(&bf->list, &sc->rxbuf); + } while (ath_rxbuf_init(sc, bf) == 0); + spin_unlock(&sc->rxbuflock); +} + /* * Calculate the receive filter according to the * operating mode and state: @@ -338,7 +445,6 @@ static void ath_mode_init(struct ath_softc *sc) static int ath_startrecv(struct ath_softc *sc) { struct ath_hw *ah = sc->ah; - struct list_head *pos; struct ath_buf *bf; int ret; @@ -348,14 +454,18 @@ static int ath_startrecv(struct ath_softc *sc) __func__, sc->cachelsz, sc->rxbufsize); sc->rxlink = NULL; - list_for_each(pos, &sc->rxbuf) { - bf = list_entry(pos, struct ath_buf, list); + + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { ret = ath_rxbuf_init(sc, bf); - if (ret != 0) + if (ret != 0) { + spin_unlock_bh(&sc->rxbuflock); goto err; + } } - bf = list_first_entry(&sc->rxbuf, struct ath_buf, list); + spin_unlock_bh(&sc->rxbuflock); + ath5k_hw_put_rx_buf(ah, bf->daddr); ath5k_hw_start_rx(ah); /* enable recv descriptors */ ath_mode_init(sc); /* set filters, etc. */ @@ -436,8 +546,6 @@ done: */ static void ath_stoprecv(struct ath_softc *sc) { -#define PA2DESC(_sc, _pa) ((struct ath_desc *)((caddr_t)(_sc)->desc + \ - ((_pa) - (_sc)->desc_daddr))) struct ath_hw *ah = sc->ah; ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ @@ -446,7 +554,6 @@ static void ath_stoprecv(struct ath_softc *sc) mdelay(3); /* 3ms is long enough for 1 frame */ #ifdef AR_DEBUG if (sc->debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) { // TODO: compiler warns integer overflow - struct list_head *pos; struct ath_desc *ds; struct ath_buf *bf; int status; @@ -454,18 +561,17 @@ static void ath_stoprecv(struct ath_softc *sc) printk(KERN_DEBUG "%s: rx queue %x, link %p\n", __func__, ath5k_hw_get_rx_buf(ah), sc->rxlink); - list_for_each(pos, &sc->rxbuf) { - bf = list_entry(pos, struct ath_buf, list); + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { ds = bf->desc; - status = ah->ah_proc_rx_desc(ah, ds, bf->daddr, - PA2DESC(sc, ds->ds_link)); + status = ah->ah_proc_rx_desc(ah, ds); if (!status || (sc->debug & ATH_DEBUG_FATAL)) ath_printrxbuf(bf, status == 0); } + spin_unlock_bh(&sc->rxbuflock); } #endif sc->rxlink = NULL; /* just in case */ -#undef PA2DESC } static void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) @@ -725,7 +831,7 @@ static int ath_tx_bf(struct ath_softc *sc, struct ath_buf *bf, ath5k_hw_tx_start(ah, txq->qnum); spin_unlock_bh(&txq->lock); - printk(KERN_DEBUG "bf: %p, skb: %p, flags: %x, daddr: %x, dlink: %x, tlink: %x\n", bf, skb, flags, bf->daddr, ds->ds_link, *txq->link); +// printk(KERN_DEBUG "bf: %p, skb: %p, flags: %x, daddr: %x, dlink: %x, tlink: %x\n", bf, skb, flags, bf->daddr, ds->ds_link, *txq->link); return 0; err_unmap: @@ -884,8 +990,8 @@ static irqreturn_t ath_intr(int irq, void *dev_id) /* bump tx trigger level */ ath5k_hw_update_tx_triglevel(ah, true); } -/* if (status & AR5K_INT_RX) - tasklet_schedule(&sc->rxtq);*/ + if (status & AR5K_INT_RX) + tasklet_schedule(&sc->rxtq); if (status & AR5K_INT_TX) tasklet_schedule(&sc->txtq); /* if (status & AR5K_INT_BMISS) { @@ -1229,11 +1335,9 @@ err: static void ath_descdma_cleanup(struct ath_softc *sc, struct pci_dev *pdev, struct list_head *head) { - struct list_head *pos; struct ath_buf *bf; - list_for_each(pos, head) { - bf = list_entry(pos, struct ath_buf, list); + list_for_each_entry(bf, head, list) { if (bf->skb) { pci_unmap_single(pdev, bf->skbaddr, sc->rxbufsize, PCI_DMA_FROMDEVICE); @@ -1241,8 +1345,6 @@ static void ath_descdma_cleanup(struct ath_softc *sc, struct pci_dev *pdev, bf->skb = NULL; } } - - INIT_LIST_HEAD(head); } static void ath_desc_free(struct ath_softc *sc, struct pci_dev *pdev) @@ -1432,13 +1534,15 @@ static int ath_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) goto err_queues; } #endif - tasklet_init(&sc->txtq, ath_tasklet_tx, (unsigned long)sc); 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; } + + tasklet_init(&sc->rxtq, ath_tasklet_rx, (unsigned long)sc); + tasklet_init(&sc->txtq, ath_tasklet_tx, (unsigned long)sc); #ifdef BLE /* * Setup rate control. Some rate control modules @@ -1644,6 +1748,7 @@ static int __devinit ath_pci_probe(struct pci_dev *pdev, sc->iobase = mem; sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); /* tasklet_init(&sc->sc_rxtq, ath_rx_tasklet, (unsigned long)hw); diff --git a/ath/if_athvar.h b/ath/if_athvar.h index 9439994..5bacf0f 100644 --- a/ath/if_athvar.h +++ b/ath/if_athvar.h @@ -253,9 +253,10 @@ struct ath_softc { #endif unsigned int rxbufsize; /* rx size based on mtu */ struct list_head rxbuf; /* receive buffer */ + spinlock_t rxbuflock; u32 *rxlink; /* link ptr in last RX desc */ -#ifdef BLE struct tasklet_struct rxtq; /* rx intr tasklet */ +#ifdef BLE struct tasklet_struct rxorntq; /* rxorn intr tasklet */ //#ifdef BLE u8 sc_defant; /* current default antenna */ @@ -263,8 +264,8 @@ struct ath_softc { #endif struct list_head txbuf; /* transmit buffer */ - spinlock_t txbuflock; /* txbuf lock */ - struct ath_txq txqs[2]; /* beacon and tx*/ + spinlock_t txbuflock; + struct ath_txq txqs[2]; /* beacon and tx */ #ifdef BLE int sc_tx_timer; /* transmit timeout */ u_int sc_txintrperiod;/* tx interrupt batching */ diff --git a/openhal/ath5k.h b/openhal/ath5k.h index c2a109e..c24480b 100644 --- a/openhal/ath5k.h +++ b/openhal/ath5k.h @@ -986,8 +986,7 @@ struct ath_hw { int (*ah_fill_tx_desc)(struct ath_hw *, struct ath_desc *, unsigned int, bool, bool); int (*ah_proc_tx_desc)(struct ath_hw *, struct ath_desc *); - int (*ah_proc_rx_desc)(struct ath_hw *, struct ath_desc *, u32, - struct ath_desc *); + int (*ah_proc_rx_desc)(struct ath_hw *, struct ath_desc *); }; /* @@ -1074,7 +1073,7 @@ 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); /* Hardware Descriptor Functions */ /* RX Descriptor */ -bool ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, u32 size, unsigned int flags); +int ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, u32 size, unsigned int flags); /* GPIO Functions */ void ath5k_hw_set_ledstate(struct ath_hw *hal, unsigned int state); bool ath5k_hw_set_gpio_output(struct ath_hw *hal, u32 gpio); diff --git a/openhal/ath5k_hw.c b/openhal/ath5k_hw.c index a8dd473..7d246e0 100644 --- a/openhal/ath5k_hw.c +++ b/openhal/ath5k_hw.c @@ -59,10 +59,8 @@ static int ath5k_hw_setup_2word_tx_desc(struct ath_hw *, struct ath_desc *, static int ath5k_hw_fill_2word_tx_desc(struct ath_hw *, struct ath_desc *, unsigned int, bool, bool); static int ath5k_hw_proc_2word_tx_status(struct ath_hw *, struct ath_desc *); -static int ath5k_hw_proc_new_rx_status(struct ath_hw *, struct ath_desc *, u32, - struct ath_desc *); -static int ath5k_hw_proc_old_rx_status(struct ath_hw *, struct ath_desc *, u32, - struct ath_desc *); +static int ath5k_hw_proc_new_rx_status(struct ath_hw *, struct ath_desc *); +static int ath5k_hw_proc_old_rx_status(struct ath_hw *, struct ath_desc *); static int ath5k_hw_get_capabilities(struct ath_hw *); static int ath5k_eeprom_init(struct ath_hw *); @@ -4122,8 +4120,7 @@ static int ath5k_hw_proc_4word_tx_status(struct ath_hw *hal, /* * Initialize an rx descriptor */ -bool -ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, +int ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, u32 size, unsigned int flags) { struct ath5k_rx_desc *rx_desc; @@ -4144,22 +4141,22 @@ ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, rx_desc->rx_control_0 = 0; rx_desc->rx_control_1 = 0; - /*Setup descriptor*/ - if ((rx_desc->rx_control_1 = (size & - AR5K_DESC_RX_CTL1_BUF_LEN)) != size) - return false; + /* Setup descriptor */ + rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; + if (rx_desc->rx_control_1 != size) + return -EINVAL; if (flags & AR5K_RXDESC_INTREQ) rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; - return true; + return 0; } /* * Proccess the rx status descriptor on 5210/5211 */ static int ath5k_hw_proc_old_rx_status(struct ath_hw *hal, - struct ath_desc *desc, u32 phys_addr, struct ath_desc *next) + struct ath_desc *desc) { struct ath5k_hw_old_rx_status *rx_status; @@ -4233,7 +4230,7 @@ static int ath5k_hw_proc_old_rx_status(struct ath_hw *hal, * Proccess the rx status descriptor on 5212 */ static int ath5k_hw_proc_new_rx_status(struct ath_hw *hal, - struct ath_desc *desc, u32 phys_addr, struct ath_desc *next) + struct ath_desc *desc) { struct ath5k_hw_new_rx_status *rx_status; struct ath5k_hw_rx_error *rx_err; @@ -4271,10 +4268,8 @@ static int ath5k_hw_proc_new_rx_status(struct ath_hw *hal, /* * Key table status */ - if (rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) - desc->ds_us.rx.rs_keyix = - AR5K_REG_MS(rx_status->rx_status_1, + if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) + desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX); else desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; @@ -4284,12 +4279,10 @@ static int ath5k_hw_proc_new_rx_status(struct ath_hw *hal, */ if ((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { - if (rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) + if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; - if (rx_status->rx_status_1 & - AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) { + if (rx_status->rx_status_1 &AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR){ desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; desc->ds_us.rx.rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1,