rt2x00: Convert AGC value from descriptor to RSSI (dBm)
authorIvo van Doorn <ivdoorn@gmail.com>
Sun, 11 Jul 2010 10:23:50 +0000 (12:23 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 12 Jul 2010 20:05:33 +0000 (16:05 -0400)
The RSSI values in the RXWI descriptor aren't true RSSI
values. Instead they are more like the AGC values similar
to rt61pci. And as such, it needs the same conversion
before it can be passed to rt2x00lib/mac80211.

This requires the struct queue_entry to be passed to
rt2800_process_rxwi rather then the skb structure which
is contained in the queue_entry. This is required to
obtain the lna_gain information from the rt2x00_dev structure.

This fixes connection problems when using wpa_supplicant
which would try to connect to the worst AP's rather then the
best ones.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c

index 3cda22931876779b4c6524449bf20c6d2a67a3b7..edd3734b8b32037acd2e798fdb5ea5686c825e89 100644 (file)
@@ -74,7 +74,7 @@
  * Signal information.
  * Default offset is required for RSSI <-> dBm conversion.
  */
-#define DEFAULT_RSSI_OFFSET            120 /* FIXME */
+#define DEFAULT_RSSI_OFFSET            120
 
 /*
  * Register layout information.
index 9030eef2403d0ad0fec8cc6d70597bb4bd047b62..255d089e87ea9732c4b41142771ccf8310a33355 100644 (file)
@@ -325,9 +325,53 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
 }
 EXPORT_SYMBOL_GPL(rt2800_write_txwi);
 
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
+static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
 {
-       __le32 *rxwi = (__le32 *) skb->data;
+       int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
+       int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
+       int rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
+       u16 eeprom;
+       u8 offset0;
+       u8 offset1;
+       u8 offset2;
+
+       if (rt2x00dev->rx_status.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);
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+               offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
+       } else {
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
+               offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
+               offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+               offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
+       }
+
+       /*
+        * Convert the value from the descriptor into the RSSI value
+        * If the value in the descriptor is 0, it is considered invalid
+        * and the default (extremely low) rssi value is assumed
+        */
+       rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
+       rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
+       rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
+
+       /*
+        * mac80211 only accepts a single RSSI value. Calculating the
+        * average doesn't deliver a fair answer either since -60:-60 would
+        * be considered equally good as -50:-70 while the second is the one
+        * which gives less energy...
+        */
+       rssi0 = max(rssi0, rssi1);
+       return max(rssi0, rssi2);
+}
+
+void rt2800_process_rxwi(struct queue_entry *entry,
+                        struct rxdone_entry_desc *rxdesc)
+{
+       __le32 *rxwi = (__le32 *) entry->skb->data;
        u32 word;
 
        rt2x00_desc_read(rxwi, 0, &word);
@@ -358,14 +402,15 @@ void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
 
        rt2x00_desc_read(rxwi, 2, &word);
 
-       rxdesc->rssi =
-           (rt2x00_get_field32(word, RXWI_W2_RSSI0) +
-            rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
+       /*
+        * Convert descriptor AGC value to RSSI value.
+        */
+       rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
 
        /*
         * Remove RXWI descriptor from start of buffer.
         */
-       skb_pull(skb, RXWI_DESC_SIZE);
+       skb_pull(entry->skb, RXWI_DESC_SIZE);
 }
 EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
 
index 8313dbf441a5be7aac2a59fa1ce089e90d7181e4..eb3a4f50a3633c4be36f525bfd5c48e5eb0b7c99 100644 (file)
@@ -121,7 +121,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 arg0, const u8 arg1);
 
 void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
+void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
 
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
 
index 6f11760117da05fa843abe5daf4dcbee39fd2d11..faf71e2aeb640eab3e2596031a75fa41678c89a7 100644 (file)
@@ -805,7 +805,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
        /*
         * Process the RXWI structure that is at the start of the buffer.
         */
-       rt2800_process_rxwi(entry->skb, rxdesc);
+       rt2800_process_rxwi(entry, rxdesc);
 
        /*
         * Set RX IDX in register to inform hardware that we have handled
index 4f85f7b4244105132c04c1161c5785703cf7b641..f2cd37e5aea822626b5a95ecad61a2be02aa8ec4 100644 (file)
@@ -563,7 +563,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
        /*
         * Process the RXWI structure.
         */
-       rt2800_process_rxwi(entry->skb, rxdesc);
+       rt2800_process_rxwi(entry, rxdesc);
 }
 
 /*