diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2800lib.c')
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 625 | 
1 files changed, 533 insertions, 92 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b66e0fd8f0f..5f00e00789d 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,8 @@ 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_QUEUE, txdesc->qid); +	rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1);  	rt2x00_desc_write(txwi, 1, word);  	/* @@ -478,9 +497,9 @@ 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) +static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)  {  	int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);  	int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); @@ -490,7 +509,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 +588,181 @@ 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_entry(struct queue_entry *entry, u32 status) +{ +	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; +	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); +	struct txdone_entry_desc txdesc; +	u32 word; +	u16 mcs, real_mcs; +	int aggr, ampdu; +	__le32 *txwi; + +	/* +	 * 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); +	ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); + +	real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); +	aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE); + +	/* +	 * If a frame was meant to be sent as a single non-aggregated MPDU +	 * but ended up in an aggregate the used tx rate doesn't correlate +	 * with the one specified in the TXWI as the whole aggregate is sent +	 * with the same rate. +	 * +	 * For example: two frames are sent to rt2x00, the first one sets +	 * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0 +	 * and requests MCS15. If the hw aggregates both frames into one +	 * AMDPU the tx status for both frames will contain MCS7 although +	 * the frame was sent successfully. +	 * +	 * Hence, replace the requested rate with the real tx rate to not +	 * confuse the rate control algortihm by providing clearly wrong +	 * data. +	 */ +	if (aggr == 1 && ampdu == 0 && real_mcs != mcs) { +		skbdesc->tx_rate_idx = real_mcs; +		mcs = real_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(status, 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_entry); + +void rt2800_txdone(struct rt2x00_dev *rt2x00dev) +{ +	struct data_queue *queue; +	struct queue_entry *entry; +	u32 reg; +	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_QUEUE); +		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; +		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; + +		rt2800_txdone_entry(entry, reg); +	} +} +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 +794,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. @@ -871,8 +1065,12 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,  		 * 1 pairwise key is possible per AID, this means that the AID  		 * equals our hw_key_idx. Make sure the WCID starts _after_ the  		 * last possible shared key entry. +		 * +		 * Since parts of the pairwise key table might be shared with +		 * the beacon frame buffers 6 & 7 we should only write into the +		 * first 222 entries.  		 */ -		if (crypto->aid > (256 - 32)) +		if (crypto->aid > (222 - 32))  			return -ENOSPC;  		key->hw_key_idx = 32 + crypto->aid; @@ -975,19 +1173,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)); @@ -995,38 +1197,149 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,  }  EXPORT_SYMBOL_GPL(rt2800_config_intf); -void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp) +static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, +				    struct rt2x00lib_erp *erp)  { +	bool any_sta_nongf = !!(erp->ht_opmode & +				IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); +	u8 protection = erp->ht_opmode & IEEE80211_HT_OP_MODE_PROTECTION; +	u8 mm20_mode, mm40_mode, gf20_mode, gf40_mode; +	u16 mm20_rate, mm40_rate, gf20_rate, gf40_rate;  	u32 reg; -	rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); -	rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, -			   !!erp->short_preamble); -	rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, -			   !!erp->short_preamble); -	rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); +	/* default protection rate for HT20: OFDM 24M */ +	mm20_rate = gf20_rate = 0x4004; -	rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); -	rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, -			   erp->cts_protection ? 2 : 0); -	rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); +	/* default protection rate for HT40: duplicate OFDM 24M */ +	mm40_rate = gf40_rate = 0x4084; -	rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, -				 erp->basic_rates); -	rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); +	switch (protection) { +	case IEEE80211_HT_OP_MODE_PROTECTION_NONE: +		/* +		 * All STAs in this BSS are HT20/40 but there might be +		 * STAs not supporting greenfield mode. +		 * => Disable protection for HT transmissions. +		 */ +		mm20_mode = mm40_mode = gf20_mode = gf40_mode = 0; -	rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); -	rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); -	rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); +		break; +	case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: +		/* +		 * All STAs in this BSS are HT20 or HT20/40 but there +		 * might be STAs not supporting greenfield mode. +		 * => Protect all HT40 transmissions. +		 */ +		mm20_mode = gf20_mode = 0; +		mm40_mode = gf40_mode = 2; -	rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); -	rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); -	rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); +		break; +	case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: +		/* +		 * Nonmember protection: +		 * According to 802.11n we _should_ protect all +		 * HT transmissions (but we don't have to). +		 * +		 * But if cts_protection is enabled we _shall_ protect +		 * all HT transmissions using a CCK rate. +		 * +		 * And if any station is non GF we _shall_ protect +		 * GF transmissions. +		 * +		 * We decide to protect everything +		 * -> fall through to mixed mode. +		 */ +	case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: +		/* +		 * Legacy STAs are present +		 * => Protect all HT transmissions. +		 */ +		mm20_mode = mm40_mode = gf20_mode = gf40_mode = 2; -	rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); -	rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, -			   erp->beacon_int * 16); -	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); +		/* +		 * If erp protection is needed we have to protect HT +		 * transmissions with CCK 11M long preamble. +		 */ +		if (erp->cts_protection) { +			/* don't duplicate RTS/CTS in CCK mode */ +			mm20_rate = mm40_rate = 0x0003; +			gf20_rate = gf40_rate = 0x0003; +		} +		break; +	}; + +	/* check for STAs not supporting greenfield mode */ +	if (any_sta_nongf) +		gf20_mode = gf40_mode = 2; + +	/* Update HT protection config */ +	rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); +	rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate); +	rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode); +	rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); + +	rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); +	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate); +	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode); +	rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); + +	rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); +	rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate); +	rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode); +	rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); + +	rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); +	rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate); +	rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode); +	rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); +} + +void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, +		       u32 changed) +{ +	u32 reg; + +	if (changed & BSS_CHANGED_ERP_PREAMBLE) { +		rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); +		rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, +				   !!erp->short_preamble); +		rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, +				   !!erp->short_preamble); +		rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); +	} + +	if (changed & BSS_CHANGED_ERP_CTS_PROT) { +		rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); +		rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, +				   erp->cts_protection ? 2 : 0); +		rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); +	} + +	if (changed & BSS_CHANGED_BASIC_RATES) { +		rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, +					 erp->basic_rates); +		rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); +	} + +	if (changed & BSS_CHANGED_ERP_SLOT) { +		rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); +		rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, +				   erp->slot_time); +		rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + +		rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); +		rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); +		rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); +	} + +	if (changed & BSS_CHANGED_BEACON_INT) { +		rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); +		rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, +				   erp->beacon_int * 16); +		rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); +	} + +	if (changed & BSS_CHANGED_HT) +		rt2800_config_ht_opmode(rt2x00dev, erp);  }  EXPORT_SYMBOL_GPL(rt2800_config_erp); @@ -1120,27 +1433,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 +1489,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 +1517,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 +1852,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; @@ -1728,8 +2044,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)  	rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®);  	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); -	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, -			   !rt2x00_is_usb(rt2x00dev)); +	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0);  	rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1);  	rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);  	rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); @@ -1886,6 +2201,14 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)  	rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg);  	/* +	 * Do not force the BA window size, we use the TXWI to set it +	 */ +	rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, ®); +	rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0); +	rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0); +	rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg); + +	/*  	 * We must clear the error counters.  	 * These registers are cleared on read,  	 * so we may pass a useless variable to store the value. @@ -1906,7 +2229,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 +2271,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 +2366,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 +2427,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 +2681,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 +2930,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 +3176,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;  	/* @@ -2770,11 +3192,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)  	 * Initialize all hw fields.  	 */  	rt2x00dev->hw->flags = -	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |  	    IEEE80211_HW_SIGNAL_DBM |  	    IEEE80211_HW_SUPPORTS_PS |  	    IEEE80211_HW_PS_NULLFUNC_STACK |  	    IEEE80211_HW_AMPDU_AGGREGATION; +	/* +	 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices +	 * unless we are capable of sending the buffered frames out after the +	 * DTIM transmission using rt2x00lib_beacondone. This will send out +	 * multicast and broadcast traffic immediately instead of buffering it +	 * infinitly and thus dropping it after some time. +	 */ +	if (!rt2x00_is_usb(rt2x00dev)) +		rt2x00dev->hw->flags |= +			IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;  	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);  	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2785,12 +3216,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)  	 * As rt2800 has a global fallback table we cannot specify  	 * more then one tx rate per frame but since the hw will  	 * try several rates (based on the fallback table) we should -	 * still initialize max_rates to the maximum number of rates +	 * initialize max_report_rates to the maximum number of rates  	 * we are going to try. Otherwise mac80211 will truncate our  	 * reported tx rates and the rc algortihm will end up with  	 * incorrect data.  	 */ -	rt2x00dev->hw->max_rates = 7; +	rt2x00dev->hw->max_rates = 1; +	rt2x00dev->hw->max_report_rates = 7;  	rt2x00dev->hw->max_rate_tries = 1;  	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); @@ -2865,27 +3297,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]);  		}  	} @@ -3042,8 +3479,12 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	switch (action) {  	case IEEE80211_AMPDU_RX_START:  	case IEEE80211_AMPDU_RX_STOP: -		/* we don't support RX aggregation yet */ -		ret = -ENOTSUPP; +		/* +		 * The hw itself takes care of setting up BlockAck mechanisms. +		 * So, we only have to allow mac80211 to nagotiate a BlockAck +		 * agreement. Once that is done, the hw will BlockAck incoming +		 * AMPDUs without further setup. +		 */  		break;  	case IEEE80211_AMPDU_TX_START:  		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);  |