diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2800pci.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 318 |
1 files changed, 128 insertions, 190 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 91cce2d..b2f2327 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -60,6 +60,12 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) unsigned int i; u32 reg; + /* + * SOC devices don't support MCU requests. + */ + if (rt2x00_is_soc(rt2x00dev)) + return; + for (i = 0; i < 200; i++) { rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); @@ -341,19 +347,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) struct queue_entry_priv_pci *entry_priv; u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); - /* * Initialize registers. */ @@ -620,64 +613,31 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ +static int rt2800pci_write_tx_data(struct queue_entry* entry, + struct txentry_desc *txdesc) +{ + int ret; + + ret = rt2x00pci_write_tx_data(entry, txdesc); + if (ret) + return ret; + + rt2800_write_txwi(entry->skb, txdesc); + + return 0; +} + + static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txd = skbdesc->desc; - __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->ops->extra_tx_headroom); + struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + __le32 *txd = entry_priv->desc; u32 word; /* - * Initialize TX Info descriptor - */ - rt2x00_desc_read(txwi, 0, &word); - rt2x00_set_field32(&word, TXWI_W0_FRAG, - test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); - rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); - rt2x00_set_field32(&word, TXWI_W0_TS, - test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_AMPDU, - test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density); - rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs); - rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs); - rt2x00_set_field32(&word, TXWI_W0_BW, - test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, - test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc); - rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); - rt2x00_desc_write(txwi, 0, word); - - rt2x00_desc_read(txwi, 1, &word); - rt2x00_set_field32(&word, TXWI_W1_ACK, - test_bit(ENTRY_TXD_ACK, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W1_NSEQ, - test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); - rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, - test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - txdesc->key_idx : 0xff); - rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, - skb->len - txdesc->l2pad); - rt2x00_set_field32(&word, TXWI_W1_PACKETID, - skbdesc->entry->queue->qid + 1); - rt2x00_desc_write(txwi, 1, word); - - /* - * Always write 0 to IV/EIV fields, hardware will insert the IV - * from the IVEIV register when TXD_W3_WIV is set to 0. - * When TXD_W3_WIV is set to 1 it will use the IV data - * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which - * crypto entry in the registers should be used to encrypt the frame. - */ - _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); - _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); - - /* * The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1 * must contains a TXWI structure + 802.11 header + padding + 802.11 * data. We choose to have SD_PTR0/SD_LEN0 only contains TXWI and @@ -698,15 +658,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W1_SD_LEN0, - rt2x00dev->ops->extra_tx_headroom); + rt2x00_set_field32(&word, TXD_W1_SD_LEN0, TXWI_DESC_SIZE); rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_SD_PTR1, - skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom); + skbdesc->skb_dma + TXWI_DESC_SIZE); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); @@ -714,15 +673,21 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W3_QSEL, 2); rt2x00_desc_write(txd, 3, word); + + /* + * Register descriptor details in skb frame descriptor. + */ + skbdesc->desc = txd; + skbdesc->desc_len = TXD_DESC_SIZE; } /* * TX data initialization */ -static void rt2800pci_write_beacon(struct queue_entry *entry) +static void rt2800pci_write_beacon(struct queue_entry *entry, + struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; u32 reg; @@ -735,15 +700,25 @@ static void rt2800pci_write_beacon(struct queue_entry *entry) rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); /* - * Write entire beacon with descriptor to register. + * Add the TXWI for the beacon to the skb. + */ + rt2800_write_txwi(entry->skb, txdesc); + skb_push(entry->skb, TXWI_DESC_SIZE); + + /* + * Write entire beacon with TXWI to register. */ beacon_base = HW_BEACON_OFFSET(entry->entry_idx); - rt2800_register_multiwrite(rt2x00dev, - beacon_base, - skbdesc->desc, skbdesc->desc_len); - rt2800_register_multiwrite(rt2x00dev, - beacon_base + skbdesc->desc_len, - entry->skb->data, entry->skb->len); + rt2800_register_multiwrite(rt2x00dev, beacon_base, + entry->skb->data, entry->skb->len); + + /* + * Enable beaconing again. + */ + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); /* * Clean up beacon skb. @@ -757,18 +732,6 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, { struct data_queue *queue; unsigned int idx, qidx = 0; - u32 reg; - - if (queue_idx == QID_BEACON) { - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - } - return; - } if (queue_idx > QID_HCCA && queue_idx != QID_MGMT) return; @@ -811,34 +774,21 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *rxd = entry_priv->desc; - __le32 *rxwi = (__le32 *)entry->skb->data; - u32 rxd3; - u32 rxwi0; - u32 rxwi1; - u32 rxwi2; - u32 rxwi3; - - rt2x00_desc_read(rxd, 3, &rxd3); - rt2x00_desc_read(rxwi, 0, &rxwi0); - rt2x00_desc_read(rxwi, 1, &rxwi1); - rt2x00_desc_read(rxwi, 2, &rxwi2); - rt2x00_desc_read(rxwi, 3, &rxwi3); - - if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR)) + u32 word; + + rt2x00_desc_read(rxd, 3, &word); + + if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { - /* - * Unfortunately we don't know the cipher type used during - * decryption. This prevents us from correct providing - * correct statistics through debugfs. - */ - rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); - rxdesc->cipher_status = - rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR); - } + /* + * Unfortunately we don't know the cipher type used during + * decryption. This prevents us from correct providing + * correct statistics through debugfs. + */ + rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W3_CIPHER_ERROR); - if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) { + if (rt2x00_get_field32(word, RXD_W3_DECRYPTED)) { /* * Hardware has stripped IV/EIV data from 802.11 frame during * decryption. Unfortunately the descriptor doesn't contain @@ -853,51 +803,22 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_MMIC_ERROR; } - if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS)) + if (rt2x00_get_field32(word, RXD_W3_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) + if (rt2x00_get_field32(word, RXD_W3_L2PAD)) rxdesc->dev_flags |= RXDONE_L2PAD; - if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) - rxdesc->flags |= RX_FLAG_SHORT_GI; - - if (rt2x00_get_field32(rxwi1, RXWI_W1_BW)) - rxdesc->flags |= RX_FLAG_40MHZ; - /* - * Detect RX rate, always use MCS as signal type. + * Process the RXWI structure that is at the start of the buffer. */ - rxdesc->dev_flags |= RXDONE_SIGNAL_MCS; - rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE); - rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS); - - /* - * Mask of 0x8 bit to remove the short preamble flag. - */ - if (rxdesc->rate_mode == RATE_MODE_CCK) - rxdesc->signal &= ~0x8; - - rxdesc->rssi = - (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) + - rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2; - - rxdesc->noise = - (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) + - rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2; - - rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); + rt2800_process_rxwi(entry->skb, rxdesc); /* * Set RX IDX in register to inform hardware that we have handled * this entry and it is available for reuse again. */ rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); - - /* - * Remove TXWI descriptor from start of buffer. - */ - skb_pull(entry->skb, RXWI_DESC_SIZE); } /* @@ -907,14 +828,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; - struct queue_entry *entry_done; - struct queue_entry_priv_pci *entry_priv; + __le32 *txwi; struct txdone_entry_desc txdesc; u32 word; u32 reg; u32 old_reg; - unsigned int type; - unsigned int index; + int wcid, ack, pid, tx_wcid, tx_ack, tx_pid; u16 mcs, real_mcs; /* @@ -936,76 +855,89 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) break; old_reg = reg; + wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); + ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); + /* * Skip this entry when it contains an invalid * queue identication number. */ - type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; - if (type >= QID_RX) + if (pid <= 0 || pid > QID_RX) continue; - queue = rt2x00queue_get_queue(rt2x00dev, type); + queue = rt2x00queue_get_queue(rt2x00dev, pid - 1); if (unlikely(!queue)) continue; /* - * Skip this entry when it contains an invalid - * index number. + * Inside each queue, we process each entry in a chronological + * order. We first check that the queue is not empty. */ - index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID) - 1; - if (unlikely(index >= queue->limit)) + if (rt2x00queue_empty(queue)) continue; + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - entry = &queue->entries[index]; - entry_priv = entry->priv_data; - rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word); + /* Check if we got a match by looking at WCID/ACK/PID + * fields */ + txwi = (__le32 *)(entry->skb->data - + rt2x00dev->ops->extra_tx_headroom); - entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - while (entry != entry_done) { - /* - * Catch up. - * Just report any entries we missed as failed. - */ - WARNING(rt2x00dev, - "TX status report missed for entry %d\n", - entry_done->entry_idx); + rt2x00_desc_read(txwi, 1, &word); + tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); + tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); + tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); - txdesc.flags = 0; - __set_bit(TXDONE_UNKNOWN, &txdesc.flags); - txdesc.retry = 0; - - rt2x00lib_txdone(entry_done, &txdesc); - entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - } + if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) + WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n"); /* * Obtain the status about this packet. */ txdesc.flags = 0; - if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) - __set_bit(TXDONE_SUCCESS, &txdesc.flags); - else - __set_bit(TXDONE_FAILURE, &txdesc.flags); + rt2x00_desc_read(txwi, 0, &word); + mcs = rt2x00_get_field32(word, TXWI_W0_MCS); + real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); /* * Ralink has a retry mechanism using a global fallback - * table. We setup this fallback table to try immediate - * lower rate for all rates. In the TX_STA_FIFO, - * the MCS field contains the MCS used for the successfull - * transmission. If the first transmission succeed, - * we have mcs == tx_mcs. On the second transmission, - * we have mcs = tx_mcs - 1. So the number of - * retry is (tx_mcs - mcs). + * table. We setup this fallback table to try the immediate + * lower rate for all rates. In the TX_STA_FIFO, the MCS field + * always contains the MCS used for the last transmission, be + * it successful or not. */ - mcs = rt2x00_get_field32(word, TXWI_W0_MCS); - real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); + if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) { + /* + * Transmission succeeded. The number of retries is + * mcs - real_mcs + */ + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0); + } else { + /* + * Transmission failed. The number of retries is + * always 7 in this case (for a total number of 8 + * frames sent). + */ + __set_bit(TXDONE_FAILURE, &txdesc.flags); + txdesc.retry = 7; + } + __set_bit(TXDONE_FALLBACK, &txdesc.flags); - txdesc.retry = mcs - min(mcs, real_mcs); + rt2x00lib_txdone(entry, &txdesc); } } +static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) +{ + struct ieee80211_conf conf = { .flags = 0 }; + struct rt2x00lib_conf libconf = { .conf = &conf }; + + rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); +} + static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; @@ -1030,6 +962,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) rt2800pci_txdone(rt2x00dev); + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) + rt2800pci_wakeup(rt2x00dev); + return IRQ_HANDLED; } @@ -1128,7 +1063,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, .write_tx_desc = rt2800pci_write_tx_desc, - .write_tx_data = rt2x00pci_write_tx_data, + .write_tx_data = rt2800pci_write_tx_data, .write_beacon = rt2800pci_write_beacon, .kick_tx_queue = rt2800pci_kick_tx_queue, .kill_tx_queue = rt2800pci_kill_tx_queue, @@ -1184,6 +1119,7 @@ static const struct rt2x00_ops rt2800pci_ops = { /* * RT2800pci module information. */ +#ifdef CONFIG_RT2800PCI_PCI static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, @@ -1208,9 +1144,11 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) }, #endif { 0, } }; +#endif /* CONFIG_RT2800PCI_PCI */ MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); |