Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 15 Jul 2011 14:05:24 +0000 (10:05 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 15 Jul 2011 14:05:24 +0000 (10:05 -0400)
Conflicts:
net/bluetooth/l2cap_core.c

1  2 
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/main.c
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c

@@@ -42,7 -42,6 +42,7 @@@
  
  #include <linux/module.h>
  #include <linux/delay.h>
 +#include <linux/dma-mapping.h>
  #include <linux/hardirq.h>
  #include <linux/if.h>
  #include <linux/io.h>
@@@ -532,7 -531,7 +532,7 @@@ ath5k_update_bssid_mask_and_opmode(stru
        if (iter_data.n_stas > 1) {
                /* If you have multiple STA interfaces connected to
                 * different APs, ARPs are not received (most of the time?)
-                * Enabling PROMISC appears to fix that probem.
+                * Enabling PROMISC appears to fix that problem.
                 */
                sc->filter_flags |= AR5K_RX_FILTER_PROM;
        }
@@@ -815,8 -814,7 +815,7 @@@ ath5k_desc_alloc(struct ath5k_softc *sc
  
        INIT_LIST_HEAD(&sc->txbuf);
        sc->txbuf_len = ATH_TXBUF;
-       for (i = 0; i < ATH_TXBUF; i++, bf++, ds++,
-                       da += sizeof(*ds)) {
+       for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
                bf->desc = ds;
                bf->daddr = da;
                list_add_tail(&bf->list, &sc->txbuf);
@@@ -982,7 -980,7 +981,7 @@@ ath5k_beaconq_config(struct ath5k_soft
                goto err;
  
        if (sc->opmode == NL80211_IFTYPE_AP ||
-               sc->opmode == NL80211_IFTYPE_MESH_POINT) {
+           sc->opmode == NL80211_IFTYPE_MESH_POINT) {
                /*
                 * Always burst out beacon and CAB traffic
                 * (aifs = cwmin = cwmax = 0)
@@@ -1262,16 -1260,15 +1261,15 @@@ ath5k_update_beacon_rssi(struct ath5k_s
   */
  static int ath5k_common_padpos(struct sk_buff *skb)
  {
-       struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 frame_control = hdr->frame_control;
        int padpos = 24;
  
-       if (ieee80211_has_a4(frame_control)) {
+       if (ieee80211_has_a4(frame_control))
                padpos += ETH_ALEN;
-       }
-       if (ieee80211_is_data_qos(frame_control)) {
+       if (ieee80211_is_data_qos(frame_control))
                padpos += IEEE80211_QOS_CTL_LEN;
-       }
  
        return padpos;
  }
@@@ -1285,13 -1282,13 +1283,13 @@@ static int ath5k_add_padding(struct sk_
        int padpos = ath5k_common_padpos(skb);
        int padsize = padpos & 3;
  
-       if (padsize && skb->len>padpos) {
+       if (padsize && skb->len > padpos) {
  
                if (skb_headroom(skb) < padsize)
                        return -1;
  
                skb_push(skb, padsize);
-               memmove(skb->data, skb->data+padsize, padpos);
+               memmove(skb->data, skb->data + padsize, padpos);
                return padsize;
        }
  
@@@ -1316,7 -1313,7 +1314,7 @@@ static int ath5k_remove_padding(struct 
        int padpos = ath5k_common_padpos(skb);
        int padsize = padpos & 3;
  
-       if (padsize && skb->len>=padpos+padsize) {
+       if (padsize && skb->len >= padpos + padsize) {
                memmove(skb->data + padsize, skb->data, padpos);
                skb_pull(skb, padsize);
                return padsize;
@@@ -1352,7 -1349,7 +1350,7 @@@ ath5k_receive_frame(struct ath5k_softc 
         * timestamp (beginning of phy frame, data frame, end of rx?).
         * The only thing we know is that it is hardware specific...
         * On AR5213 it seems the rx timestamp is at the end of the
-        * frame, but i'm not sure.
+        * frame, but I'm not sure.
         *
         * NOTE: mac80211 defines mactime at the beginning of the first
         * data symbol. Since we don't have any time references it's
@@@ -1450,10 -1447,11 +1448,11 @@@ ath5k_receive_frame_ok(struct ath5k_sof
  static void
  ath5k_set_current_imask(struct ath5k_softc *sc)
  {
-       enum ath5k_int imask = sc->imask;
+       enum ath5k_int imask;
        unsigned long flags;
  
        spin_lock_irqsave(&sc->irqlock, flags);
+       imask = sc->imask;
        if (sc->rx_pending)
                imask &= ~AR5K_INT_RX_ALL;
        if (sc->tx_pending)
@@@ -1556,7 -1554,8 +1555,8 @@@ ath5k_tx_queue(struct ieee80211_hw *hw
                goto drop_packet;
        }
  
-       if (txq->txq_len >= txq->txq_max)
+       if (txq->txq_len >= txq->txq_max &&
+           txq->qnum <= AR5K_TX_QUEUE_ID_DATA_MAX)
                ieee80211_stop_queue(hw, txq->qnum);
  
        spin_lock_irqsave(&sc->txbuflock, flags);
@@@ -1711,7 -1710,7 +1711,7 @@@ ath5k_tasklet_tx(unsigned long data
        int i;
        struct ath5k_softc *sc = (void *)data;
  
-       for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+       for (i = 0; i < AR5K_NUM_TX_QUEUES; i++)
                if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
                        ath5k_tx_processq(sc, &sc->txqs[i]);
  
@@@ -1766,7 -1765,7 +1766,7 @@@ ath5k_beacon_setup(struct ath5k_softc *
         * 4 beacons to make sure everybody hears our AP.
         * When a client tries to associate, hw will keep
         * track of the tx antenna to be used for this client
-        * automaticaly, based on ACKed packets.
+        * automatically, based on ACKed packets.
         *
         * Note: AP still listens and transmits RTS on the
         * default antenna which is supposed to be an omni.
@@@ -1902,7 -1901,7 +1902,7 @@@ ath5k_beacon_send(struct ath5k_softc *s
        avf = (void *)vif->drv_priv;
        bf = avf->bbuf;
        if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
-                       sc->opmode == NL80211_IFTYPE_MONITOR)) {
+                    sc->opmode == NL80211_IFTYPE_MONITOR)) {
                ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
                return;
        }
  
        /* refresh the beacon for AP or MESH mode */
        if (sc->opmode == NL80211_IFTYPE_AP ||
-                       sc->opmode == NL80211_IFTYPE_MESH_POINT)
+           sc->opmode == NL80211_IFTYPE_MESH_POINT)
                ath5k_beacon_update(sc->hw, vif);
  
        trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]);
        skb = ieee80211_get_buffered_bc(sc->hw, vif);
        while (skb) {
                ath5k_tx_queue(sc->hw, skb, sc->cabq);
+               if (sc->cabq->txq_len >= sc->cabq->txq_max)
+                       break;
                skb = ieee80211_get_buffered_bc(sc->hw, vif);
        }
  
@@@ -1978,7 -1981,7 +1982,7 @@@ ath5k_beacon_update_timers(struct ath5k
        hw_tsf = ath5k_hw_get_tsf64(ah);
        hw_tu = TSF_TO_TU(hw_tsf);
  
- #define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3
+ #define FUDGE (AR5K_TUNE_SW_BEACON_RESP + 3)
        /* We use FUDGE to make sure the next TBTT is ahead of the current TU.
         * Since we later subtract AR5K_TUNE_SW_BEACON_RESP (10) in the timer
         * configuration we need to make sure it is bigger than that. */
@@@ -2101,11 -2104,11 +2105,11 @@@ static void ath5k_tasklet_beacon(unsign
         *
         * In IBSS mode we use this interrupt just to
         * keep track of the next TBTT (target beacon
-        * transmission time) in order to detect wether
+        * transmission time) in order to detect whether
         * automatic TSF updates happened.
         */
        if (sc->opmode == NL80211_IFTYPE_ADHOC) {
-               /* XXX: only if VEOL suppported */
+               /* XXX: only if VEOL supported */
                u64 tsf = ath5k_hw_get_tsf64(sc->ah);
                sc->nexttbtt += sc->bintval;
                ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
@@@ -2200,13 -2203,12 +2204,12 @@@ ath5k_intr(int irq, void *dev_id
                                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                                          "rx overrun, resetting\n");
                                ieee80211_queue_work(sc->hw, &sc->reset_work);
-                       }
-                       else
+                       } else
                                ath5k_schedule_rx(sc);
                } else {
-                       if (status & AR5K_INT_SWBA) {
+                       if (status & AR5K_INT_SWBA)
                                tasklet_hi_schedule(&sc->beacontq);
-                       }
                        if (status & AR5K_INT_RXEOL) {
                                /*
                                * NB: the hardware should re-read the link when
@@@ -2358,7 -2360,7 +2361,7 @@@ ath5k_tx_complete_poll_work(struct work
  * Initialization routines *
  \*************************/
  
- int
+ int __devinit
  ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
  {
        struct ieee80211_hw *hw = sc->hw;
        common->ah = sc->ah;
        common->hw = hw;
        common->priv = sc;
+       common->clockrate = 40;
  
        /*
         * Cache line size is used to size and align various
                                                sc->ah->ah_radio_5ghz_revision),
                                                sc->ah->ah_radio_5ghz_revision);
                        /* No 2GHz support (5110 and some
-                        * 5Ghz only cards) -> report 5Ghz radio */
+                        * 5GHz only cards) -> report 5GHz radio */
                        } else if (!test_bit(AR5K_MODE_11B,
                                sc->ah->ah_capabilities.cap_mode)) {
                                ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
                /* Multi chip radio (RF5111 - RF2111) ->
                 * report both 2GHz/5GHz radios */
                else if (sc->ah->ah_radio_5ghz_revision &&
-                               sc->ah->ah_radio_2ghz_revision){
+                               sc->ah->ah_radio_2ghz_revision) {
                        ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
                                ath5k_chip_name(AR5K_VERSION_RAD,
                                        sc->ah->ah_radio_5ghz_revision),
@@@ -2713,8 -2716,7 +2717,7 @@@ ath5k_reset(struct ath5k_softc *sc, str
  
        fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
  
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast,
-                                                               skip_pcu);
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
                goto err;
  
        ath5k_ani_init(ah, ani_mode);
  
-       ah->ah_cal_next_full = jiffies;
+       ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100);
        ah->ah_cal_next_ani = jiffies;
        ah->ah_cal_next_nf = jiffies;
        ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
@@@ -2772,7 -2774,7 +2775,7 @@@ static void ath5k_reset_work(struct wor
        mutex_unlock(&sc->lock);
  }
  
- static int
+ static int __devinit
  ath5k_init(struct ieee80211_hw *hw)
  {
  
  
        /*
         * Collect the channel list.  The 802.11 layer
-        * is resposible for filtering this list based
+        * is responsible for filtering this list based
         * on settings like the phy mode and regulatory
         * domain restrictions.
         */
@@@ -1155,6 -1155,21 +1155,21 @@@ void b43_power_saving_ctl_bits(struct b
        }
  }
  
+ #ifdef CONFIG_B43_BCMA
+ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
+ {
+       u32 flags = 0;
+       if (gmode)
+               flags = B43_BCMA_IOCTL_GMODE;
+       flags |= B43_BCMA_IOCTL_PHY_CLKEN;
+       flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */
+       b43_device_enable(dev, flags);
+       /* TODO: reset PHY */
+ }
+ #endif
  static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
  {
        struct ssb_device *sdev = dev->dev->sdev;
@@@ -1187,7 -1202,18 +1202,18 @@@ void b43_wireless_core_reset(struct b43
  {
        u32 macctl;
  
-       b43_ssb_wireless_core_reset(dev, gmode);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43_bcma_wireless_core_reset(dev, gmode);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_ssb_wireless_core_reset(dev, gmode);
+               break;
+ #endif
+       }
  
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@@ -1938,7 -1964,7 +1964,7 @@@ static irqreturn_t b43_do_interrupt(str
                return IRQ_NONE;
        reason &= dev->irq_mask;
        if (!reason)
-               return IRQ_HANDLED;
+               return IRQ_NONE;
  
        dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
            & 0x0001DC00;
@@@ -2133,21 -2159,43 +2159,43 @@@ static int b43_try_request_fw(struct b4
        u32 tmshigh;
        int err;
  
+       /* Files for HT and LCN were found by trying one by one */
        /* Get microcode */
-       if ((rev >= 5) && (rev <= 10))
+       if ((rev >= 5) && (rev <= 10)) {
                filename = "ucode5";
-       else if ((rev >= 11) && (rev <= 12))
+       } else if ((rev >= 11) && (rev <= 12)) {
                filename = "ucode11";
-       else if (rev == 13)
+       } else if (rev == 13) {
                filename = "ucode13";
-       else if (rev == 14)
+       } else if (rev == 14) {
                filename = "ucode14";
-       else if (rev == 15)
+       } else if (rev == 15) {
                filename = "ucode15";
-       else if ((rev >= 16) && (rev <= 20))
-               filename = "ucode16_mimo";
-       else
-               goto err_no_ucode;
+       } else {
+               switch (dev->phy.type) {
+               case B43_PHYTYPE_N:
+                       if (rev >= 16)
+                               filename = "ucode16_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_HT:
+                       if (rev == 29)
+                               filename = "ucode29_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_LCN:
+                       if (rev == 24)
+                               filename = "ucode24_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               default:
+                       goto err_no_ucode;
+               }
+       }
        err = b43_do_request_fw(ctx, filename, &fw->ucode);
        if (err)
                goto err_load;
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0initvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0initvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0bsinitvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0bsinitvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
@@@ -2624,11 -2696,24 +2696,24 @@@ static int b43_gpio_init(struct b43_wld
        if (dev->dev->core_rev >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
  
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL,
-                           (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                            & mask) | set);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
+                                       BCMA_CC_GPIOCTL) & mask) | set);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL,
+                                   (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+                                   & mask) | set);
+               break;
+ #endif
+       }
  
        return 0;
  }
@@@ -2638,9 -2723,21 +2723,21 @@@ static void b43_gpio_cleanup(struct b43
  {
        struct ssb_device *gpiodev;
  
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               0);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+               break;
+ #endif
+       }
  }
  
  /* http://bcm-specs.sipsolutions.net/EnableMac */
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
  void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
  {
-       u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
-       if (on)
-               tmslow |= B43_TMSLOW_MACPHYCLKEN;
-       else
-               tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       u32 tmp;
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_read32(dev->dev->bdev, BCMA_IOCTL);
+               if (on)
+                       tmp |= B43_BCMA_IOCTL_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_BCMA_IOCTL_MACPHYCLKEN;
+               bcma_write32(dev->dev->bdev, BCMA_IOCTL, tmp);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               if (on)
+                       tmp |= B43_TMSLOW_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_TMSLOW_MACPHYCLKEN;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               break;
+ #endif
+       }
  }
  
  static void b43_adjust_opmode(struct b43_wldev *dev)
@@@ -2956,8 -3071,20 +3071,20 @@@ static int b43_chip_init(struct b43_wld
  
        b43_mac_phy_clock_set(dev, true);
  
-       b43_write16(dev, B43_MMIO_POWERUP_DELAY,
-                   dev->sdev->bus->chipco.fast_pwrup_delay);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               /* FIXME: 0xE74 is quite common, but should be read from CC */
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY, 0xE74);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+                           dev->dev->sdev->bus->chipco.fast_pwrup_delay);
+               break;
+ #endif
+       }
  
        err = 0;
        b43dbg(dev->wl, "Chip initialized\n");
@@@ -3473,21 -3600,33 +3600,33 @@@ static void b43_op_set_tsf(struct ieee8
  
  static void b43_put_phy_into_reset(struct b43_wldev *dev)
  {
-       struct ssb_device *sdev = dev->sdev;
-       u32 tmslow;
+       u32 tmp;
  
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~B43_TMSLOW_GMODE;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       tmslow |= SSB_TMSLOW_FGC;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43err(dev->wl,
+                      "Putting PHY into reset not supported on BCMA\n");
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~B43_TMSLOW_GMODE;
+               tmp |= B43_TMSLOW_PHYRESET;
+               tmp |= SSB_TMSLOW_FGC;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~SSB_TMSLOW_FGC;
+               tmp |= B43_TMSLOW_PHYRESET;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
  
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~SSB_TMSLOW_FGC;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+               break;
+ #endif
+       }
  }
  
  static const char *band_to_string(enum ieee80211_band band)
@@@ -4103,10 -4242,16 +4242,16 @@@ static int b43_phy_versioning(struct b4
                if (phy_rev > 1)
                        unsupported = 1;
                break;
+ #endif
+ #ifdef CONFIG_B43_PHY_LCN
+       case B43_PHYTYPE_LCN:
+               if (phy_rev > 1)
+                       unsupported = 1;
+               break;
  #endif
        default:
                unsupported = 1;
 -      };
 +      }
        if (unsupported) {
                b43err(dev->wl, "FOUND UNSUPPORTED PHY "
                       "(Analog %u, Type %u, Revision %u)\n",
               analog_type, phy_type, phy_rev);
  
        /* Get RADIO versioning */
-       if (dev->dev->chip_id == 0x4317) {
-               if (dev->dev->chip_rev == 0)
-                       tmp = 0x3205017F;
-               else if (dev->dev->chip_rev == 1)
-                       tmp = 0x4205017F;
-               else
-                       tmp = 0x5205017F;
+       if (dev->dev->core_rev >= 24) {
+               u16 radio24[3];
+               for (tmp = 0; tmp < 3; tmp++) {
+                       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+                       radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+               }
+               /* Broadcom uses "id" for our "ver" and has separated "ver" */
+               /* radio_ver = (radio24[0] & 0xF0) >> 4; */
+               radio_manuf = 0x17F;
+               radio_ver = (radio24[2] << 8) | radio24[1];
+               radio_rev = (radio24[0] & 0xF);
        } else {
-               b43_write16(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;
-       }
-       radio_manuf = (tmp & 0x00000FFF);
-       radio_ver = (tmp & 0x0FFFF000) >> 12;
-       radio_rev = (tmp & 0xF0000000) >> 28;
+               if (dev->dev->chip_id == 0x4317) {
+                       if (dev->dev->chip_rev == 0)
+                               tmp = 0x3205017F;
+                       else if (dev->dev->chip_rev == 1)
+                               tmp = 0x4205017F;
+                       else
+                               tmp = 0x5205017F;
+               } else {
+                       b43_write16(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;
+               }
+               radio_manuf = (tmp & 0x00000FFF);
+               radio_ver = (tmp & 0x0FFFF000) >> 12;
+               radio_rev = (tmp & 0xF0000000) >> 28;
+       }
        if (radio_manuf != 0x17F /* Broadcom */)
                unsupported = 1;
        switch (phy_type) {
                if (radio_ver != 0x2059)
                        unsupported = 1;
                break;
+       case B43_PHYTYPE_LCN:
+               if (radio_ver != 0x2064)
+                       unsupported = 1;
+               break;
        default:
                B43_WARN_ON(1);
        }
@@@ -4347,7 -4516,6 +4516,6 @@@ static void b43_wireless_core_exit(stru
  /* Initialize a wireless core */
  static int b43_wireless_core_init(struct b43_wldev *dev)
  {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
        phy->ops->prepare_structs(dev);
  
        /* Enable IRQ routing to this device. */
-       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
+                                     dev->dev->bdev, true);
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               ssb_pcicore_dev_irqvecs_enable(&dev->dev->sdev->bus->pcicore,
+                                              dev->dev->sdev);
+               break;
+ #endif
+       }
  
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
        if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
                hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
  #ifdef CONFIG_SSB_DRIVER_PCICORE
-       if ((bus->bustype == SSB_BUSTYPE_PCI) &&
-           (bus->pcicore.dev->id.revision <= 10))
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+           dev->dev->sdev->bus->pcicore.dev->id.revision <= 10)
                hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
  #endif
        hf &= ~B43_HF_SKCFPUP;
@@@ -4764,8 -4946,7 +4946,7 @@@ static void b43_wireless_core_detach(st
  static int b43_wireless_core_attach(struct b43_wldev *dev)
  {
        struct b43_wl *wl = dev->wl;
-       struct ssb_bus *bus = dev->sdev->bus;
-       struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
+       struct pci_dev *pdev = NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
  
         * that in core_init(), too.
         */
  
+ #ifdef CONFIG_B43_SSB
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI)
+               pdev = dev->dev->sdev->bus->host_pci;
+ #endif
        err = b43_bus_powerup(dev, 0);
        if (err) {
                b43err(wl, "Bus powerup failed\n");
                goto out;
        }
-       /* Get the PHY type. */
-       if (dev->dev->core_rev >= 5) {
-               u32 tmshigh;
  
-               tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
-               have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
-               have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
-       } else
-               B43_WARN_ON(1);
+       /* Get the PHY type. */
+       switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               /* FIXME */
+               have_2ghz_phy = 1;
+               have_5ghz_phy = 0;
+               break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               if (dev->dev->core_rev >= 5) {
+                       u32 tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
+                       have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+                       have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
+               } else
+                       B43_WARN_ON(1);
+               break;
+ #endif
+       }
  
        dev->phy.gmode = have_2ghz_phy;
        dev->phy.radio_on = 1;
  #endif
                case B43_PHYTYPE_G:
                case B43_PHYTYPE_N:
+               case B43_PHYTYPE_HT:
+               case B43_PHYTYPE_LCN:
                        have_2ghz_phy = 1;
                        break;
                default:
@@@ -4877,13 -5078,13 +5078,13 @@@ static void b43_one_core_detach(struct 
        /* Do not cancel ieee80211-workqueue based work here.
         * See comment in b43_remove(). */
  
-       wldev = ssb_get_drvdata(dev->sdev);
+       wldev = b43_bus_get_wldev(dev);
        wl = wldev->wl;
        b43_debugfs_remove_device(wldev);
        b43_wireless_core_detach(wldev);
        list_del(&wldev->list);
        wl->nr_devs--;
-       ssb_set_drvdata(dev->sdev, NULL);
+       b43_bus_set_wldev(dev, NULL);
        kfree(wldev);
  }
  
@@@ -4898,7 -5099,6 +5099,6 @@@ static int b43_one_core_attach(struct b
  
        wldev->use_pio = b43_modparam_pio;
        wldev->dev = dev;
-       wldev->sdev = dev->sdev; /* TODO: Remove when not needed */
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
  
        list_add(&wldev->list, &wl->devlist);
        wl->nr_devs++;
-       ssb_set_drvdata(dev->sdev, wldev);
+       b43_bus_set_wldev(dev, wldev);
        b43_debugfs_add_device(wldev);
  
        out:
@@@ -4959,9 -5159,9 +5159,9 @@@ static void b43_wireless_exit(struct b4
        ieee80211_free_hw(hw);
  }
  
- static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
+ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
  {
-       struct ssb_sprom *sprom = &dev->bus->sprom;
+       struct ssb_sprom *sprom = dev->bus_sprom;
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
  
        skb_queue_head_init(&wl->tx_queue);
  
        b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
-               dev->bus->chip_id, dev->id.revision);
+               dev->chip_id, dev->core_rev);
        return wl;
  }
  
  #ifdef CONFIG_B43_BCMA
  static int b43_bcma_probe(struct bcma_device *core)
  {
+       struct b43_bus_dev *dev;
+       dev = b43_bus_dev_bcma_init(core);
+       if (!dev)
+               return -ENODEV;
        b43err(NULL, "BCMA is not supported yet!");
+       kfree(dev);
        return -EOPNOTSUPP;
  }
  
@@@ -5045,7 -5252,7 +5252,7 @@@ int b43_ssb_probe(struct ssb_device *sd
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
                b43_sprom_fixup(sdev->bus);
-               wl = b43_wireless_init(sdev);
+               wl = b43_wireless_init(dev);
                if (IS_ERR(wl)) {
                        err = PTR_ERR(wl);
                        goto out;
@@@ -31,7 -31,6 +31,7 @@@
  #ifndef __iwl_dev_h__
  #define __iwl_dev_h__
  
 +#include <linux/interrupt.h>
  #include <linux/pci.h> /* for struct pci_device_id */
  #include <linux/kernel.h>
  #include <linux/wait.h>
@@@ -260,11 -259,9 +260,9 @@@ struct iwl_channel_info 
  
  enum {
        CMD_SYNC = 0,
-       CMD_SIZE_NORMAL = 0,
-       CMD_NO_SKB = 0,
-       CMD_ASYNC = (1 << 1),
-       CMD_WANT_SKB = (1 << 2),
-       CMD_MAPPED = (1 << 3),
+       CMD_ASYNC = BIT(0),
+       CMD_WANT_SKB = BIT(1),
+       CMD_ON_DEMAND = BIT(2),
  };
  
  #define DEF_CMD_PAYLOAD_SIZE 320
@@@ -297,6 -294,16 +295,16 @@@ enum iwl_hcmd_dataflag 
        IWL_HCMD_DFL_NOCOPY     = BIT(0),
  };
  
+ /**
+  * struct iwl_host_cmd - Host command to the uCode
+  * @data: array of chunks that composes the data of the host command
+  * @reply_page: pointer to the page that holds the response to the host command
+  * @callback:
+  * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
+  * @len: array of the lenths of the chunks in data
+  * @dataflags:
+  * @id: id of the host command
+  */
  struct iwl_host_cmd {
        const void *data[IWL_MAX_CMD_TFDS];
        unsigned long reply_page;
@@@ -634,7 -641,6 +642,6 @@@ struct iwl_sensitivity_ranges 
  /**
   * struct iwl_hw_params
   * @max_txq_num: Max # Tx queues supported
-  * @dma_chnl_num: Number of Tx DMA/FIFO channels
   * @scd_bc_tbls_size: size of scheduler byte count tables
   * @tfd_size: TFD size
   * @tx/rx_chains_num: Number of TX/RX chains
   */
  struct iwl_hw_params {
        u8 max_txq_num;
-       u8 dma_chnl_num;
        u16 scd_bc_tbls_size;
        u32 tfd_size;
        u8  tx_chains_num;
   ****************************************************************************/
  extern void iwl_update_chain_flags(struct iwl_priv *priv);
  extern const u8 iwl_bcast_addr[ETH_ALEN];
- extern int iwl_rxq_stop(struct iwl_priv *priv);
- extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
  extern int iwl_queue_space(const struct iwl_queue *q);
  static inline int iwl_queue_used(const struct iwl_queue *q, int i)
  {
@@@ -1233,19 -1236,37 +1237,37 @@@ struct iwl_trans
   * struct iwl_trans_ops - transport specific operations
  
   * @rx_init: inits the rx memory, allocate it if needed
+  * @rx_stop: stop the rx
   * @rx_free: frees the rx memory
   * @tx_init:inits the tx memory, allocate if needed
+  * @tx_stop: stop the tx
+  * @tx_free: frees the tx memory
+  * @send_cmd:send a host command
+  * @send_cmd_pdu:send a host command: flags can be CMD_*
   */
  struct iwl_trans_ops {
        int (*rx_init)(struct iwl_priv *priv);
+       int (*rx_stop)(struct iwl_priv *priv);
        void (*rx_free)(struct iwl_priv *priv);
        int (*tx_init)(struct iwl_priv *priv);
+       int (*tx_stop)(struct iwl_priv *priv);
+       void (*tx_free)(struct iwl_priv *priv);
+       int (*send_cmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+       int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
+                    const void *data);
  };
  
  struct iwl_trans {
        const struct iwl_trans_ops *ops;
  };
  
+ /* uCode ownership */
+ #define IWL_OWNERSHIP_DRIVER  0
+ #define IWL_OWNERSHIP_TM      1
  struct iwl_priv {
  
        /* ieee device used by generic ieee processing code */
        int fw_index;                   /* firmware we're trying to load */
        u32 ucode_ver;                  /* version of ucode, copy of
                                           iwl_ucode.ver */
+       /* uCode owner: default: IWL_OWNERSHIP_DRIVER */
+       u8 ucode_owner;
        struct fw_img ucode_rt;
        struct fw_img ucode_init;
  
        u16 dynamic_frag_thresh;
        u8 bt_ci_compliance;
        struct work_struct bt_traffic_change_work;
+       bool bt_enable_pspoll;
+       struct iwl_rxon_context *cur_rssi_ctx;
+       bool bt_is_sco;
  
        struct iwl_hw_params hw_params;
  
  #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
        struct iwl_testmode_trace testmode_trace;
  #endif
-       u32 dbg_fixed_rate;
+       u32 tm_fixed_rate;
  
  }; /*iwl_priv */
  
@@@ -3,7 -3,6 +3,7 @@@
   * It prepares command and sends it to firmware when it is ready.
   */
  
 +#include <linux/hardirq.h>
  #include <linux/kfifo.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
@@@ -874,6 -873,7 +874,7 @@@ int lbs_get_reg(struct lbs_private *pri
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.offset = cpu_to_le16(offset);
  
        if (reg != CMD_MAC_REG_ACCESS &&
            reg != CMD_BBP_REG_ACCESS &&
        }
  
        ret = lbs_cmd_with_response(priv, reg, &cmd);
-       if (ret) {
+       if (!ret) {
                if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
                        *value = cmd.value.bbp_rf;
                else if (reg == CMD_MAC_REG_ACCESS)
@@@ -916,6 -916,7 +917,7 @@@ int lbs_set_reg(struct lbs_private *pri
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.offset = cpu_to_le16(offset);
  
        if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
                cmd.value.bbp_rf = (u8) (value & 0xFF);
@@@ -1068,16 -1069,34 +1070,34 @@@ static void lbs_cleanup_and_insert_cmd(
        spin_unlock_irqrestore(&priv->driver_lock, flags);
  }
  
- void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                         int result)
+ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result)
  {
+       /*
+        * Normally, commands are removed from cmdpendingq before being
+        * submitted. However, we can arrive here on alternative codepaths
+        * where the command is still pending. Make sure the command really
+        * isn't part of a list at this point.
+        */
+       list_del_init(&cmd->list);
        cmd->result = result;
        cmd->cmdwaitqwoken = 1;
-       wake_up_interruptible(&cmd->cmdwait_q);
+       wake_up(&cmd->cmdwait_q);
  
        if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
                __lbs_cleanup_and_insert_cmd(priv, cmd);
        priv->cur_cmd = NULL;
+       wake_up_interruptible(&priv->waitq);
+ }
+ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                         int result)
+ {
+       unsigned long flags;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       __lbs_complete_command(priv, cmd, result);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
  }
  
  int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
@@@ -1249,7 -1268,7 +1269,7 @@@ static struct cmd_ctrl_node *lbs_get_fr
        if (!list_empty(&priv->cmdfreeq)) {
                tempnode = list_first_entry(&priv->cmdfreeq,
                                            struct cmd_ctrl_node, list);
-               list_del(&tempnode->list);
+               list_del_init(&tempnode->list);
        } else {
                lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
                tempnode = NULL;
@@@ -1357,10 -1376,7 +1377,7 @@@ int lbs_execute_next_command(struct lbs
                                    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
  
                                        ret = 0;
                                        goto done;
                                    (priv->psstate == PS_STATE_PRE_SLEEP)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
                                        priv->needtowakeup = 1;
  
                                        ret = 0;
                        }
                }
                spin_lock_irqsave(&priv->driver_lock, flags);
-               list_del(&cmdnode->list);
+               list_del_init(&cmdnode->list);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
                            le16_to_cpu(cmd->command));
@@@ -1668,7 -1681,13 +1682,13 @@@ int __lbs_cmd(struct lbs_private *priv
        }
  
        might_sleep();
-       wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+       /*
+        * Be careful with signals here. A signal may be received as the system
+        * goes into suspend or resume. We do not want this to interrupt the
+        * command, so we perform an uninterruptible sleep.
+        */
+       wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
  
        spin_lock_irqsave(&priv->driver_lock, flags);
        ret = cmdnode->result;
@@@ -3,7 -3,6 +3,7 @@@
   * responses as well as events generated by firmware.
   */
  
 +#include <linux/hardirq.h>
  #include <linux/slab.h>
  #include <linux/delay.h>
  #include <linux/sched.h>
@@@ -166,7 -165,7 +166,7 @@@ int lbs_process_command_response(struc
                        lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
                }
  
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
  
                ret = 0;
                        break;
  
                }
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
  
                ret = -1;
  
        if (priv->cur_cmd) {
                /* Clean up and Put current command back to cmdfreeq */
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
        }
        spin_unlock_irqrestore(&priv->driver_lock, flags);
  
@@@ -9,7 -9,6 +9,7 @@@
  #include <linux/moduleparam.h>
  #include <linux/delay.h>
  #include <linux/etherdevice.h>
 +#include <linux/hardirq.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/kthread.h>
@@@ -639,6 -638,14 +639,14 @@@ static void lbs_cmd_timeout_handler(uns
                    le16_to_cpu(priv->cur_cmd->cmdbuf->command));
  
        priv->cmd_timed_out = 1;
+       /*
+        * If the device didn't even acknowledge the command, reset the state
+        * so that we don't block all future commands due to this one timeout.
+        */
+       if (priv->dnld_sent == DNLD_CMD_SENT)
+               priv->dnld_sent = DNLD_RES_RECEIVED;
        wake_up_interruptible(&priv->waitq);
  out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@@ -995,7 -1002,7 +1003,7 @@@ void lbs_stop_card(struct lbs_private *
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
                cmdnode->result = -ENOENT;
                cmdnode->cmdwaitqwoken = 1;
-               wake_up_interruptible(&cmdnode->cmdwait_q);
+               wake_up(&cmdnode->cmdwait_q);
        }
  
        /* Flush the command the card is currently processing */
                lbs_deb_main("clearing current command\n");
                priv->cur_cmd->result = -ENOENT;
                priv->cur_cmd->cmdwaitqwoken = 1;
-               wake_up_interruptible(&priv->cur_cmd->cmdwait_q);
+               wake_up(&priv->cur_cmd->cmdwait_q);
        }
        lbs_deb_main("done clearing commands\n");
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@@ -25,7 -25,6 +25,7 @@@
  #ifndef __HCI_CORE_H
  #define __HCI_CORE_H
  
 +#include <linux/interrupt.h>
  #include <net/bluetooth/hci.h>
  
  /* HCI upper protocols */
@@@ -75,12 -74,28 +75,28 @@@ struct bt_uuid 
        u8 svc_hint;
  };
  
+ struct key_master_id {
+       __le16 ediv;
+       u8 rand[8];
+ } __packed;
+ struct link_key_data {
+       bdaddr_t bdaddr;
+       u8 type;
+       u8 val[16];
+       u8 pin_len;
+       u8 dlen;
+       u8 data[0];
+ } __packed;
  struct link_key {
        struct list_head list;
        bdaddr_t bdaddr;
        u8 type;
        u8 val[16];
        u8 pin_len;
+       u8 dlen;
+       u8 data[0];
  };
  
  struct oob_data {
@@@ -114,6 -129,7 +130,7 @@@ struct hci_dev 
        __u8            major_class;
        __u8            minor_class;
        __u8            features[8];
+       __u8            extfeatures[8];
        __u8            commands[64];
        __u8            ssp_mode;
        __u8            hci_ver;
@@@ -224,7 -240,6 +241,6 @@@ struct hci_conn 
        struct list_head list;
  
        atomic_t        refcnt;
-       spinlock_t      lock;
  
        bdaddr_t        dst;
        __u8            dst_type;
        __u8            sec_level;
        __u8            pending_sec_level;
        __u8            pin_length;
+       __u8            enc_key_size;
        __u8            io_capability;
        __u8            power_save;
        __u16           disc_timeout;
        unsigned long   pend;
-       __u8            ltk[16];
  
        __u8            remote_cap;
        __u8            remote_oob;
        struct hci_dev  *hdev;
        void            *l2cap_data;
        void            *sco_data;
-       void            *priv;
  
        struct hci_conn *link;
  
@@@ -539,6 -553,11 +554,11 @@@ int hci_link_keys_clear(struct hci_dev 
  struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
  int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                        bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
+ struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+ struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
+                                       bdaddr_t *bdaddr, u8 type);
+ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
  int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
  
  int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@@ -580,6 -599,9 +600,9 @@@ void hci_conn_del_sysfs(struct hci_con
  #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
  #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
  
+ /* ----- Extended LMP capabilities ----- */
+ #define lmp_host_le_capable(dev)   ((dev)->extfeatures[0] & LMP_HOST_LE)
  /* ----- HCI protocols ----- */
  struct hci_proto {
        char            *name;
diff --combined net/bluetooth/hci_core.c
@@@ -60,8 -60,6 +60,6 @@@ static void hci_tx_task(unsigned long a
  
  static DEFINE_RWLOCK(hci_task_lock);
  
- static int enable_smp;
  /* HCI device list */
  LIST_HEAD(hci_dev_list);
  DEFINE_RWLOCK(hci_dev_list_lock);
@@@ -148,7 -146,7 +146,7 @@@ static int __hci_request(struct hci_de
  
        switch (hdev->req_status) {
        case HCI_REQ_DONE:
-               err = -bt_err(hdev->req_result);
+               err = -bt_to_errno(hdev->req_result);
                break;
  
        case HCI_REQ_CANCELED:
@@@ -542,7 -540,7 +540,7 @@@ int hci_dev_open(__u16 dev
                ret = __hci_request(hdev, hci_init_req, 0,
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
  
-               if (lmp_le_capable(hdev))
+               if (lmp_host_le_capable(hdev))
                        ret = __hci_request(hdev, hci_le_init_req, 0,
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
  
@@@ -1059,6 -1057,42 +1057,42 @@@ static int hci_persistent_key(struct hc
        return 0;
  }
  
+ struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+ {
+       struct link_key *k;
+       list_for_each_entry(k, &hdev->link_keys, list) {
+               struct key_master_id *id;
+               if (k->type != HCI_LK_SMP_LTK)
+                       continue;
+               if (k->dlen != sizeof(*id))
+                       continue;
+               id = (void *) &k->data;
+               if (id->ediv == ediv &&
+                               (memcmp(rand, id->rand, sizeof(id->rand)) == 0))
+                       return k;
+       }
+       return NULL;
+ }
+ EXPORT_SYMBOL(hci_find_ltk);
+ struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
+                                       bdaddr_t *bdaddr, u8 type)
+ {
+       struct link_key *k;
+       list_for_each_entry(k, &hdev->link_keys, list)
+               if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+                       return k;
+       return NULL;
+ }
+ EXPORT_SYMBOL(hci_find_link_key_type);
  int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                                bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
  {
        return 0;
  }
  
+ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
+ {
+       struct link_key *key, *old_key;
+       struct key_master_id *id;
+       u8 old_key_type;
+       BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+       old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
+       if (old_key) {
+               key = old_key;
+               old_key_type = old_key->type;
+       } else {
+               key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+               if (!key)
+                       return -ENOMEM;
+               list_add(&key->list, &hdev->link_keys);
+               old_key_type = 0xff;
+       }
+       key->dlen = sizeof(*id);
+       bacpy(&key->bdaddr, bdaddr);
+       memcpy(key->val, ltk, sizeof(key->val));
+       key->type = HCI_LK_SMP_LTK;
+       key->pin_len = key_size;
+       id = (void *) &key->data;
+       id->ediv = ediv;
+       memcpy(id->rand, rand, sizeof(id->rand));
+       if (new_key)
+               mgmt_new_key(hdev->id, key, old_key_type);
+       return 0;
+ }
  int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
  {
        struct link_key *key;
@@@ -1246,7 -1318,7 +1318,7 @@@ int hci_blacklist_add(struct hci_dev *h
        if (bacmp(bdaddr, BDADDR_ANY) == 0)
                return -EBADF;
  
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
  
        if (hci_blacklist_lookup(hdev, bdaddr)) {
                err = -EEXIST;
        err = 0;
  
  err:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        return err;
  }
  
@@@ -1275,7 -1347,7 +1347,7 @@@ int hci_blacklist_del(struct hci_dev *h
        struct bdaddr_list *entry;
        int err = 0;
  
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
  
        if (bacmp(bdaddr, BDADDR_ANY) == 0) {
                hci_blacklist_clear(hdev);
        kfree(entry);
  
  done:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        return err;
  }
  
@@@ -1368,14 -1440,6 +1440,6 @@@ int hci_add_adv_entry(struct hci_dev *h
        return 0;
  }
  
- static struct crypto_blkcipher *alloc_cypher(void)
- {
-       if (enable_smp)
-               return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-       return ERR_PTR(-ENOTSUPP);
- }
  /* Register HCI device */
  int hci_register_dev(struct hci_dev *hdev)
  {
        if (!hdev->workqueue)
                goto nomem;
  
-       hdev->tfm = alloc_cypher();
+       hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(hdev->tfm))
                BT_INFO("Failed to load transform for ecb(aes): %ld",
                                                        PTR_ERR(hdev->tfm));
@@@ -1707,7 -1771,7 +1771,7 @@@ int hci_recv_fragment(struct hci_dev *h
  
                data += (count - rem);
                count = rem;
 -      };
 +      }
  
        return rem;
  }
@@@ -1742,7 -1806,7 +1806,7 @@@ int hci_recv_stream_fragment(struct hci
  
                data += (count - rem);
                count = rem;
 -      };
 +      }
  
        return rem;
  }
@@@ -2352,6 -2416,3 +2416,3 @@@ static void hci_cmd_task(unsigned long 
                }
        }
  }
- module_param(enable_smp, bool, 0644);
- MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");