]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
rt2x00: Fix max TX power settings
authorIvo van Doorn <ivdoorn@gmail.com>
Mon, 23 Aug 2010 17:56:07 +0000 (19:56 +0200)
committerAK <andi@firstfloor.org>
Sun, 6 Feb 2011 19:03:44 +0000 (11:03 -0800)
commit 8d1331b37d5b656a7a8e561f8e9d7661dd00c910 upstream.

During initialization each driver reads the default TX power
for each individual channel. However mac80211 only accepts the
maximum value (which is also handled as default value).

As a result, the TX power of the device was being limited to
the default value, which is often quite low compared to the
real maximum acceptable value.

This patch allows each driver to set the maximum value on a
per-channel basis which is forwarded to mac80211. The default
value will be preserved for now, in case we want to update
mac80211 to differentiate between the maximum and default txpower.

This fixes bug complaining about limited TX power values like:
https://bugzilla.kernel.org/show_bug.cgi?id=16358

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c

index ad2c98af7e9d62090dd54837206d07bcd23675a6..f57f0df45a68508d61ea46a4da57c8784ab80cf5 100644 (file)
@@ -1462,8 +1462,10 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        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;
 }
index 41da3d218c65e343b5ded898ad5cee89257e4201..fec3d9e636d1a8300cb72c9a0581f77b6bb17f80 100644 (file)
@@ -1780,12 +1780,16 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        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;
index 9ae96a626e6d0fafc6b8a633af03c75a135c5b3d..9e8b33d6d2665879ac99a379e08ab27ff3c4c478 100644 (file)
@@ -1690,12 +1690,16 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        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;
index 2aa03751c341d18848f668beb26868bdc252abb5..b72161c6aef45d4bcef2312d9e7ad8f4a4254e97 100644 (file)
@@ -1769,6 +1769,13 @@ struct mac_iveiv_entry {
 #define EEPROM_RSSI_A2_OFFSET2         FIELD16(0x00ff)
 #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.
index db4250d1c8b35cc68abfe078a10753d5ad97e198..27c13d72044dfe217d8118b9d3491eb608665344 100644 (file)
@@ -840,27 +840,27 @@ 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));
+                                  TXPOWER_A_TO_DEV(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));
+                                  TXPOWER_A_TO_DEV(info->default_power2));
        } else {
                rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power1));
+                                  TXPOWER_G_TO_DEV(info->default_power1));
                rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power2));
+                                  TXPOWER_G_TO_DEV(info->default_power2));
        }
 
        rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
@@ -900,13 +900,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);
@@ -2226,6 +2224,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);
@@ -2466,9 +2471,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;
 
        /*
@@ -2566,21 +2572,26 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        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]);
                }
        }
 
index 6c1ff4c15c8430d4288b4bb0e687d812e912d1e5..0d1ff9d7c8ba89c7f4442b67aadbcdcd00bb5acb 100644 (file)
@@ -211,8 +211,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;
 };
 
 /*
index f20d3eeeea7fe0ee4001bf3597255bab1ad9856e..f444f0bd5978a192aba47bc98cfa09f5d3e74752 100644 (file)
@@ -605,7 +605,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);
        }
 
        /*
index 6a74baf4e934b97e4ac3978341736790f18fb6e3..766032e0d9cb721fd57578035e9f315eaaf91556 100644 (file)
@@ -2605,13 +2605,17 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        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;
index 6e0d82efe9241802d8fdea54eacfe9f686437f0d..1e99a020194a209cb14840d8c4d2351b8127f3ca 100644 (file)
@@ -2092,13 +2092,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        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;