b43: Fix QoS defaults
[safe/jmp/linux-2.6] / drivers / net / wireless / b43 / main.c
index af43f03..79c25d6 100644 (file)
@@ -46,7 +46,7 @@
 #include "debugfs.h"
 #include "phy_common.h"
 #include "phy_g.h"
-#include "nphy.h"
+#include "phy_n.h"
 #include "dma.h"
 #include "pio.h"
 #include "sysfs.h"
@@ -1052,23 +1052,6 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
-/* Turn the Analog ON/OFF */
-static void b43_switch_analog(struct b43_wldev *dev, int on)
-{
-       switch (dev->phy.type) {
-       case B43_PHYTYPE_A:
-       case B43_PHYTYPE_G:
-               b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
-               break;
-       case B43_PHYTYPE_N:
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
-                             on ? 0 : 0x7FFF);
-               break;
-       default:
-               B43_WARN_ON(1);
-       }
-}
-
 void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 {
        u32 tmslow;
@@ -1091,8 +1074,12 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
        ssb_read32(dev->dev, SSB_TMSLOW);       /* flush */
        msleep(1);
 
-       /* Turn Analog ON */
-       b43_switch_analog(dev, 1);
+       /* Turn Analog ON, but only if we already know the PHY-type.
+        * This protects against very early setup where we don't know the
+        * PHY-type, yet. wireless_core_reset will be called once again later,
+        * when we know the PHY-type. */
+       if (dev->phy.ops)
+               dev->phy.ops->switch_analog(dev, 1);
 
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
        macctl &= ~B43_MACCTL_GMODE;
@@ -2694,6 +2681,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 /* This is the opposite of b43_chip_init() */
 static void b43_chip_exit(struct b43_wldev *dev)
 {
+       b43_phy_exit(dev);
        b43_gpio_cleanup(dev);
        /* firmware is released later */
 }
@@ -2730,7 +2718,8 @@ static int b43_chip_init(struct b43_wldev *dev)
        if (err)
                goto err_gpio_clean;
 
-       b43_write16(dev, 0x03E6, 0x0000);
+       /* Turn the Analog on and initialize the PHY. */
+       phy->ops->switch_analog(dev, 1);
        err = b43_phy_init(dev);
        if (err)
                goto err_gpio_clean;
@@ -2805,6 +2794,9 @@ static void b43_periodic_every60sec(struct b43_wldev *dev)
 
        if (ops->pwork_60sec)
                ops->pwork_60sec(dev);
+
+       /* Force check the TX power emission now. */
+       b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
 }
 
 static void b43_periodic_every30sec(struct b43_wldev *dev)
@@ -2835,8 +2827,6 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
        if (phy->ops->pwork_15sec)
                phy->ops->pwork_15sec(dev);
 
-       phy->ops->xmitpower(dev);
-
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
        wmb();
 }
@@ -3069,6 +3059,15 @@ static void b43_qos_params_upload(struct b43_wldev *dev,
        }
 }
 
+/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
+static const u16 b43_qos_shm_offsets[] = {
+       /* [mac80211-queue-nr] = SHM_OFFSET, */
+       [0] = B43_QOS_VOICE,
+       [1] = B43_QOS_VIDEO,
+       [2] = B43_QOS_BESTEFFORT,
+       [3] = B43_QOS_BACKGROUND,
+};
+
 /* Update the QOS parameters in hardware. */
 static void b43_qos_update(struct b43_wldev *dev)
 {
@@ -3077,14 +3076,8 @@ static void b43_qos_update(struct b43_wldev *dev)
        unsigned long flags;
        unsigned int i;
 
-       /* Mapping of mac80211 queues to b43 SHM offsets. */
-       static const u16 qos_shm_offsets[] = {
-               [0] = B43_QOS_VOICE,
-               [1] = B43_QOS_VIDEO,
-               [2] = B43_QOS_BESTEFFORT,
-               [3] = B43_QOS_BACKGROUND,
-       };
-       BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
+       BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+                    ARRAY_SIZE(wl->qos_params));
 
        b43_mac_suspend(dev);
        spin_lock_irqsave(&wl->irq_lock, flags);
@@ -3093,7 +3086,7 @@ static void b43_qos_update(struct b43_wldev *dev)
                params = &(wl->qos_params[i]);
                if (params->need_hw_update) {
                        b43_qos_params_upload(dev, &(params->p),
-                                             qos_shm_offsets[i]);
+                                             b43_qos_shm_offsets[i]);
                        params->need_hw_update = 0;
                }
        }
@@ -3107,11 +3100,42 @@ static void b43_qos_clear(struct b43_wl *wl)
        struct b43_qos_params *params;
        unsigned int i;
 
+       /* Initialize QoS parameters to sane defaults. */
+
+       BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+                    ARRAY_SIZE(wl->qos_params));
+
        for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
                params = &(wl->qos_params[i]);
 
