Merge tag 'iommu-config-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / net / wireless / b43 / main.c
index 2af1ac3..47731cb 100644 (file)
@@ -1204,6 +1204,36 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
+void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
+{
+       struct bcma_drv_cc *bcma_cc __maybe_unused;
+       struct ssb_chipcommon *ssb_cc __maybe_unused;
+
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc = &dev->dev->bdev->bus->drv_cc;
+
+               bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+               bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               ssb_cc = &dev->dev->sdev->bus->chipco;
+
+               chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
+               chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+               chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
+               chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+               break;
+#endif
+       }
+}
+
 #ifdef CONFIG_B43_BCMA
 static void b43_bcma_phy_reset(struct b43_wldev *dev)
 {
@@ -2985,7 +3015,22 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode)
 {
        u16 chip_id = dev->dev->chip_id;
 
-       if (chip_id == BCMA_CHIP_ID_BCM43131 ||
+       if (chip_id == BCMA_CHIP_ID_BCM4331) {
+               switch (spurmode) {
+               case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+                       break;
+               case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+                       break;
+               default: /* 160 Mhz: 2^26/160 = 0x66666 */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+                       break;
+               }
+       } else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
            chip_id == BCMA_CHIP_ID_BCM43217 ||
            chip_id == BCMA_CHIP_ID_BCM43222 ||
            chip_id == BCMA_CHIP_ID_BCM43224 ||
@@ -3106,6 +3151,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
        case B43_PHYTYPE_HT:
        case B43_PHYTYPE_LCN:
                b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+               b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
                b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
@@ -3884,6 +3930,12 @@ static int b43_switch_band(struct b43_wldev *dev,
        return 0;
 }
 
+static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval)
+{
+       interval = min_t(u16, interval, (u16)0xFF);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval);
+}
+
 /* Write the short and long frame retry limit values. */
 static void b43_set_retry_limits(struct b43_wldev *dev,
                                 unsigned int short_retry,
@@ -3912,6 +3964,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        mutex_lock(&wl->mutex);
        b43_mac_suspend(dev);
 
+       if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL)
+               b43_set_beacon_listen_interval(dev, conf->listen_interval);
+
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                phy->chandef = &conf->chandef;
                phy->channel = conf->chandef.chan->hw_value;
@@ -4466,10 +4521,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
        if (core_rev == 40 || core_rev == 42) {
                radio_manuf = 0x17F;
 
-               b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0);
+               b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
                radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
-               b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
+               b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
                radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
                radio_ver = 0; /* Is there version somewhere? */
@@ -4477,7 +4532,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                u16 radio24[3];
 
                for (tmp = 0; tmp < 3; tmp++) {
-                       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+                       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
                        radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
                }
 
@@ -4494,13 +4549,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        else
                                tmp = 0x5205017F;
                } else {
-                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-                                   B43_RADIOCTL_ID);
+                       b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+                                    B43_RADIOCTL_ID);
                        tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-                                   B43_RADIOCTL_ID);
-                       tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
-                               << 16;
+                       b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+                                    B43_RADIOCTL_ID);
+                       tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
                }
                radio_manuf = (tmp & 0x00000FFF);
                radio_id = (tmp & 0x0FFFF000) >> 12;
@@ -4813,6 +4867,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        hf &= ~B43_HF_SKCFPUP;
        b43_hf_write(dev, hf);
 
+       /* tell the ucode MAC capabilities */
+       if (dev->dev->core_rev >= 13) {
+               u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP);
+
+               b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L,
+                               mac_hw_cap & 0xffff);
+               b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H,
+                               (mac_hw_cap >> 16) & 0xffff);
+       }
+
        b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
                             B43_DEFAULT_LONG_RETRY_LIMIT);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
@@ -4835,6 +4899,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
+       /* write phytype and phyvers */
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev);
+
        if (b43_bus_host_is_pcmcia(dev->dev) ||
            b43_bus_host_is_sdio(dev->dev)) {
                dev->__using_pio_transfers = true;
@@ -5042,7 +5110,9 @@ static void b43_op_sta_notify(struct ieee80211_hw *hw,
        B43_WARN_ON(!vif || wl->vif != vif);
 }
 
-static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
+static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw,
+                                         struct ieee80211_vif *vif,
+                                         const u8 *mac_addr)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -5056,7 +5126,8 @@ static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
        mutex_unlock(&wl->mutex);
 }
 
-static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
+static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw,
+                                            struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;