diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00')
21 files changed, 975 insertions, 690 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 5063e01410e5..103c71164f10 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1007,12 +1007,11 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2400pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1096,7 +1095,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2400pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1112,24 +1111,24 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt2400pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } -static void rt2400pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2400pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, CSR14, 0); } else { rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); @@ -1481,15 +1480,17 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER); + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c2a555d5376b..ab0507110e42 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1161,12 +1161,11 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2500pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1249,7 +1248,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2500pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1265,24 +1264,24 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt2500pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } -static void rt2500pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2500pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, CSR14, 0); } else { rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); @@ -1795,19 +1794,23 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = DEFAULT_TXPOWER; + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = DEFAULT_TXPOWER; + } } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index cdaf93f48263..db64df4267d8 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -355,7 +355,9 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, * it is known that not work at least on some hardware. * SW crypto will be used in that case. */ - if (key->alg == ALG_WEP && key->keyidx != 0) + if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) && + key->keyidx != 0) return -EOPNOTSUPP; /* @@ -1039,12 +1041,11 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2500usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txd = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txd = (__le32 *) entry->skb->data; u32 word; /* @@ -1127,7 +1128,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2500usb_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1195,6 +1196,14 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry) return length; } +static void rt2500usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0); + + rt2x00usb_kill_tx_queue(queue); +} + /* * RX control handlers */ @@ -1698,19 +1707,23 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = DEFAULT_TXPOWER; + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = DEFAULT_TXPOWER; + } } return 0; @@ -1789,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .write_beacon = rt2500usb_write_beacon, .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt2500usb_kill_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, .config_shared_key = rt2500usb_config_key, .config_pairwise_key = rt2500usb_config_key, diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index ed4ebcdde7c9..70a5cb86405b 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1318,7 +1318,25 @@ #define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) /* - * TX_STA_FIFO: TX Result for specific PID status fifo register + * TX_STA_FIFO: TX Result for specific PID status fifo register. + * + * This register is implemented as FIFO with 16 entries in the HW. Each + * register read fetches the next tx result. If the FIFO is full because + * it wasn't read fast enough after the according interrupt (TX_FIFO_STATUS) + * triggered, the hw seems to simply drop further tx results. + * + * VALID: 1: this tx result is valid + * 0: no valid tx result -> driver should stop reading + * PID_TYPE: The PID latched from the PID field in the TXWI, can be used + * to match a frame with its tx result (even though the PID is + * only 4 bits wide). + * TX_SUCCESS: Indicates tx success (1) or failure (0) + * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0) + * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0) + * WCID: The wireless client ID. + * MCS: The tx rate used during the last transmission of this frame, be it + * successful or not. + * PHYMODE: The phymode used for the transmission. */ #define TX_STA_FIFO 0x1718 #define TX_STA_FIFO_VALID FIELD32(0x00000001) @@ -1841,6 +1859,13 @@ struct mac_iveiv_entry { #define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) /* + * EEPROM Maximum TX power values + */ +#define EEPROM_MAX_TX_POWER 0x0027 +#define EEPROM_MAX_TX_POWER_24GHZ FIELD16(0x00ff) +#define EEPROM_MAX_TX_POWER_5GHZ FIELD16(0xff00) + +/* * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. * This is delta in 40MHZ. * VALUE: Tx Power dalta value (MAX=4) @@ -1928,6 +1953,8 @@ struct mac_iveiv_entry { * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs * BW: Channel bandwidth 20MHz or 40 MHz * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will + * aggregate consecutive frames with the same RA and QoS TID. */ #define TXWI_W0_FRAG FIELD32(0x00000001) #define TXWI_W0_MIMO_PS FIELD32(0x00000002) @@ -1945,6 +1972,15 @@ struct mac_iveiv_entry { /* * Word1 + * ACK: 0: No Ack needed, 1: Ack needed + * NSEQ: 0: Don't assign hw sequence number, 1: Assign hw sequence number + * BW_WIN_SIZE: BA windows size of the recipient + * WIRELESS_CLI_ID: Client ID for WCID table access + * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame + * PACKETID: Will be latched into the TX_STA_FIFO register once the according + * frame was processed. If multiple frames are aggregated together + * (AMPDU==1) the reported tx status will always contain the packet + * id of the first frame. 0: Don't report tx status for this frame. */ #define TXWI_W1_ACK FIELD32(0x00000001) #define TXWI_W1_NSEQ FIELD32(0x00000002) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b66e0fd8f0fa..27a6e225083c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1,4 +1,5 @@ /* + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com> @@ -254,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_mcu_request); +int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i = 0; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + return 0; + msleep(1); + } + + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; +} +EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready); + int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; @@ -367,19 +385,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, u32 reg; /* - * Wait for stable hardware. + * If driver doesn't wake up firmware here, + * rt2800_load_firmware will hang forever when interface is up again. */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); + /* + * Wait for stable hardware. + */ + if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - } if (rt2x00_is_pci(rt2x00dev)) rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); @@ -427,8 +442,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_load_firmware); -void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) +void rt2800_write_tx_data(struct queue_entry *entry, + struct txentry_desc *txdesc) { + __le32 *txwi = rt2800_drv_get_txwi(entry); u32 word; /* @@ -437,7 +454,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) 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_MIMO_PS, + test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); rt2x00_set_field32(&word, TXWI_W0_TS, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); @@ -465,7 +483,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) txdesc->key_idx : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, txdesc->length); - rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1); rt2x00_desc_write(txwi, 1, word); /* @@ -478,7 +496,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc) _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); } -EXPORT_SYMBOL_GPL(rt2800_write_txwi); +EXPORT_SYMBOL_GPL(rt2800_write_tx_data); static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) { @@ -490,7 +508,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2) u8 offset1; u8 offset2; - if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) { + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); @@ -569,6 +587,148 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); +static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) +{ + __le32 *txwi; + u32 word; + int wcid, ack, pid; + int tx_wcid, tx_ack, tx_pid; + + 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); + + /* + * This frames has returned with an IO error, + * so the status report is not intended for this + * frame. + */ + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + return false; + } + + /* + * Validate if this TX status report is intended for + * this entry by comparing the WCID/ACK/PID fields. + */ + txwi = rt2800_drv_get_txwi(entry); + + 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); + + if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { + WARNING(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + return false; + } + + return true; +} + +void rt2800_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + __le32 *txwi; + struct txdone_entry_desc txdesc; + u32 word; + u32 reg; + u16 mcs, real_mcs; + u8 pid; + int i; + + /* + * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO + * at most X times and also stop processing once the TX_STA_FIFO_VALID + * flag is not set anymore. + * + * The legacy drivers use X=TX_RING_SIZE but state in a comment + * that the TX_STA_FIFO stack has a size of 16. We stick to our + * tx ring size for now. + */ + for (i = 0; i < TX_ENTRIES; i++) { + rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); + if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) + break; + + /* + * Skip this entry when it contains an invalid + * queue identication number. + */ + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; + if (pid >= QID_RX) + continue; + + queue = rt2x00queue_get_queue(rt2x00dev, pid); + if (unlikely(!queue)) + continue; + + /* + * Inside each queue, we process each entry in a chronological + * order. We first check that the queue is not empty. + */ + entry = NULL; + txwi = NULL; + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + if (rt2800_txdone_entry_check(entry, reg)) + break; + } + + if (!entry || rt2x00queue_empty(queue)) + break; + + + /* + * Obtain the status about this packet. + */ + txdesc.flags = 0; + txwi = rt2800_drv_get_txwi(entry); + 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 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. + */ + 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 = rt2x00dev->long_retry; + } + + /* + * the frame was retried at least once + * -> hw used fallback rates + */ + if (txdesc.retry) + __set_bit(TXDONE_FALLBACK, &txdesc.flags); + + rt2x00lib_txdone(entry, &txdesc); + } +} +EXPORT_SYMBOL_GPL(rt2800_txdone); + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -600,7 +760,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) /* * Add the TXWI for the beacon to the skb. */ - rt2800_write_txwi((__le32 *)entry->skb->data, txdesc); + rt2800_write_tx_data(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -975,19 +1135,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, } if (flags & CONFIG_UPDATE_MAC) { - reg = le32_to_cpu(conf->mac[1]); - rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); - conf->mac[1] = cpu_to_le32(reg); + if (!is_zero_ether_addr((const u8 *)conf->mac)) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + } rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, conf->mac, sizeof(conf->mac)); } if (flags & CONFIG_UPDATE_BSSID) { - reg = le32_to_cpu(conf->bssid[1]); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); - conf->bssid[1] = cpu_to_le32(reg); + if (!is_zero_ether_addr((const u8 *)conf->bssid)) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); + conf->bssid[1] = cpu_to_le32(reg); + } rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, conf->bssid, sizeof(conf->bssid)); @@ -1120,27 +1284,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, * double meaning, and we should set a 7DBm boost flag. */ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, - (info->tx_power1 >= 0)); + (info->default_power1 >= 0)); - if (info->tx_power1 < 0) - info->tx_power1 += 7; + if (info->default_power1 < 0) + info->default_power1 += 7; - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1); rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, - (info->tx_power2 >= 0)); + (info->default_power2 >= 0)); - if (info->tx_power2 < 0) - info->tx_power2 += 7; + if (info->default_power2 < 0) + info->default_power2 += 7; - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power2)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2); } else { - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power2)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2); } rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); @@ -1180,13 +1340,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power2)); + rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); @@ -1210,10 +1368,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; + if (rf->channel <= 14) { + info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1); + info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2); + } else { + info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1); + info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2); + } + if (rt2x00_rf(rt2x00dev, RF2020) || rt2x00_rf(rt2x00dev, RF3020) || rt2x00_rf(rt2x00dev, RF3021) || - rt2x00_rf(rt2x00dev, RF3022)) + rt2x00_rf(rt2x00dev, RF3022) || + rt2x00_rf(rt2x00dev, RF3052)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); else rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); @@ -1536,7 +1703,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner); /* * Initialization functions. */ -int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; u16 eeprom; @@ -1906,7 +2073,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_registers); static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) { @@ -1949,7 +2115,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) return -EACCES; } -int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) { unsigned int i; u16 eeprom; @@ -2044,7 +2210,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_bbp); static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, u8 rfcsr24, u8 filter_target) @@ -2106,7 +2271,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, return rfcsr24; } -int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) { u8 rfcsr; u8 bbp; @@ -2360,7 +2525,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); + +int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 word; + + /* + * Initialize all registers. + */ + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || + rt2800_init_registers(rt2x00dev) || + rt2800_init_bbp(rt2x00dev) || + rt2800_init_rfcsr(rt2x00dev))) + return -EIO; + + /* + * Send signal to firmware during boot time. + */ + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); + + if (rt2x00_is_usb(rt2x00dev) && + (rt2x00_rt(rt2x00dev, RT3070) || + rt2x00_rt(rt2x00dev, RT3071) || + rt2x00_rt(rt2x00dev, RT3572))) { + udelay(200); + rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); + udelay(10); + } + + /* + * Enable RX. + */ + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + udelay(50); + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + /* + * Initialize LED control + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + word & 0xff, (word >> 8) & 0xff); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_enable_radio); + +void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + /* Wait for DMA, ignore error */ + rt2800_wait_wpdma_ready(rt2x00dev); + + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); +} +EXPORT_SYMBOL_GPL(rt2800_disable_radio); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) { @@ -2516,6 +2774,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) default_lna_gain); rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word); + if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff) + rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER); + if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff) + rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER); + rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word); + return 0; } EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); @@ -2755,9 +3020,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; - char *tx_power1; - char *tx_power2; + char *default_power1; + char *default_power2; unsigned int i; + unsigned short max_power; u16 eeprom; /* @@ -2865,27 +3131,32 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom); + max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ); + default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); for (i = 0; i < 14; i++) { - info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + info[i].max_power = max_power; + info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]); + info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]); } if (spec->num_channels > 14) { - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ); + default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); for (i = 14; i < spec->num_channels; i++) { - info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + info[i].max_power = max_power; + info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]); + info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]); } } diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 091641e3c5e2..986229c06c19 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -1,4 +1,6 @@ /* + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2009 Bartlomiej Zolnierkiewicz This program is free software; you can redistribute it and/or modify @@ -44,6 +46,7 @@ struct rt2800_ops { int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len); int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev); + __le32 *(*drv_get_txwi)(struct queue_entry *entry); }; static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, @@ -126,18 +129,31 @@ static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev) return rt2800ops->drv_init_registers(rt2x00dev); } +static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry) +{ + const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv; + + return rt2800ops->drv_get_txwi(entry); +} + void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1); +int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev); +int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); + int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len); int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len); -void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc); +void rt2800_write_tx_data(struct queue_entry *entry, + struct txentry_desc *txdesc); void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); +void rt2800_txdone(struct rt2x00_dev *rt2x00dev); + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); extern const struct rt2x00debug rt2800_rt2x00debug; @@ -163,10 +179,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); -int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); -int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); -int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); -int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); +int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 39b3846fa340..2bcb1507e3ac 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> @@ -196,8 +196,6 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); - /* * enable Host program ram write selection */ @@ -399,78 +397,18 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - u16 word; - - /* - * Initialize all registers. - */ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800pci_init_queues(rt2x00dev) || - rt2800_init_registers(rt2x00dev) || - rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800_init_bbp(rt2x00dev) || - rt2800_init_rfcsr(rt2x00dev))) + rt2800pci_init_queues(rt2x00dev))) return -EIO; - /* - * Send signal to firmware during boot time. - */ - rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); - - /* - * Enable RX. - */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - /* - * Initialize LED control - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, - word & 0xff, (word >> 8) & 0xff); - - return 0; + return rt2800_enable_radio(rt2x00dev); } static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2800_disable_radio(rt2x00dev); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); @@ -486,9 +424,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); - - /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); } static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, @@ -566,21 +501,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2800pci_write_tx_data(struct queue_entry* entry, - struct txentry_desc *txdesc) +static __le32 *rt2800pci_get_txwi(struct queue_entry *entry) { - __le32 *txwi = (__le32 *) entry->skb->data; - - rt2800_write_txwi(txwi, txdesc); + return (__le32 *) entry->skb->data; } - -static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2800pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -600,7 +530,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len); + rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len); rt2x00_set_field32(&word, TXD_W1_LAST_SEC1, !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BURST, @@ -631,41 +561,35 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * TX data initialization */ -static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue_idx) +static void rt2800pci_kick_tx_queue(struct data_queue *queue) { - struct data_queue *queue; - unsigned int idx, qidx = 0; - - if (queue_idx > QID_HCCA && queue_idx != QID_MGMT) - return; - - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - idx = queue->index[Q_INDEX]; + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + unsigned int qidx = 0; - if (queue_idx == QID_MGMT) + if (queue->qid == QID_MGMT) qidx = 5; else - qidx = queue_idx; + qidx = queue->qid; - rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); + rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx); } -static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2800pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0); return; } rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO)); rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); } @@ -728,110 +652,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, /* * Interrupt functions. */ -static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - __le32 *txwi; - struct txdone_entry_desc txdesc; - u32 word; - u32 reg; - int wcid, ack, pid, tx_wcid, tx_ack, tx_pid; - u16 mcs, real_mcs; - int i; - - /* - * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO - * at most X times and also stop processing once the TX_STA_FIFO_VALID - * flag is not set anymore. - * - * The legacy drivers use X=TX_RING_SIZE but state in a comment - * that the TX_STA_FIFO stack has a size of 16. We stick to our - * tx ring size for now. - */ - for (i = 0; i < TX_ENTRIES; i++) { - rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); - if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) - break; - - 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. - */ - if (pid <= 0 || pid > QID_RX) - continue; - - queue = rt2x00queue_get_queue(rt2x00dev, pid - 1); - if (unlikely(!queue)) - continue; - - /* - * Inside each queue, we process each entry in a chronological - * order. We first check that the queue is not empty. - */ - if (rt2x00queue_empty(queue)) - continue; - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - - /* Check if we got a match by looking at WCID/ACK/PID - * fields */ - txwi = (__le32 *) entry->skb->data; - - 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); - - 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; - 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 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. - */ - 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; - } - - /* - * the frame was retried at least once - * -> hw used fallback rates - */ - if (txdesc.retry) - __set_bit(TXDONE_FALLBACK, &txdesc.flags); - - rt2x00lib_txdone(entry, &txdesc); - } -} - static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) { struct ieee80211_conf conf = { .flags = 0 }; @@ -867,7 +687,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) * 4 - Tx done interrupt. */ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) - rt2800pci_txdone(rt2x00dev); + rt2800_txdone(rt2x00dev); /* * 5 - Auto wakeup interrupt. @@ -1011,6 +831,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = { .regbusy_read = rt2x00pci_regbusy_read, .drv_write_firmware = rt2800pci_write_firmware, .drv_init_registers = rt2800pci_init_registers, + .drv_get_txwi = rt2800pci_get_txwi, }; static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { @@ -1030,7 +851,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 = rt2800pci_write_tx_data, + .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, .kick_tx_queue = rt2800pci_kick_tx_queue, .kill_tx_queue = rt2800pci_kill_tx_queue, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5a2dfe87c6b6..3dff56ec195a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> @@ -100,19 +101,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, msleep(10); rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); - /* - * Send signal to firmware during boot time. - */ - rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); - - if (rt2x00_rt(rt2x00dev, RT3070) || - rt2x00_rt(rt2x00dev, RT3071) || - rt2x00_rt(rt2x00dev, RT3572)) { - udelay(200); - rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); - udelay(10); - } - return 0; } @@ -134,26 +122,18 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - int i; /* * Wait until BBP and RF are ready. */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } - - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); + if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - } rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); @@ -172,30 +152,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 word; - /* - * Initialize all registers. - */ - if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800_init_registers(rt2x00dev) || - rt2800_init_bbp(rt2x00dev) || - rt2800_init_rfcsr(rt2x00dev))) + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev))) return -EIO; - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - udelay(50); - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); @@ -210,45 +170,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - /* - * Initialize LED control - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, - word & 0xff, (word >> 8) & 0xff); - - return 0; + return rt2800_enable_radio(rt2x00dev); } static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); - - /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); - + rt2800_disable_radio(rt2x00dev); rt2x00usb_disable_radio(rt2x00dev); } @@ -320,21 +247,19 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2800usb_write_tx_data(struct queue_entry* entry, - struct txentry_desc *txdesc) +static __le32 *rt2800usb_get_txwi(struct queue_entry *entry) { - __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE); - - rt2800_write_txwi(txwi, txdesc); + if (entry->queue->qid == QID_BEACON) + return (__le32 *) (entry->skb->data); + else + return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE); } - -static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2800usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txi = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txi = (__le32 *) entry->skb->data; u32 word; /* @@ -342,7 +267,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txi, 0, &word); rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, - skb->len - TXINFO_DESC_SIZE); + entry->skb->len - TXINFO_DESC_SIZE); rt2x00_set_field32(&word, TXINFO_W0_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); @@ -379,6 +304,46 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) } /* + * TX control handlers + */ +static void rt2800usb_work_txdone(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, txdone_work); + struct data_queue *queue; + struct queue_entry *entry; + + rt2800_txdone(rt2x00dev); + + /* + * Process any trailing TX status reports for IO failures, + * we loop until we find the first non-IO error entry. This + * can either be a frame which is free, is being uploaded, + * or has completed the upload but didn't have an entry + * in the TX_STAT_FIFO register yet. + */ + tx_queue_for_each(rt2x00dev, queue) { + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || + !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + break; + + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + } + } +} + +static void rt2800usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0); + + rt2x00usb_kill_tx_queue(queue); +} + +/* * RX control handlers */ static void rt2800usb_fill_rxdone(struct queue_entry *entry, @@ -514,6 +479,11 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + /* + * Overwrite TX done handler + */ + PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone); + return 0; } @@ -549,6 +519,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = { .regbusy_read = rt2x00usb_regbusy_read, .drv_write_firmware = rt2800usb_write_firmware, .drv_init_registers = rt2800usb_init_registers, + .drv_get_txwi = rt2800usb_get_txwi, }; static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { @@ -566,11 +537,11 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_tuner = rt2800_link_tuner, .watchdog = rt2x00usb_watchdog, .write_tx_desc = rt2800usb_write_tx_desc, - .write_tx_data = rt2800usb_write_tx_data, + .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, .get_tx_data_len = rt2800usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt2800usb_kill_tx_queue, .fill_rxdone = rt2800usb_fill_rxdone, .config_shared_key = rt2800_config_shared_key, .config_pairwise_key = rt2800_config_pairwise_key, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c21af38cc5af..0ae942cb66df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> <http://rt2x00.serialmonkey.com> @@ -212,8 +213,9 @@ struct channel_info { unsigned int flags; #define GEOGRAPHY_ALLOWED 0x00000001 - short tx_power1; - short tx_power2; + short max_power; + short default_power1; + short default_power2; }; /* @@ -558,18 +560,15 @@ struct rt2x00lib_ops { /* * TX control handlers */ - void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, + void (*write_tx_desc) (struct queue_entry *entry, struct txentry_desc *txdesc); void (*write_tx_data) (struct queue_entry *entry, struct txentry_desc *txdesc); void (*write_beacon) (struct queue_entry *entry, struct txentry_desc *txdesc); int (*get_tx_data_len) (struct queue_entry *entry); - void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue); - void (*kill_tx_queue) (struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue); + void (*kick_tx_queue) (struct data_queue *queue); + void (*kill_tx_queue) (struct data_queue *queue); /* * RX control handlers @@ -698,6 +697,7 @@ struct rt2x00_dev { struct ieee80211_hw *hw; struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; enum ieee80211_band curr_band; + int curr_freq; /* * If enabled, the debugfs interface structures @@ -850,11 +850,6 @@ struct rt2x00_dev { struct ieee80211_low_level_stats low_level_stats; /* - * RX configuration information. - */ - struct ieee80211_rx_status rx_status; - - /* * Scheduled work. * NOTE: intf_work will use ieee80211_iterate_active_interfaces() * which means it cannot be placed on the hw->workqueue @@ -862,6 +857,12 @@ struct rt2x00_dev { */ struct work_struct intf_work; + /** + * Scheduled work for TX/RX done handling (USB devices) + */ + struct work_struct rxdone_work; + struct work_struct txdone_work; + /* * Data queue arrays for RX, TX and Beacon. * The Beacon array also contains the Atim queue @@ -1069,8 +1070,10 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, */ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_dmadone(struct queue_entry *entry); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); +void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status); void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 953dc4f2c6af..34f34fa7f53a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -126,11 +126,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * ANTENNA_SW_DIVERSITY state to the driver. * If that happens, fallback to hardware defaults, * or our own default. - * If diversity handling is active for a particular antenna, - * we shouldn't overwrite that antenna. - * The calls to rt2x00lib_config_antenna_check() - * might have caused that we restore back to the already - * active setting. If that has happened we can quit. */ if (!(ant->flags & ANTENNA_RX_DIVERSITY)) config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); @@ -142,9 +137,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, else config.tx = active->tx; - if (config.rx == active->rx && config.tx == active->tx) - return; - /* * Antenna setup changes require the RX to be disabled, * else the changes will be ignored by the device. @@ -209,10 +201,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00link_reset_tuner(rt2x00dev, false); rt2x00dev->curr_band = conf->channel->band; + rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; rt2x00dev->short_retry = conf->short_frame_max_tx_count; rt2x00dev->long_retry = conf->long_frame_max_tx_count; - - rt2x00dev->rx_status.band = conf->channel->band; - rt2x00dev->rx_status.freq = conf->channel->center_freq; } diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 583dacd8d241..5e9074bf2b8e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -31,15 +31,14 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) { - switch (key->alg) { - case ALG_WEP: - if (key->keylen == WLAN_KEY_LEN_WEP40) - return CIPHER_WEP64; - else - return CIPHER_WEP128; - case ALG_TKIP: + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return CIPHER_WEP64; + case WLAN_CIPHER_SUITE_WEP104: + return CIPHER_WEP128; + case WLAN_CIPHER_SUITE_TKIP: return CIPHER_TKIP; - case ALG_CCMP: + case WLAN_CIPHER_SUITE_CCMP: return CIPHER_AES; default: return CIPHER_NONE; @@ -95,7 +94,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, overhead += key->iv_len; if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { - if (key->alg == ALG_TKIP) + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) overhead += 8; } diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index b0498e7e7aae..b8cf45c4e9f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -333,12 +333,12 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, if (*offset) return 0; - data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL); + data = kcalloc(lines, MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return -ENOMEM; temp = data + - sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n"); + sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n"); queue_for_each(intf->rt2x00dev, queue) { spin_lock_irqsave(&queue->lock, irqflags); @@ -346,8 +346,8 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, queue->count, queue->limit, queue->length, queue->index[Q_INDEX], - queue->index[Q_INDEX_DONE], - queue->index[Q_INDEX_CRYPTO]); + queue->index[Q_INDEX_DMA_DONE], + queue->index[Q_INDEX_DONE]); spin_unlock_irqrestore(&queue->lock, irqflags); } @@ -481,6 +481,9 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ if (index >= debug->__name.word_count) \ return -EINVAL; \ \ + if (length > sizeof(line)) \ + return -EINVAL; \ + \ if (copy_from_user(line, buf, length)) \ return -EFAULT; \ \ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 585e8166f22a..053fdd3bd720 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com> <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -250,6 +251,12 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); +void rt2x00lib_dmadone(struct queue_entry *entry) +{ + rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); +} +EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); + void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc) { @@ -383,15 +390,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * send the status report back. */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) - /* - * Only PCI and SOC devices process the tx status in process - * context. Hence use ieee80211_tx_status for PCI and SOC - * devices and stick to ieee80211_tx_status_irqsafe for USB. - */ - if (rt2x00_is_usb(rt2x00dev)) - ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); - else - ieee80211_tx_status(rt2x00dev->hw, entry->skb); + ieee80211_tx_status(rt2x00dev->hw, entry->skb); else dev_kfree_skb_any(entry->skb); @@ -403,7 +402,6 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->clear_entry(entry); - clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* @@ -416,6 +414,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); +void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) +{ + struct txdone_entry_desc txdesc; + + txdesc.flags = 0; + __set_bit(status, &txdesc.flags); + txdesc.retry = 0; + + rt2x00lib_txdone(entry, &txdesc); +} +EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); + static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct rxdone_entry_desc *rxdesc) { @@ -460,9 +470,13 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, { struct rxdone_entry_desc rxdesc; struct sk_buff *skb; - struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; + struct ieee80211_rx_status *rx_status; unsigned int header_length; int rate_idx; + + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + goto submit_entry; + /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. @@ -527,39 +541,32 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, */ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); rt2x00debug_update_crypto(rt2x00dev, &rxdesc); + rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); + /* + * Initialize RX status information, and send frame + * to mac80211. + */ + rx_status = IEEE80211_SKB_RXCB(entry->skb); rx_status->mactime = rxdesc.timestamp; + rx_status->band = rt2x00dev->curr_band; + rx_status->freq = rt2x00dev->curr_freq; rx_status->rate_idx = rate_idx; rx_status->signal = rxdesc.rssi; rx_status->flag = rxdesc.flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; - /* - * Send frame to mac80211 & debugfs. - * mac80211 will clean up the skb structure. - */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); - memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); - - /* - * Currently only PCI and SOC devices handle rx interrupts in process - * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni - * for PCI and SOC devices. - */ - if (rt2x00_is_usb(rt2x00dev)) - ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); - else - ieee80211_rx_ni(rt2x00dev->hw, entry->skb); + ieee80211_rx_ni(rt2x00dev->hw, entry->skb); /* * Replace the skb with the freshly allocated one. */ entry->skb = skb; - entry->flags = 0; +submit_entry: rt2x00dev->ops->lib->clear_entry(entry); - rt2x00queue_index_inc(entry->queue, Q_INDEX); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); } EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); @@ -710,7 +717,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, for (i = 0; i < spec->num_channels; i++) { rt2x00lib_channel(&channels[i], spec->channels[i].channel, - spec->channels_info[i].tx_power1, i); + spec->channels_info[i].max_power, i); } /* @@ -1017,6 +1024,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); + cancel_work_sync(&rt2x00dev->rxdone_work); + cancel_work_sync(&rt2x00dev->txdone_work); /* * Uninitialize device. diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index b818a43c4672..f0e1eb72befc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -63,6 +63,9 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", fw->data[fw->size - 4], fw->data[fw->size - 3]); + snprintf(rt2x00dev->hw->wiphy->fw_version, + sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d", + fw->data[fw->size - 4], fw->data[fw->size - 3]); retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size); switch (retval) { diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index c004cd3a8847..ad3c7ff4837b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -54,6 +54,16 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, */ if (txrate->flags & IEEE80211_TX_RC_MCS) { txdesc->mcs = txrate->idx; + + /* + * MIMO PS should be set to 1 for STA's using dynamic SM PS + * when using more then one tx stream (>MCS7). + */ + if (tx_info->control.sta && txdesc->mcs > 7 && + (tx_info->control.sta->ht_cap.cap & + (WLAN_HT_CAP_SM_PS_DYNAMIC << + IEEE80211_HT_CAP_SM_PS_SHIFT))) + __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); } else { txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index a3401d301058..eede99939db9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com> Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> <http://rt2x00.serialmonkey.com> @@ -311,7 +312,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Initialize information from queue */ - txdesc->queue = entry->queue->qid; + txdesc->qid = entry->queue->qid; txdesc->cw_min = entry->queue->cw_min; txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; @@ -448,15 +449,14 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc) { struct data_queue *queue = entry->queue; - struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc); /* * All processing on the frame has been completed, this means * it is now ready to be dumped to userspace through debugfs. */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); + rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb); } static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, @@ -476,7 +476,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, */ if (rt2x00queue_threshold(queue) || !test_bit(ENTRY_TXD_BURST, &txdesc->flags)) - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); + rt2x00dev->ops->lib->kick_tx_queue(queue); } int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, @@ -590,7 +590,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, intf->beacon->skb = NULL; if (!enable_beacon) { - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); + rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue); mutex_unlock(&intf->beacon_skb_mutex); return 0; } @@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, return 0; } +void rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, + void (*fn)(struct queue_entry *entry)) +{ + unsigned long irqflags; + unsigned int index_start; + unsigned int index_end; + unsigned int i; + + if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) { + ERROR(queue->rt2x00dev, + "Entry requested from invalid index range (%d - %d)\n", + start, end); + return; + } + + /* + * Only protect the range we are going to loop over, + * if during our loop a extra entry is set to pending + * it should not be kicked during this run, since it + * is part of another TX operation. + */ + spin_lock_irqsave(&queue->lock, irqflags); + index_start = queue->index[start]; + index_end = queue->index[end]; + spin_unlock_irqrestore(&queue->lock, irqflags); + + /* + * Start from the TX done pointer, this guarentees that we will + * send out all frames in the correct order. + */ + if (index_start < index_end) { + for (i = index_start; i < index_end; i++) + fn(&queue->entries[i]); + } else { + for (i = index_start; i < queue->limit; i++) + fn(&queue->entries[i]); + + for (i = 0; i < index_end; i++) + fn(&queue->entries[i]); + } +} +EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { @@ -686,13 +731,13 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) if (queue->index[index] >= queue->limit) queue->index[index] = 0; + queue->last_action[index] = jiffies; + if (index == Q_INDEX) { queue->length++; - queue->last_index = jiffies; } else if (index == Q_INDEX_DONE) { queue->length--; queue->count++; - queue->last_index_done = jiffies; } spin_unlock_irqrestore(&queue->lock, irqflags); @@ -701,14 +746,17 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) static void rt2x00queue_reset(struct data_queue *queue) { unsigned long irqflags; + unsigned int i; spin_lock_irqsave(&queue->lock, irqflags); queue->count = 0; queue->length = 0; - queue->last_index = jiffies; - queue->last_index_done = jiffies; - memset(queue->index, 0, sizeof(queue->index)); + + for (i = 0; i < Q_INDEX_MAX; i++) { + queue->index[i] = 0; + queue->last_action[i] = jiffies; + } spin_unlock_irqrestore(&queue->lock, irqflags); } @@ -718,7 +766,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; txall_queue_for_each(rt2x00dev, queue) - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid); + rt2x00dev->ops->lib->kill_tx_queue(queue); } void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) @@ -730,9 +778,9 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00queue_reset(queue); for (i = 0; i < queue->limit; i++) { - queue->entries[i].flags = 0; - rt2x00dev->ops->lib->clear_entry(&queue->entries[i]); + if (queue->qid == QID_RX) + rt2x00queue_index_inc(queue, Q_INDEX); } } } @@ -755,7 +803,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, * Allocate all queue entries. */ entry_size = sizeof(*entries) + qdesc->priv_size; - entries = kzalloc(queue->limit * entry_size, GFP_KERNEL); + entries = kcalloc(queue->limit, entry_size, GFP_KERNEL); if (!entries) return -ENOMEM; @@ -891,7 +939,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim; - queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); + queue = kcalloc(rt2x00dev->data_queues, sizeof(*queue), GFP_KERNEL); if (!queue) { ERROR(rt2x00dev, "Queue allocation failed.\n"); return -ENOMEM; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 191e7775a9c0..d81d85f34866 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com> <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -268,6 +268,7 @@ struct txdone_entry_desc { * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU. * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth. * @ENTRY_TXD_HT_SHORT_GI: Use short GI. + * @ENTRY_TXD_HT_MIMO_PS: The receiving STA is in dynamic SM PS mode. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, @@ -286,6 +287,7 @@ enum txentry_desc_flags { ENTRY_TXD_HT_AMPDU, ENTRY_TXD_HT_BW_40, ENTRY_TXD_HT_SHORT_GI, + ENTRY_TXD_HT_MIMO_PS, }; /** @@ -294,7 +296,7 @@ enum txentry_desc_flags { * Summary of information for the frame descriptor before sending a TX frame. * * @flags: Descriptor flags (See &enum queue_entry_flags). - * @queue: Queue identification (See &enum data_queue_qid). + * @qid: Queue identification (See &enum data_queue_qid). * @length: Length of the entire frame. * @header_length: Length of 802.11 header. * @length_high: PLCP length high word. @@ -320,7 +322,7 @@ enum txentry_desc_flags { struct txentry_desc { unsigned long flags; - enum data_queue_qid queue; + enum data_queue_qid qid; u16 length; u16 header_length; @@ -358,17 +360,17 @@ struct txentry_desc { * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data * transfer (either TX or RX depending on the queue). The entry should * only be touched after the device has signaled it is done with it. - * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data - * encryption or decryption. The entry should only be touched after - * the device has signaled it is done with it. * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting * for the signal to start sending. + * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured + * while transfering the data to the hardware. No TX status report will + * be expected from the hardware. */ enum queue_entry_flags { ENTRY_BCN_ASSIGNED, ENTRY_OWNER_DEVICE_DATA, - ENTRY_OWNER_DEVICE_CRYPTO, ENTRY_DATA_PENDING, + ENTRY_DATA_IO_FAILED }; /** @@ -399,18 +401,18 @@ struct queue_entry { * * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is * owned by the hardware then the queue is considered to be full. + * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been + * transfered to the hardware. * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by * the hardware and for which we need to run the txdone handler. If this * entry is not owned by the hardware the queue is considered to be empty. - * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription - * will be completed by the hardware next. * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size * of the index array. */ enum queue_index { Q_INDEX, + Q_INDEX_DMA_DONE, Q_INDEX_DONE, - Q_INDEX_CRYPTO, Q_INDEX_MAX, }; @@ -446,13 +448,12 @@ struct data_queue { enum data_queue_qid qid; spinlock_t lock; - unsigned long last_index; - unsigned long last_index_done; unsigned int count; unsigned short limit; unsigned short threshold; unsigned short length; unsigned short index[Q_INDEX_MAX]; + unsigned long last_action[Q_INDEX_MAX]; unsigned short txop; unsigned short aifs; @@ -565,6 +566,22 @@ struct data_queue_desc { queue_loop(__entry, (__dev)->tx, queue_end(__dev)) /** + * rt2x00queue_for_each_entry - Loop through all entries in the queue + * @queue: Pointer to @data_queue + * @start: &enum queue_index Pointer to start index + * @end: &enum queue_index Pointer to end index + * @fn: The function to call for each &struct queue_entry + * + * This will walk through all entries in the queue, in chronological + * order. This means it will start at the current @start pointer + * and will walk through the queue until it reaches the @end pointer. + */ +void rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, + void (*fn)(struct queue_entry *entry)); + +/** * rt2x00queue_empty - Check if the queue is empty. * @queue: Queue to check if empty. */ @@ -601,12 +618,23 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00queue_timeout - Check if a timeout occured for this queue + * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts * @queue: Queue to check. */ static inline int rt2x00queue_timeout(struct data_queue *queue) { - return time_after(queue->last_index, queue->last_index_done + (HZ / 10)); + return time_after(queue->last_action[Q_INDEX_DMA_DONE], + queue->last_action[Q_INDEX_DONE] + (HZ / 10)); +} + +/** + * rt2x00queue_timeout - Check if a timeout occured for DMA transfers + * @queue: Queue to check. + */ +static inline int rt2x00queue_dma_timeout(struct data_queue *queue) +{ + return time_after(queue->last_action[Q_INDEX], + queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); } /** diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index ff3a36622d1b..4c5ae3d45625 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + Copyright (C) 2010 Willow Garage <http://www.willowgarage.com> + Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com> <http://rt2x00.serialmonkey.com> This program is free software; you can redistribute it and/or modify @@ -167,137 +168,142 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); /* * TX data handlers. */ -static void rt2x00usb_interrupt_txdone(struct urb *urb) +static void rt2x00usb_work_txdone_entry(struct queue_entry *entry) { - struct queue_entry *entry = (struct queue_entry *)urb->context; - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct txdone_entry_desc txdesc; - - if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) - return; - /* - * Obtain the status about this packet. - * Note that when the status is 0 it does not mean the + * If the transfer to hardware succeeded, it does not mean the * frame was send out correctly. It only means the frame * was succesfully pushed to the hardware, we have no * way to determine the transmission status right now. * (Only indirectly by looking at the failed TX counters * in the register). */ - txdesc.flags = 0; - if (!urb->status) - __set_bit(TXDONE_UNKNOWN, &txdesc.flags); + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); else - __set_bit(TXDONE_FAILURE, &txdesc.flags); - txdesc.retry = 0; - - rt2x00lib_txdone(entry, &txdesc); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); } -static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +static void rt2x00usb_work_txdone(struct work_struct *work) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); - struct queue_entry_priv_usb *entry_priv = entry->priv_data; - u32 length; + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, txdone_work); + struct data_queue *queue; + struct queue_entry *entry; - if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) { - /* - * USB devices cannot blindly pass the skb->len as the - * length of the data to usb_fill_bulk_urb. Pass the skb - * to the driver to determine what the length should be. - */ - length = rt2x00dev->ops->lib->get_tx_data_len(entry); + tx_queue_for_each(rt2x00dev, queue) { + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), - entry->skb->data, length, - rt2x00usb_interrupt_txdone, entry); + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + break; - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + rt2x00usb_work_txdone_entry(entry); + } } } -void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2x00usb_interrupt_txdone(struct urb *urb) { - struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); - unsigned long irqflags; - unsigned int index; - unsigned int index_done; - unsigned int i; + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + + if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; /* - * Only protect the range we are going to loop over, - * if during our loop a extra entry is set to pending - * it should not be kicked during this run, since it - * is part of another TX operation. + * Report the frame as DMA done */ - spin_lock_irqsave(&queue->lock, irqflags); - index = queue->index[Q_INDEX]; - index_done = queue->index[Q_INDEX_DONE]; - spin_unlock_irqrestore(&queue->lock, irqflags); + rt2x00lib_dmadone(entry); /* - * Start from the TX done pointer, this guarentees that we will - * send out all frames in the correct order. + * Check if the frame was correctly uploaded */ - if (index_done < index) { - for (i = index_done; i < index; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); - } else { - for (i = index_done; i < queue->limit; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); + if (urb->status) + __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); - for (i = 0; i < index; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); - } + /* + * Schedule the delayed work for reading the TX status + * from the device. + */ + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); +} + +static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + u32 length; + + if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + return; + + /* + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. + */ + length = rt2x00dev->ops->lib->get_tx_data_len(entry); + + usb_fill_bulk_urb(entry_priv->urb, usb_dev, + usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), + entry->skb->data, length, + rt2x00usb_interrupt_txdone, entry); + + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); +} + +void rt2x00usb_kick_tx_queue(struct data_queue *queue) +{ + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00usb_kick_tx_entry); } EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue); -void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2x00usb_kill_tx_entry(struct queue_entry *entry) { - struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); - struct queue_entry_priv_usb *entry_priv; - struct queue_entry_priv_usb_bcn *bcn_priv; - unsigned int i; - bool kill_guard; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; + + if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; + + usb_kill_urb(entry_priv->urb); /* - * When killing the beacon queue, we must also kill - * the beacon guard byte. + * Kill guardian urb (if required by driver). */ - kill_guard = - (qid == QID_BEACON) && - (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)); + if ((entry->queue->qid == QID_BEACON) && + (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) + usb_kill_urb(bcn_priv->guardian_urb); /* - * Cancel all entries. + * We need a short delay here to wait for + * the URB to be canceled */ - for (i = 0; i < queue->limit; i++) { - entry_priv = queue->entries[i].priv_data; - usb_kill_urb(entry_priv->urb); + do { + udelay(100); + } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)); +} - /* - * Kill guardian urb (if required by driver). - */ - if (kill_guard) { - bcn_priv = queue->entries[i].priv_data; - usb_kill_urb(bcn_priv->guardian_urb); - } - } +void rt2x00usb_kill_tx_queue(struct data_queue *queue) +{ + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00usb_kill_tx_entry); } EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue); -static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) +static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) { - struct queue_entry_priv_usb *entry_priv; + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; unsigned short threshold = queue->threshold; - WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid); + WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," + " invoke forced forced reset", queue->qid); /* * Temporarily disable the TX queue, this will force mac80211 @@ -307,20 +313,33 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) * queue from being enabled during the txdone handler. */ queue->threshold = queue->limit; - ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid); + ieee80211_stop_queue(rt2x00dev->hw, queue->qid); /* - * Reset all currently uploaded TX frames. + * Kill all entries in the queue, afterwards we need to + * wait a bit for all URBs to be cancelled. */ - while (!rt2x00queue_empty(queue)) { - entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data; - usb_kill_urb(entry_priv->urb); + rt2x00usb_kill_tx_queue(queue); - /* - * We need a short delay here to wait for - * the URB to be canceled and invoked the tx_done handler. - */ - udelay(200); + /* + * In case that a driver has overriden the txdone_work + * function, we invoke the TX done through there. + */ + rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work); + + /* + * Security measure: if the driver did override the + * txdone_work function, and the hardware did arrive + * in a state which causes it to malfunction, it is + * possible that the driver couldn't handle the txdone + * event correctly. So after giving the driver the + * chance to cleanup, we now force a cleanup of any + * leftovers. + */ + if (!rt2x00queue_empty(queue)) { + WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," + " status handling failed, invoke hard reset", queue->qid); + rt2x00usb_work_txdone(&rt2x00dev->txdone_work); } /* @@ -328,7 +347,15 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) * queue again. */ queue->threshold = threshold; - ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); + ieee80211_wake_queue(rt2x00dev->hw, queue->qid); +} + +static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) +{ + WARNING(queue->rt2x00dev, "TX queue %d status timed out," + " invoke forced tx handler", queue->qid); + + ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work); } void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) @@ -336,8 +363,10 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { + if (rt2x00queue_dma_timeout(queue)) + rt2x00usb_watchdog_tx_dma(queue); if (rt2x00queue_timeout(queue)) - rt2x00usb_watchdog_reset_tx(queue); + rt2x00usb_watchdog_tx_status(queue); } } EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); @@ -345,38 +374,62 @@ EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); /* * RX data handlers. */ +static void rt2x00usb_work_rxdone(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, rxdone_work); + struct queue_entry *entry; + struct skb_frame_desc *skbdesc; + u8 rxd[32]; + + while (!rt2x00queue_empty(rt2x00dev->rx)) { + entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE); + + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + break; + + /* + * Fill in desc fields of the skb descriptor + */ + skbdesc = get_skb_frame_desc(entry->skb); + skbdesc->desc = rxd; + skbdesc->desc_len = entry->queue->desc_size; + + /* + * Send the frame to rt2x00lib for further processing. + */ + rt2x00lib_rxdone(rt2x00dev, entry); + } +} + static void rt2x00usb_interrupt_rxdone(struct urb *urb) { struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - u8 rxd[32]; - if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* - * Check if the received data is simply too small - * to be actually valid, or if the urb is signaling - * a problem. + * Report the frame as DMA done */ - if (urb->actual_length < entry->queue->desc_size || urb->status) { - set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(urb, GFP_ATOMIC); - return; - } + rt2x00lib_dmadone(entry); /* - * Fill in desc fields of the skb descriptor + * Check if the received data is simply too small + * to be actually valid, or if the urb is signaling + * a problem. */ - skbdesc->desc = rxd; - skbdesc->desc_len = entry->queue->desc_size; + if (urb->actual_length < entry->queue->desc_size || urb->status) + __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); /* - * Send the frame to rt2x00lib for further processing. + * Schedule the delayed work for reading the RX status + * from the device. */ - rt2x00lib_rxdone(rt2x00dev, entry); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); } /* @@ -391,7 +444,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) * The USB version of kill_tx_queue also works * on the RX queue. */ - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX); + rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx); } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); @@ -405,6 +458,8 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) struct queue_entry_priv_usb *entry_priv = entry->priv_data; int pipe; + entry->flags = 0; + if (entry->queue->qid == QID_RX) { pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint); usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe, @@ -413,8 +468,6 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(entry_priv->urb, GFP_ATOMIC); - } else { - entry->flags = 0; } } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); @@ -659,6 +712,9 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); + INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); + INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); + retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) goto exit_free_device; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index d3d3ddc40875..c2d997f67b3e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -379,25 +379,21 @@ struct queue_entry_priv_usb_bcn { /** * rt2x00usb_kick_tx_queue - Kick data queue - * @rt2x00dev: Pointer to &struct rt2x00_dev - * @qid: Data queue to kick + * @queue: Data queue to kick * * This will walk through all entries of the queue and push all pending * frames to the hardware as a single burst. */ -void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid); +void rt2x00usb_kick_tx_queue(struct data_queue *queue); /** * rt2x00usb_kill_tx_queue - Kill data queue - * @rt2x00dev: Pointer to &struct rt2x00_dev - * @qid: Data queue to kill + * @queue: Data queue to kill * * This will walk through all entries of the queue and kill all * previously kicked frames before they can be send. */ -void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid); +void rt2x00usb_kill_tx_queue(struct data_queue *queue); /** * rt2x00usb_watchdog - Watchdog for USB communication diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index e539c6cb636f..3a7759929190 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1050,7 +1050,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { @@ -1766,12 +1766,11 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt61pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1779,7 +1778,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); @@ -1802,15 +1801,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, } rt2x00_desc_read(txd, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, skbdesc->entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(rt2x00dev->tx_power)); + TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); - if (txdesc->queue != QID_BEACON) { + if (txdesc->qid != QID_BEACON) { rt2x00_desc_read(txd, 6, &word); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); @@ -1857,7 +1856,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ skbdesc->desc = txd; skbdesc->desc_len = - (txdesc->queue == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE; + (txdesc->qid == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE; } /* @@ -1882,7 +1881,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt61pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1918,34 +1917,34 @@ static void rt61pci_write_beacon(struct queue_entry *entry, entry->skb = NULL; } -static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt61pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } -static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt61pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); return; } rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } @@ -1972,7 +1971,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { if (lna == 3 || lna == 2) offset += 10; } @@ -2107,11 +2106,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) "TX status report missed for entry %d\n", entry_done->entry_idx); - txdesc.flags = 0; - __set_bit(TXDONE_UNKNOWN, &txdesc.flags); - txdesc.retry = 0; - - rt2x00lib_txdone(entry_done, &txdesc); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); } @@ -2654,20 +2649,24 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } } return 0; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index aa9de18fd410..87fb2201537b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -929,7 +929,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; @@ -1426,12 +1426,11 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt73usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txd = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txd = (__le32 *) entry->skb->data; u32 word; /* @@ -1464,7 +1463,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); @@ -1487,7 +1486,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(rt2x00dev->tx_power)); + TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); @@ -1526,7 +1525,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt73usb_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1574,6 +1573,14 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry) return length; } +static void rt73usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0); + + rt2x00usb_kill_tx_queue(queue); +} + /* * RX control handlers */ @@ -1597,7 +1604,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { if (lna == 3 || lna == 2) offset += 10; @@ -2084,20 +2091,24 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Create channel information array */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } } return 0; @@ -2259,7 +2270,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .write_beacon = rt73usb_write_beacon, .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt73usb_kill_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, .config_shared_key = rt73usb_config_shared_key, .config_pairwise_key = rt73usb_config_pairwise_key, |