-               memset(&(params->p), 0, sizeof(params->p));
-               params->p.aifs = -1;
+               switch (b43_qos_shm_offsets[i]) {
+               case B43_QOS_VOICE:
+                       params->p.txop = 0;
+                       params->p.aifs = 2;
+                       params->p.cw_min = 0x0001;
+                       params->p.cw_max = 0x0001;
+                       break;
+               case B43_QOS_VIDEO:
+                       params->p.txop = 0;
+                       params->p.aifs = 2;
+                       params->p.cw_min = 0x0001;
+                       params->p.cw_max = 0x0001;
+                       break;
+               case B43_QOS_BESTEFFORT:
+                       params->p.txop = 0;
+                       params->p.aifs = 3;
+                       params->p.cw_min = 0x0001;
+                       params->p.cw_max = 0x03FF;
+                       break;
+               case B43_QOS_BACKGROUND:
+                       params->p.txop = 0;
+                       params->p.aifs = 7;
+                       params->p.cw_min = 0x0001;
+                       params->p.cw_max = 0x03FF;
+                       break;
+               default:
+                       B43_WARN_ON(1);
+               }
                params->need_hw_update = 1;
        }
 }
@@ -3382,10 +3406,13 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 
        /* Adjust the desired TX power level. */
        if (conf->power_level != 0) {
-               if (conf->power_level != phy->power_level) {
-                       phy->power_level = conf->power_level;
-                       phy->ops->xmitpower(dev);
+               spin_lock_irqsave(&wl->irq_lock, flags);
+               if (conf->power_level != phy->desired_txpower) {
+                       phy->desired_txpower = conf->power_level;
+                       b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
+                                                  B43_TXPWR_IGNORE_TSSI);
                }
+               spin_unlock_irqrestore(&wl->irq_lock, flags);
        }
 
        /* Antennas for RX and management frame TX. */
@@ -3785,6 +3812,7 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
                                      struct b43_phy *phy)
 {
        phy->hardware_power_control = !!modparam_hwpctl;
+       phy->next_txpwr_check_time = jiffies;
        /* PHY TX errors counter. */
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
 }
@@ -3942,12 +3970,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
        b43_dma_free(dev);
        b43_pio_free(dev);
        b43_chip_exit(dev);
-       b43_switch_analog(dev, 0);
+       dev->phy.ops->switch_analog(dev, 0);
        if (dev->wl->current_beacon) {
                dev_kfree_skb_any(dev->wl->current_beacon);
                dev->wl->current_beacon = NULL;
        }
-       b43_phy_exit(dev);
 
        ssb_device_disable(dev->dev, 0);
        ssb_bus_may_powerdown(dev->dev->bus);
@@ -3974,24 +4001,23 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
                b43_wireless_core_reset(dev, tmp);
        }
 
+       /* Reset all data structures. */
        setup_struct_wldev_for_init(dev);
-       err = b43_phy_operations_setup(dev);
-       if (err)
-               goto err_busdown;
+       phy->ops->prepare_structs(dev);
 
        /* Enable IRQ routing to this device. */
        ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
 
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
-       if (phy->ops->prepare) {
-               err = phy->ops->prepare(dev);
+       if (phy->ops->prepare_hardware) {
+               err = phy->ops->prepare_hardware(dev);
                if (err)
-                       goto err_phy_exit;
+                       goto err_busdown;
        }
        err = b43_chip_init(dev);
        if (err)
-               goto err_phy_exit;
+               goto err_busdown;
        b43_shm_write16(dev, B43_SHM_SHARED,
                        B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
        hf = b43_hf_read(dev);
@@ -4059,8 +4085,6 @@ out:
 
 err_chip_exit:
        b43_chip_exit(dev);
-err_phy_exit:
-       b43_phy_exit(dev);
 err_busdown:
        ssb_bus_may_powerdown(bus);
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
@@ -4204,6 +4228,8 @@ static void b43_op_stop(struct ieee80211_hw *hw)
                b43_wireless_core_stop(dev);
        b43_wireless_core_exit(dev);
        mutex_unlock(&wl->mutex);
+
+       cancel_work_sync(&(wl->txpower_adjust_work));
 }
 
 static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
@@ -4335,6 +4361,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
        /* We release firmware that late to not be required to re-request
         * is all the time when we reinit the core. */
        b43_release_firmware(dev);
+       b43_phy_free(dev);
 }
 
 static int b43_wireless_core_attach(struct b43_wldev *dev)
@@ -4408,29 +4435,35 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                }
        }
 
+       err = b43_phy_allocate(dev);
+       if (err)
+               goto err_powerdown;
+
        dev->phy.gmode = have_2ghz_phy;
        tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
        b43_wireless_core_reset(dev, tmp);
 
        err = b43_validate_chipaccess(dev);
        if (err)
-               goto err_powerdown;
+               goto err_phy_free;
        err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
        if (err)
-               goto err_powerdown;
+               goto err_phy_free;
 
        /* Now set some default "current_dev" */
        if (!wl->current_dev)
                wl->current_dev = dev;
        INIT_WORK(&dev->restart_work, b43_chip_reset);
 
-       b43_switch_analog(dev, 0);
+       dev->phy.ops->switch_analog(dev, 0);
        ssb_device_disable(dev->dev, 0);
        ssb_bus_may_powerdown(bus);
 
 out:
        return err;
 
+err_phy_free:
+       b43_phy_free(dev);
 err_powerdown:
        ssb_bus_may_powerdown(bus);
        return err;
@@ -4562,6 +4595,13 @@ static int b43_wireless_init(struct ssb_device *dev)
                    IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_NOISE_DBM;
 
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_MESH_POINT) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_WDS) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
        hw->queues = b43_modparam_qos ? 4 : 1;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
@@ -4581,6 +4621,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        INIT_LIST_HEAD(&wl->devlist);
        INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
        INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
+       INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
 
        ssb_set_devtypedata(dev, wl);
        b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);