]> Git Repo - linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <[email protected]>
Thu, 5 Jan 2012 02:35:43 +0000 (21:35 -0500)
committerDavid S. Miller <[email protected]>
Thu, 5 Jan 2012 02:35:43 +0000 (21:35 -0500)
1  2 
MAINTAINERS
drivers/net/ethernet/freescale/Kconfig
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/mwifiex/sta_ioctl.c
net/bluetooth/hci_core.c
net/sched/sch_qfq.c

diff --combined MAINTAINERS
index dbf3d94b1dedd0b65d9d29323281aac1b4bc4ae3,62f1cd357ddf76ef0cc1c63e4a38133a3935dbe0..0cc83fc1d8b208d76026348848868ee11f2c292b
@@@ -1698,11 -1698,9 +1698,9 @@@ F:     arch/x86/include/asm/tce.
  
  CAN NETWORK LAYER
  M:    Oliver Hartkopp <[email protected]>
- M:    Oliver Hartkopp <[email protected]>
- M:    Urs Thuermann <[email protected]>
  L:    [email protected]
- L:    [email protected]
- W:    http://developer.berlios.de/projects/socketcan/
+ W:    http://gitorious.org/linux-can
+ T:    git git://gitorious.org/linux-can/linux-can-next.git
  S:    Maintained
  F:    net/can/
  F:    include/linux/can.h
@@@ -1713,9 -1711,10 +1711,10 @@@ F:    include/linux/can/gw.
  
  CAN NETWORK DRIVERS
  M:    Wolfgang Grandegger <[email protected]>
+ M:    Marc Kleine-Budde <[email protected]>
  L:    [email protected]
- L:    [email protected]
- W:    http://developer.berlios.de/projects/socketcan/
+ W:    http://gitorious.org/linux-can
+ T:    git git://gitorious.org/linux-can/linux-can-next.git
  S:    Maintained
  F:    drivers/net/can/
  F:    include/linux/can/dev.h
@@@ -4855,14 -4854,6 +4854,14 @@@ S:    Maintaine
  T:    git git://openrisc.net/~jonas/linux
  F:    arch/openrisc
  
 +OPENVSWITCH
 +M:    Jesse Gross <[email protected]>
 +L:    [email protected]
 +W:    http://openvswitch.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch.git
 +S:    Maintained
 +F:    net/openvswitch/
 +
  OPL4 DRIVER
  M:    Clemens Ladisch <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
@@@ -5382,7 -5373,6 +5381,7 @@@ S:      Supporte
  F:    drivers/scsi/qla4xxx/
  
  QLOGIC QLA3XXX NETWORK DRIVER
 +M:    Jitendra Kalsaria <[email protected]>
  M:    Ron Mercer <[email protected]>
  M:    [email protected]
  L:    [email protected]
@@@ -5902,6 -5892,7 +5901,6 @@@ F:      drivers/net/ethernet/emulex/benet
  
  SFC NETWORK DRIVER
  M:    Solarflare linux maintainers <[email protected]>
 -M:    Steve Hodgson <[email protected]>
  M:    Ben Hutchings <[email protected]>
  L:    [email protected]
  S:    Supported
@@@ -6509,13 -6500,6 +6508,13 @@@ W:    http://tcp-lp-mod.sourceforge.net
  S:    Maintained
  F:    net/ipv4/tcp_lp.c
  
 +TEAM DRIVER
 +M:    Jiri Pirko <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    drivers/net/team/
 +F:    include/linux/if_team.h
 +
  TEGRA SUPPORT
  M:    Colin Cross <[email protected]>
  M:    Olof Johansson <[email protected]>
index 820de8b9ff0871ccfbd24ff0b4f5e9376345dfa3,9de37642f09f24371f857df61eaecb89b3bbb416..3574e1499dfc30db059160e80b8a77766cd8392f
@@@ -21,10 -21,10 +21,10 @@@ config NET_VENDOR_FREESCAL
  if NET_VENDOR_FREESCALE
  
  config FEC
 -      bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
 +      tristate "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
        depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
-                  ARCH_MXC || ARCH_MXS)
-       default ARCH_MXC || ARCH_MXS if ARM
+                  ARCH_MXC || SOC_IMX28)
+       default ARCH_MXC || SOC_IMX28 if ARM
        select PHYLIB
        ---help---
          Say Y here if you want to use the built-in 10/100 Fast ethernet
index 6e3d8384e081effb2422e4410ea1db1eb192c7d4,a9c5ae75277e18b0993af04bdfff063955fc8ce2..e267c92dbfb8e22de58a0156771a461ccfada95a
@@@ -118,7 -118,7 +118,7 @@@ void ath9k_ps_restore(struct ath_softc 
        if (--sc->ps_usecount != 0)
                goto unlock;
  
 -      if (sc->ps_idle)
 +      if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
                mode = ATH9K_PM_FULL_SLEEP;
        else if (sc->ps_enabled &&
                 !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
@@@ -332,14 -332,14 +332,14 @@@ static int ath_reset_internal(struct at
                hchan = ah->curchan;
        }
  
 -      if (fastcc && !ath9k_hw_check_alive(ah))
 +      if (fastcc && (ah->chip_fullsleep ||
 +          !ath9k_hw_check_alive(ah)))
                fastcc = false;
  
        if (!ath_prepare_reset(sc, retry_tx, flush))
                fastcc = false;
  
 -      ath_dbg(common, ATH_DBG_CONFIG,
 -              "Reset to %u MHz, HT40: %d fastcc: %d\n",
 +      ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
                hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS |
                                                          CHANNEL_HT40PLUS)),
                fastcc);
@@@ -428,7 -428,7 +428,7 @@@ static bool ath_paprd_send_frame(struc
        txctl.paprd = BIT(chain);
  
        if (ath_tx_start(hw, skb, &txctl) != 0) {
 -              ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD TX failed\n");
 +              ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
                dev_kfree_skb_any(skb);
                return false;
        }
                        msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
  
        if (!time_left)
 -              ath_dbg(common, ATH_DBG_CALIBRATE,
 +              ath_dbg(common, CALIBRATE,
                        "Timeout waiting for paprd training on TX chain %d\n",
                        chain);
  
@@@ -486,27 -486,27 +486,27 @@@ void ath_paprd_calibrate(struct work_st
  
                chain_ok = 0;
  
 -              ath_dbg(common, ATH_DBG_CALIBRATE,
 -                      "Sending PAPRD frame for thermal measurement "
 -                      "on chain %d\n", chain);
 +              ath_dbg(common, CALIBRATE,
 +                      "Sending PAPRD frame for thermal measurement on chain %d\n",
 +                      chain);
                if (!ath_paprd_send_frame(sc, skb, chain))
                        goto fail_paprd;
  
                ar9003_paprd_setup_gain_table(ah, chain);
  
 -              ath_dbg(common, ATH_DBG_CALIBRATE,
 +              ath_dbg(common, CALIBRATE,
                        "Sending PAPRD training frame on chain %d\n", chain);
                if (!ath_paprd_send_frame(sc, skb, chain))
                        goto fail_paprd;
  
                if (!ar9003_paprd_is_done(ah)) {
 -                      ath_dbg(common, ATH_DBG_CALIBRATE,
 +                      ath_dbg(common, CALIBRATE,
                                "PAPRD not yet done on chain %d\n", chain);
                        break;
                }
  
                if (ar9003_paprd_create_curve(ah, caldata, chain)) {
 -                      ath_dbg(common, ATH_DBG_CALIBRATE,
 +                      ath_dbg(common, CALIBRATE,
                                "PAPRD create curve failed on chain %d\n",
                                                                   chain);
                        break;
@@@ -561,6 -561,7 +561,6 @@@ void ath_ani_calibrate(unsigned long da
        /* Long calibration runs independently of short calibration. */
        if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
                longcal = true;
 -              ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
                common->ani.longcal_timer = timestamp;
        }
  
        if (!common->ani.caldone) {
                if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
                        shortcal = true;
 -                      ath_dbg(common, ATH_DBG_ANI,
 -                              "shortcal @%lu\n", jiffies);
                        common->ani.shortcal_timer = timestamp;
                        common->ani.resetcal_timer = timestamp;
                }
        }
  
        /* Verify whether we must check ANI */
 -      if ((timestamp - common->ani.checkani_timer) >=
 -           ah->config.ani_poll_interval) {
 +      if (sc->sc_ah->config.enable_ani
 +          && (timestamp - common->ani.checkani_timer) >=
 +          ah->config.ani_poll_interval) {
                aniflag = true;
                common->ani.checkani_timer = timestamp;
        }
                                                ah->rxchainmask, longcal);
        }
  
 +      ath_dbg(common, ANI,
 +              "Calibration @%lu finished: %s %s %s, caldone: %s\n",
 +              jiffies,
 +              longcal ? "long" : "", shortcal ? "short" : "",
 +              aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
 +
        ath9k_ps_restore(sc);
  
  set_timer:
        }
  }
  
 -static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 +static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
 +                          struct ieee80211_vif *vif)
  {
        struct ath_node *an;
        an = (struct ath_node *)sta->drv_priv;
        spin_lock(&sc->nodes_lock);
        list_add(&an->list, &sc->nodes);
        spin_unlock(&sc->nodes_lock);
 -      an->sta = sta;
  #endif
 +      an->sta = sta;
 +      an->vif = vif;
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
                an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
@@@ -715,7 -709,8 +715,7 @@@ void ath9k_tasklet(unsigned long data
                 * TSF sync does not look correct; remain awake to sync with
                 * the next Beacon.
                 */
 -              ath_dbg(common, ATH_DBG_PS,
 -                      "TSFOOR - Sync with next Beacon\n");
 +              ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
                sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
  
                        ath_tx_tasklet(sc);
        }
  
 -      if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 +      if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
                if (status & ATH9K_INT_GENTIMER)
                        ath_gen_timer_isr(sc->sc_ah);
  
 +      if ((status & ATH9K_INT_MCI) && ATH9K_HW_CAP_MCI)
 +              ath_mci_intr(sc);
 +
  out:
        /* re-enable hardware interrupt */
        ath9k_hw_enable_interrupts(ah);
@@@ -770,8 -762,7 +770,8 @@@ irqreturn_t ath_isr(int irq, void *dev
                ATH9K_INT_BMISS |               \
                ATH9K_INT_CST |                 \
                ATH9K_INT_TSFOOR |              \
 -              ATH9K_INT_GENTIMER)
 +              ATH9K_INT_GENTIMER |            \
 +              ATH9K_INT_MCI)
  
        struct ath_softc *sc = dev;
        struct ath_hw *ah = sc->sc_ah;
@@@ -889,6 -880,82 +889,6 @@@ chip_reset
  #undef SCHED_INTR
  }
  
 -static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
 -      struct ieee80211_channel *channel = hw->conf.channel;
 -      int r;
 -
 -      ath9k_ps_wakeup(sc);
 -      spin_lock_bh(&sc->sc_pcu_lock);
 -      atomic_set(&ah->intr_ref_cnt, -1);
 -
 -      ath9k_hw_configpcipowersave(ah, false);
 -
 -      if (!ah->curchan)
 -              ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
 -
 -      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 -      if (r) {
 -              ath_err(common,
 -                      "Unable to reset channel (%u MHz), reset status %d\n",
 -                      channel->center_freq, r);
 -      }
 -
 -      ath_complete_reset(sc, true);
 -
 -      /* Enable LED */
 -      ath9k_hw_cfg_output(ah, ah->led_pin,
 -                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 -      ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 -
 -      spin_unlock_bh(&sc->sc_pcu_lock);
 -
 -      ath9k_ps_restore(sc);
 -}
 -
 -void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 -{
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ieee80211_channel *channel = hw->conf.channel;
 -      int r;
 -
 -      ath9k_ps_wakeup(sc);
 -
 -      ath_cancel_work(sc);
 -
 -      spin_lock_bh(&sc->sc_pcu_lock);
 -
 -      /*
 -       * Keep the LED on when the radio is disabled
 -       * during idle unassociated state.
 -       */
 -      if (!sc->ps_idle) {
 -              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
 -              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 -      }
 -
 -      ath_prepare_reset(sc, false, true);
 -
 -      if (!ah->curchan)
 -              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 -
 -      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 -      if (r) {
 -              ath_err(ath9k_hw_common(sc->sc_ah),
 -                      "Unable to reset channel (%u MHz), reset status %d\n",
 -                      channel->center_freq, r);
 -      }
 -
 -      ath9k_hw_phy_disable(ah);
 -
 -      ath9k_hw_configpcipowersave(ah, true);
 -
 -      spin_unlock_bh(&sc->sc_pcu_lock);
 -      ath9k_ps_restore(sc);
 -}
 -
  static int ath_reset(struct ath_softc *sc, bool retry_tx)
  {
        int r;
@@@ -935,8 -1002,8 +935,8 @@@ void ath_hw_check(struct work_struct *w
        busy = ath_update_survey_stats(sc);
        spin_unlock_irqrestore(&common->cc_lock, flags);
  
 -      ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
 -              "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
 +      ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
 +              busy, sc->hw_busy_count + 1);
        if (busy >= 99) {
                if (++sc->hw_busy_count >= 3) {
                        RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
@@@ -959,7 -1026,8 +959,7 @@@ static void ath_hw_pll_rx_hang_check(st
                count++;
                if (count == 3) {
                        /* Rx is hung for more than 500ms. Reset it */
 -                      ath_dbg(common, ATH_DBG_RESET,
 -                              "Possible RX hang, resetting");
 +                      ath_dbg(common, RESET, "Possible RX hang, resetting\n");
                        RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
                        count = 0;
@@@ -999,7 -1067,7 +999,7 @@@ static int ath9k_start(struct ieee80211
        struct ath9k_channel *init_channel;
        int r;
  
 -      ath_dbg(common, ATH_DBG_CONFIG,
 +      ath_dbg(common, CONFIG,
                "Starting driver with initial channel: %d MHz\n",
                curchan->center_freq);
  
         * and then setup of the interrupt mask.
         */
        spin_lock_bh(&sc->sc_pcu_lock);
 +
 +      atomic_set(&ah->intr_ref_cnt, -1);
 +
        r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (r) {
                ath_err(common,
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ah->imask |= ATH9K_INT_CST;
  
 +      if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
 +              ah->imask |= ATH9K_INT_MCI;
 +
        sc->sc_flags &= ~SC_OP_INVALID;
        sc->sc_ah->is_monitoring = false;
  
                goto mutex_unlock;
        }
  
 +      if (ah->led_pin >= 0) {
 +              ath9k_hw_cfg_output(ah, ah->led_pin,
 +                                  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 +              ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 +      }
 +
 +      /*
 +       * Reset key cache to sane defaults (all entries cleared) instead of
 +       * semi-random values after suspend/resume.
 +       */
 +      ath9k_cmn_init_crypto(sc->sc_ah);
 +
        spin_unlock_bh(&sc->sc_pcu_lock);
  
 -      if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
 +      if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) &&
            !ah->btcoex_hw.enabled) {
 -              ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 -                                         AR_STOMP_LOW_WLAN_WGHT);
 +              if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
 +                      ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 +                                                 AR_STOMP_LOW_WLAN_WGHT);
                ath9k_hw_btcoex_enable(ah);
  
 -              if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 +              if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
                        ath9k_btcoex_timer_resume(sc);
        }
  
@@@ -1118,19 -1167,12 +1118,19 @@@ static void ath9k_tx(struct ieee80211_h
                if (ieee80211_is_data(hdr->frame_control) &&
                    !ieee80211_is_nullfunc(hdr->frame_control) &&
                    !ieee80211_has_pm(hdr->frame_control)) {
 -                      ath_dbg(common, ATH_DBG_PS,
 +                      ath_dbg(common, PS,
                                "Add PM=1 for a TX frame while in PS mode\n");
                        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
                }
        }
  
 +      /*
 +       * Cannot tx while the hardware is in full sleep, it first needs a full
 +       * chip reset to recover from that
 +       */
 +      if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP))
 +              goto exit;
 +
        if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
                /*
                 * We are using PS-Poll and mac80211 can request TX while in
                if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                if (ieee80211_is_pspoll(hdr->frame_control)) {
 -                      ath_dbg(common, ATH_DBG_PS,
 +                      ath_dbg(common, PS,
                                "Sending PS-Poll to pick a buffered frame\n");
                        sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
                } else {
 -                      ath_dbg(common, ATH_DBG_PS,
 -                              "Wake up to complete TX\n");
 +                      ath_dbg(common, PS, "Wake up to complete TX\n");
                        sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
                }
                /*
        memset(&txctl, 0, sizeof(struct ath_tx_control));
        txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
  
 -      ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
 +      ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb);
  
        if (ath_tx_start(hw, skb, &txctl) != 0) {
 -              ath_dbg(common, ATH_DBG_XMIT, "TX failed\n");
 +              ath_dbg(common, XMIT, "TX failed\n");
                goto exit;
        }
  
@@@ -1176,14 -1219,13 +1176,14 @@@ static void ath9k_stop(struct ieee80211
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 +      bool prev_idle;
  
        mutex_lock(&sc->mutex);
  
        ath_cancel_work(sc);
  
        if (sc->sc_flags & SC_OP_INVALID) {
 -              ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
 +              ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
        }
        /* Ensure HW is awake when we try to shut it down. */
        ath9k_ps_wakeup(sc);
  
 -      if (ah->btcoex_hw.enabled) {
 +      if (ah->btcoex_hw.enabled &&
 +          ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
                ath9k_hw_btcoex_disable(ah);
 -              if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 +              if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
                        ath9k_btcoex_timer_pause(sc);
 +              ath_mci_flush_profile(&sc->btcoex.mci);
        }
  
        spin_lock_bh(&sc->sc_pcu_lock);
         * before setting the invalid flag. */
        ath9k_hw_disable_interrupts(ah);
  
 -      if (!(sc->sc_flags & SC_OP_INVALID)) {
 -              ath_drain_all_txq(sc, false);
 -              ath_stoprecv(sc);
 -              ath9k_hw_phy_disable(ah);
 -      } else
 -              sc->rx.rxlink = NULL;
 +      spin_unlock_bh(&sc->sc_pcu_lock);
 +
 +      /* we can now sync irq and kill any running tasklets, since we already
 +       * disabled interrupts and not holding a spin lock */
 +      synchronize_irq(sc->irq);
 +      tasklet_kill(&sc->intr_tq);
 +      tasklet_kill(&sc->bcon_tasklet);
 +
 +      prev_idle = sc->ps_idle;
 +      sc->ps_idle = true;
 +
 +      spin_lock_bh(&sc->sc_pcu_lock);
 +
 +      if (ah->led_pin >= 0) {
 +              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
 +              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 +      }
 +
 +      ath_prepare_reset(sc, false, true);
  
        if (sc->rx.frag) {
                dev_kfree_skb_any(sc->rx.frag);
                sc->rx.frag = NULL;
        }
  
 -      /* disable HAL and put h/w to sleep */
 -      ath9k_hw_disable(ah);
 +      if (!ah->curchan)
 +              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 +
 +      ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 +      ath9k_hw_phy_disable(ah);
  
 -      spin_unlock_bh(&sc->sc_pcu_lock);
 +      ath9k_hw_configpcipowersave(ah, true);
  
 -      /* we can now sync irq and kill any running tasklets, since we already
 -       * disabled interrupts and not holding a spin lock */
 -      synchronize_irq(sc->irq);
 -      tasklet_kill(&sc->intr_tq);
 -      tasklet_kill(&sc->bcon_tasklet);
 +      spin_unlock_bh(&sc->sc_pcu_lock);
  
        ath9k_ps_restore(sc);
  
 -      sc->ps_idle = true;
 -      ath_radio_disable(sc, hw);
 -
        sc->sc_flags |= SC_OP_INVALID;
 +      sc->ps_idle = prev_idle;
  
        mutex_unlock(&sc->mutex);
  
 -      ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
 +      ath_dbg(common, CONFIG, "Driver halt\n");
  }
  
  bool ath9k_uses_beacons(int type)
@@@ -1465,7 -1495,8 +1465,7 @@@ static int ath9k_add_interface(struct i
                goto out;
        }
  
 -      ath_dbg(common, ATH_DBG_CONFIG,
 -              "Attach a VIF of type: %d\n", vif->type);
 +      ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
  
        sc->nvifs++;
  
@@@ -1485,7 -1516,7 +1485,7 @@@ static int ath9k_change_interface(struc
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int ret = 0;
  
 -      ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
 +      ath_dbg(common, CONFIG, "Change Interface\n");
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
  
@@@ -1528,7 -1559,7 +1528,7 @@@ static void ath9k_remove_interface(stru
        struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  
 -      ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
 +      ath_dbg(common, CONFIG, "Detach Interface\n");
  
        ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
@@@ -1585,8 -1616,8 +1585,8 @@@ static int ath9k_config(struct ieee8021
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_conf *conf = &hw->conf;
 -      bool disable_radio = false;
  
 +      ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
  
        /*
         */
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 -              if (!sc->ps_idle) {
 -                      ath_radio_enable(sc, hw);
 -                      ath_dbg(common, ATH_DBG_CONFIG,
 -                              "not-idle: enabling radio\n");
 -              } else {
 -                      disable_radio = true;
 -              }
 +              if (sc->ps_idle)
 +                      ath_cancel_work(sc);
        }
  
        /*
  
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
 -                      ath_dbg(common, ATH_DBG_CONFIG,
 -                              "Monitor mode is enabled\n");
 +                      ath_dbg(common, CONFIG, "Monitor mode is enabled\n");
                        sc->sc_ah->is_monitoring = true;
                } else {
 -                      ath_dbg(common, ATH_DBG_CONFIG,
 -                              "Monitor mode is disabled\n");
 +                      ath_dbg(common, CONFIG, "Monitor mode is disabled\n");
                        sc->sc_ah->is_monitoring = false;
                }
        }
                else
                        sc->sc_flags &= ~SC_OP_OFFCHANNEL;
  
 -              ath_dbg(common, ATH_DBG_CONFIG,
 -                      "Set channel: %d MHz type: %d\n",
 +              ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
                        curchan->center_freq, conf->channel_type);
  
                /* update survey stats for the old channel before switching */
        }
  
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
 -              ath_dbg(common, ATH_DBG_CONFIG,
 -                      "Set power: %d\n", conf->power_level);
 +              ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
                sc->config.txpowlimit = 2 * conf->power_level;
 -              ath9k_ps_wakeup(sc);
                ath9k_cmn_update_txpow(ah, sc->curtxpow,
                                       sc->config.txpowlimit, &sc->curtxpow);
 -              ath9k_ps_restore(sc);
 -      }
 -
 -      if (disable_radio) {
 -              ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
 -              ath_radio_disable(sc, hw);
        }
  
        mutex_unlock(&sc->mutex);
 +      ath9k_ps_restore(sc);
  
        return 0;
  }
@@@ -1739,8 -1785,8 +1739,8 @@@ static void ath9k_configure_filter(stru
        ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
        ath9k_ps_restore(sc);
  
 -      ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
 -              "Set HW RX filter: 0x%x\n", rfilt);
 +      ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n",
 +              rfilt);
  }
  
  static int ath9k_sta_add(struct ieee80211_hw *hw,
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
        struct ieee80211_key_conf ps_key = { };
  
 -      ath_node_attach(sc, sta);
 +      ath_node_attach(sc, sta, vif);
  
        if (vif->type != NL80211_IFTYPE_AP &&
            vif->type != NL80211_IFTYPE_AP_VLAN)
@@@ -1797,6 -1843,9 +1797,9 @@@ static void ath9k_sta_notify(struct iee
        struct ath_softc *sc = hw->priv;
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
  
+       if (!(sc->sc_flags & SC_OP_TXAGGR))
+               return;
        switch (cmd) {
        case STA_NOTIFY_SLEEP:
                an->sleeping = true;
@@@ -1834,7 -1883,7 +1837,7 @@@ static int ath9k_conf_tx(struct ieee802
        qi.tqi_cwmax = params->cw_max;
        qi.tqi_burstTime = params->txop;
  
 -      ath_dbg(common, ATH_DBG_CONFIG,
 +      ath_dbg(common, CONFIG,
                "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
                queue, txq->axq_qnum, params->aifs, params->cw_min,
                params->cw_max, params->txop);
@@@ -1866,8 -1915,7 +1869,8 @@@ static int ath9k_set_key(struct ieee802
        if (ath9k_modparam_nohwcrypt)
                return -ENOSPC;
  
 -      if (vif->type == NL80211_IFTYPE_ADHOC &&
 +      if ((vif->type == NL80211_IFTYPE_ADHOC ||
 +           vif->type == NL80211_IFTYPE_MESH_POINT) &&
            (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
             key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
  
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
 -      ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
 +      ath_dbg(common, CONFIG, "Set HW Key\n");
  
        switch (cmd) {
        case SET_KEY:
@@@ -1935,8 -1983,9 +1938,8 @@@ static void ath9k_bss_iter(void *data, 
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = bss_conf->aid;
                ath9k_hw_write_associd(sc->sc_ah);
 -              ath_dbg(common, ATH_DBG_CONFIG,
 -                              "Bss Info ASSOC %d, bssid: %pM\n",
 -                              bss_conf->aid, common->curbssid);
 +              ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
 +                      bss_conf->aid, common->curbssid);
                ath_beacon_config(sc, vif);
                /*
                 * Request a re-configuration of Beacon related timers
@@@ -1967,7 -2016,8 +1970,7 @@@ static void ath9k_config_bss(struct ath
  
        /* Reconfigure bss info */
        if (avp->primary_sta_vif && !bss_conf->assoc) {
 -              ath_dbg(common, ATH_DBG_CONFIG,
 -                      "Bss Info DISASSOC %d, bssid %pM\n",
 +              ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
                        common->curaid, common->curbssid);
                sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
                avp->primary_sta_vif = false;
@@@ -2009,7 -2059,7 +2012,7 @@@ static void ath9k_bss_info_changed(stru
        if (changed & BSS_CHANGED_BSSID) {
                ath9k_config_bss(sc, vif);
  
 -              ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
 +              ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n",
                        common->curbssid, common->curaid);
        }
  
        }
  
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
 -              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
 +              ath_dbg(common, CONFIG, "BSS Changed PREAMBLE %d\n",
                        bss_conf->use_short_preamble);
                if (bss_conf->use_short_preamble)
                        sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
        }
  
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
 -              ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
 +              ath_dbg(common, CONFIG, "BSS Changed CTS PROT %d\n",
                        bss_conf->use_cts_prot);
                if (bss_conf->use_cts_prot &&
                    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
@@@ -2262,17 -2312,20 +2265,17 @@@ static void ath9k_flush(struct ieee8021
        cancel_delayed_work_sync(&sc->tx_complete_work);
  
        if (ah->ah_flags & AH_UNPLUGGED) {
 -              ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n");
 +              ath_dbg(common, ANY, "Device has been unplugged!\n");
                mutex_unlock(&sc->mutex);
                return;
        }
  
        if (sc->sc_flags & SC_OP_INVALID) {
 -              ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
 +              ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
        }
  
 -      if (drop)
 -              timeout = 1;
 -
        for (j = 0; j < timeout; j++) {
                bool npend = false;
  
                }
  
                if (!npend)
 -                  goto out;
 +                  break;
        }
  
 -      ath9k_ps_wakeup(sc);
 -      spin_lock_bh(&sc->sc_pcu_lock);
 -      drain_txq = ath_drain_all_txq(sc, false);
 -      spin_unlock_bh(&sc->sc_pcu_lock);
 +      if (drop) {
 +              ath9k_ps_wakeup(sc);
 +              spin_lock_bh(&sc->sc_pcu_lock);
 +              drain_txq = ath_drain_all_txq(sc, false);
 +              spin_unlock_bh(&sc->sc_pcu_lock);
  
 -      if (!drain_txq)
 -              ath_reset(sc, false);
 +              if (!drain_txq)
 +                      ath_reset(sc, false);
  
 -      ath9k_ps_restore(sc);
 -      ieee80211_wake_queues(hw);
 +              ath9k_ps_restore(sc);
 +              ieee80211_wake_queues(hw);
 +      }
  
 -out:
        ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
        mutex_unlock(&sc->mutex);
  }
index d07b412a32c41fd93ce0dd0ce493ca2f043427f6,279a53eae4c57108b26b8e5e25fdf27a053ca9af..3533ab86bd363982e4ffd5f73e7e7af1dacc70d6
@@@ -539,7 -539,7 +539,7 @@@ int b43_pio_tx(struct b43_wldev *dev, s
                /* Not enough memory on the queue. */
                err = -EBUSY;
                ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
 -              q->stopped = 1;
 +              q->stopped = true;
                goto out;
        }
  
            (q->free_packet_slots == 0)) {
                /* The queue is full. */
                ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
 -              q->stopped = 1;
 +              q->stopped = true;
        }
  
  out:
@@@ -601,7 -601,7 +601,7 @@@ void b43_pio_handle_txstatus(struct b43
  
        if (q->stopped) {
                ieee80211_wake_queue(dev->wl->hw, q->queue_prio);
 -              q->stopped = 0;
 +              q->stopped = false;
        }
  }
  
@@@ -617,9 -617,19 +617,19 @@@ static bool pio_rx_frame(struct b43_pio
        const char *err_msg = NULL;
        struct b43_rxhdr_fw4 *rxhdr =
                (struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
+       size_t rxhdr_size = sizeof(*rxhdr);
  
        BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
-       memset(rxhdr, 0, sizeof(*rxhdr));
+       switch (dev->fw.hdr_format) {
+       case B43_FW_HDR_410:
+       case B43_FW_HDR_351:
+               rxhdr_size -= sizeof(rxhdr->format_598) -
+                       sizeof(rxhdr->format_351);
+               break;
+       case B43_FW_HDR_598:
+               break;
+       }
+       memset(rxhdr, 0, rxhdr_size);
  
        /* Check if we have data and wait for it to get ready. */
        if (q->rev >= 8) {
@@@ -657,11 -667,11 +667,11 @@@ data_ready
  
        /* Get the preamble (RX header) */
        if (q->rev >= 8) {
-               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, rxhdr_size,
                               q->mmio_base + B43_PIO8_RXDATA,
                               sizeof(u32));
        } else {
-               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, rxhdr_size,
                               q->mmio_base + B43_PIO_RXDATA,
                               sizeof(u16));
        }
index e40196dfdea06dba7a4185440cd71ea8830c2a92,1679c2593b7ba7d2975f584e250241a1892b341d..470ca75ec250ae522184a1da80170d247ea6733f
@@@ -55,9 -55,14 +55,14 @@@ int mwifiex_wait_queue_complete(struct 
  {
        bool cancel_flag = false;
        int status = adapter->cmd_wait_q.status;
-       struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued;
+       struct cmd_ctrl_node *cmd_queued;
  
+       if (!adapter->cmd_queued)
+               return 0;
+       cmd_queued = adapter->cmd_queued;
        adapter->cmd_queued = NULL;
        dev_dbg(adapter->dev, "cmd pending\n");
        atomic_inc(&adapter->cmd_pending);
  
@@@ -234,7 -239,7 +239,7 @@@ int mwifiex_bss_start(struct mwifiex_pr
                                      "associating...\n");
  
                if (!netif_queue_stopped(priv->netdev))
 -                      netif_stop_queue(priv->netdev);
 +                      mwifiex_stop_net_dev_queue(priv->netdev, adapter);
  
                /* Clear any past association response stored for
                 * application retrieval */
                ret = mwifiex_check_network_compatibility(priv, bss_desc);
  
                if (!netif_queue_stopped(priv->netdev))
 -                      netif_stop_queue(priv->netdev);
 +                      mwifiex_stop_net_dev_queue(priv->netdev, adapter);
  
                if (!ret) {
                        dev_dbg(adapter->dev, "info: network found in scan"
@@@ -471,6 -476,67 +476,6 @@@ int mwifiex_get_bss_info(struct mwifiex
        return 0;
  }
  
 -/*
 - * The function sets band configurations.
 - *
 - * it performs extra checks to make sure the Ad-Hoc
 - * band and channel are compatible. Otherwise it returns an error.
 - *
 - */
 -int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv,
 -                             struct mwifiex_ds_band_cfg *radio_cfg)
 -{
 -      struct mwifiex_adapter *adapter = priv->adapter;
 -      u8 infra_band, adhoc_band;
 -      u32 adhoc_channel;
 -
 -      infra_band = (u8) radio_cfg->config_bands;
 -      adhoc_band = (u8) radio_cfg->adhoc_start_band;
 -      adhoc_channel = radio_cfg->adhoc_channel;
 -
 -      /* SET Infra band */
 -      if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
 -              return -1;
 -
 -      adapter->config_bands = infra_band;
 -
 -      /* SET Ad-hoc Band */
 -      if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
 -              return -1;
 -
 -      if (adhoc_band)
 -              adapter->adhoc_start_band = adhoc_band;
 -      adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
 -      /*
 -       * If no adhoc_channel is supplied verify if the existing adhoc
 -       * channel compiles with new adhoc_band
 -       */
 -      if (!adhoc_channel) {
 -              if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
 -                   (priv, adapter->adhoc_start_band,
 -                   priv->adhoc_channel)) {
 -                      /* Pass back the default channel */
 -                      radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
 -                      if ((adapter->adhoc_start_band & BAND_A)
 -                          || (adapter->adhoc_start_band & BAND_AN))
 -                              radio_cfg->adhoc_channel =
 -                                      DEFAULT_AD_HOC_CHANNEL_A;
 -              }
 -      } else {        /* Retrurn error if adhoc_band and
 -                         adhoc_channel combination is invalid */
 -              if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
 -                  (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
 -                      return -1;
 -              priv->adhoc_channel = (u8) adhoc_channel;
 -      }
 -      if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
 -              adapter->adhoc_11n_enabled = true;
 -      else
 -              adapter->adhoc_11n_enabled = false;
 -
 -      return 0;
 -}
 -
  /*
   * The function disables auto deep sleep mode.
   */
@@@ -771,8 -837,8 +776,8 @@@ int mwifiex_drv_get_data_rate(struct mw
  
        if (!ret) {
                if (rate->is_rate_auto)
 -                      rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
 -                                                      priv->tx_htinfo);
 +                      rate->rate = mwifiex_index_to_data_rate(priv,
 +                                      priv->tx_rate, priv->tx_htinfo);
                else
                        rate->rate = priv->data_rate;
        } else {
diff --combined net/bluetooth/hci_core.c
index 6d38d80195cb40c43ae6c292a7406e58d64d05b3,b84458dcc2261259d83e1bad2aecef95ed622113..845da3ee56a0d3966bdeb5ab627ef3dc49c8dead
@@@ -1,7 -1,6 +1,7 @@@
  /*
     BlueZ - Bluetooth protocol stack for Linux
     Copyright (C) 2000-2001 Qualcomm Incorporated
 +   Copyright (C) 2011 ProFUSION Embedded Systems
  
     Written 2000,2001 by Maxim Krasnyansky <[email protected]>
  
  
  #define AUTO_OFF_TIMEOUT 2000
  
 -static void hci_cmd_task(unsigned long arg);
 -static void hci_rx_task(unsigned long arg);
 -static void hci_tx_task(unsigned long arg);
 +int enable_hs;
  
 -static DEFINE_RWLOCK(hci_task_lock);
 +static void hci_rx_work(struct work_struct *work);
 +static void hci_cmd_work(struct work_struct *work);
 +static void hci_tx_work(struct work_struct *work);
  
  /* HCI device list */
  LIST_HEAD(hci_dev_list);
@@@ -69,6 -68,10 +69,6 @@@ DEFINE_RWLOCK(hci_dev_list_lock)
  LIST_HEAD(hci_cb_list);
  DEFINE_RWLOCK(hci_cb_list_lock);
  
 -/* HCI protocols */
 -#define HCI_MAX_PROTO 2
 -struct hci_proto *hci_proto[HCI_MAX_PROTO];
 -
  /* HCI notifiers list */
  static ATOMIC_NOTIFIER_HEAD(hci_notifier);
  
@@@ -187,20 -190,33 +187,20 @@@ static void hci_reset_req(struct hci_de
        hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
  }
  
 -static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 +static void bredr_init(struct hci_dev *hdev)
  {
        struct hci_cp_delete_stored_link_key cp;
 -      struct sk_buff *skb;
        __le16 param;
        __u8 flt_type;
  
 -      BT_DBG("%s %ld", hdev->name, opt);
 -
 -      /* Driver initialization */
 -
 -      /* Special commands */
 -      while ((skb = skb_dequeue(&hdev->driver_init))) {
 -              bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
 -              skb->dev = (void *) hdev;
 -
 -              skb_queue_tail(&hdev->cmd_q, skb);
 -              tasklet_schedule(&hdev->cmd_task);
 -      }
 -      skb_queue_purge(&hdev->driver_init);
 +      hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
  
        /* Mandatory initialization */
  
        /* Reset */
        if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
 -                      set_bit(HCI_RESET, &hdev->flags);
 -                      hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 +              set_bit(HCI_RESET, &hdev->flags);
 +              hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
        }
  
        /* Read Local Supported Features */
        /* Read Buffer Size (ACL mtu, max pkt, etc.) */
        hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
  
 -#if 0
 -      /* Host buffer size */
 -      {
 -              struct hci_cp_host_buffer_size cp;
 -              cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
 -              cp.sco_mtu = HCI_MAX_SCO_SIZE;
 -              cp.acl_max_pkt = cpu_to_le16(0xffff);
 -              cp.sco_max_pkt = cpu_to_le16(0xffff);
 -              hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
 -      }
 -#endif
 -
        /* Read BD Address */
        hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
  
        hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
  }
  
 +static void amp_init(struct hci_dev *hdev)
 +{
 +      hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
 +
 +      /* Reset */
 +      hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 +
 +      /* Read Local Version */
 +      hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 +}
 +
 +static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 +{
 +      struct sk_buff *skb;
 +
 +      BT_DBG("%s %ld", hdev->name, opt);
 +
 +      /* Driver initialization */
 +
 +      /* Special commands */
 +      while ((skb = skb_dequeue(&hdev->driver_init))) {
 +              bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
 +              skb->dev = (void *) hdev;
 +
 +              skb_queue_tail(&hdev->cmd_q, skb);
 +              queue_work(hdev->workqueue, &hdev->cmd_work);
 +      }
 +      skb_queue_purge(&hdev->driver_init);
 +
 +      switch (hdev->dev_type) {
 +      case HCI_BREDR:
 +              bredr_init(hdev);
 +              break;
 +
 +      case HCI_AMP:
 +              amp_init(hdev);
 +              break;
 +
 +      default:
 +              BT_ERR("Unknown device type %d", hdev->dev_type);
 +              break;
 +      }
 +
 +}
 +
  static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
  {
        BT_DBG("%s", hdev->name);
@@@ -336,7 -319,8 +336,7 @@@ static void hci_linkpol_req(struct hci_
   * Device is held on return. */
  struct hci_dev *hci_dev_get(int index)
  {
 -      struct hci_dev *hdev = NULL;
 -      struct list_head *p;
 +      struct hci_dev *hdev = NULL, *d;
  
        BT_DBG("%d", index);
  
                return NULL;
  
        read_lock(&hci_dev_list_lock);
 -      list_for_each(p, &hci_dev_list) {
 -              struct hci_dev *d = list_entry(p, struct hci_dev, list);
 +      list_for_each_entry(d, &hci_dev_list, list) {
                if (d->id == index) {
                        hdev = hci_dev_hold(d);
                        break;
@@@ -460,14 -445,14 +460,14 @@@ int hci_inquiry(void __user *arg
        if (!hdev)
                return -ENODEV;
  
 -      hci_dev_lock_bh(hdev);
 +      hci_dev_lock(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
                                inquiry_cache_empty(hdev) ||
                                ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
                do_inquiry = 1;
        }
 -      hci_dev_unlock_bh(hdev);
 +      hci_dev_unlock(hdev);
  
        timeo = ir.length * msecs_to_jiffies(2000);
  
                goto done;
        }
  
 -      hci_dev_lock_bh(hdev);
 +      hci_dev_lock(hdev);
        ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
 -      hci_dev_unlock_bh(hdev);
 +      hci_dev_unlock(hdev);
  
        BT_DBG("num_rsp %d", ir.num_rsp);
  
@@@ -538,9 -523,8 +538,9 @@@ int hci_dev_open(__u16 dev
        if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
                set_bit(HCI_RAW, &hdev->flags);
  
 -      /* Treat all non BR/EDR controllers as raw devices for now */
 -      if (hdev->dev_type != HCI_BREDR)
 +      /* Treat all non BR/EDR controllers as raw devices if
 +         enable_hs is not set */
 +      if (hdev->dev_type != HCI_BREDR && !enable_hs)
                set_bit(HCI_RAW, &hdev->flags);
  
        if (hdev->open(hdev)) {
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
 -              if (!test_bit(HCI_SETUP, &hdev->flags))
 -                      mgmt_powered(hdev->id, 1);
 +              if (!test_bit(HCI_SETUP, &hdev->flags)) {
 +                      hci_dev_lock(hdev);
 +                      mgmt_powered(hdev, 1);
 +                      hci_dev_unlock(hdev);
 +              }
        } else {
                /* Init failed, cleanup */
 -              tasklet_kill(&hdev->rx_task);
 -              tasklet_kill(&hdev->tx_task);
 -              tasklet_kill(&hdev->cmd_task);
 +              flush_work(&hdev->tx_work);
 +              flush_work(&hdev->cmd_work);
 +              flush_work(&hdev->rx_work);
  
                skb_queue_purge(&hdev->cmd_q);
                skb_queue_purge(&hdev->rx_q);
@@@ -612,25 -593,14 +612,25 @@@ static int hci_dev_do_close(struct hci_
                return 0;
        }
  
 -      /* Kill RX and TX tasks */
 -      tasklet_kill(&hdev->rx_task);
 -      tasklet_kill(&hdev->tx_task);
 +      /* Flush RX and TX works */
 +      flush_work(&hdev->tx_work);
 +      flush_work(&hdev->rx_work);
 +
 +      if (hdev->discov_timeout > 0) {
 +              cancel_delayed_work(&hdev->discov_off);
 +              hdev->discov_timeout = 0;
 +      }
  
 -      hci_dev_lock_bh(hdev);
 +      if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
 +              cancel_delayed_work(&hdev->power_off);
 +
 +      if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
 +              cancel_delayed_work(&hdev->service_cache);
 +
 +      hci_dev_lock(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
 -      hci_dev_unlock_bh(hdev);
 +      hci_dev_unlock(hdev);
  
        hci_notify(hdev, HCI_DEV_DOWN);
  
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                set_bit(HCI_INIT, &hdev->flags);
                __hci_request(hdev, hci_reset_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                       msecs_to_jiffies(250));
                clear_bit(HCI_INIT, &hdev->flags);
        }
  
 -      /* Kill cmd task */
 -      tasklet_kill(&hdev->cmd_task);
 +      /* flush cmd  work */
 +      flush_work(&hdev->cmd_work);
  
        /* Drop queues */
        skb_queue_purge(&hdev->rx_q);
         * and no tasks are scheduled. */
        hdev->close(hdev);
  
 -      mgmt_powered(hdev->id, 0);
 +      hci_dev_lock(hdev);
 +      mgmt_powered(hdev, 0);
 +      hci_dev_unlock(hdev);
  
        /* Clear flags */
        hdev->flags = 0;
@@@ -702,6 -670,7 +702,6 @@@ int hci_dev_reset(__u16 dev
                return -ENODEV;
  
        hci_req_lock(hdev);
 -      tasklet_disable(&hdev->tx_task);
  
        if (!test_bit(HCI_UP, &hdev->flags))
                goto done;
        skb_queue_purge(&hdev->rx_q);
        skb_queue_purge(&hdev->cmd_q);
  
 -      hci_dev_lock_bh(hdev);
 +      hci_dev_lock(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
 -      hci_dev_unlock_bh(hdev);
 +      hci_dev_unlock(hdev);
  
        if (hdev->flush)
                hdev->flush(hdev);
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
  
  done:
 -      tasklet_enable(&hdev->tx_task);
        hci_req_unlock(hdev);
        hci_dev_put(hdev);
        return ret;
@@@ -824,9 -794,9 +824,9 @@@ int hci_dev_cmd(unsigned int cmd, void 
  
  int hci_get_dev_list(void __user *arg)
  {
 +      struct hci_dev *hdev;
        struct hci_dev_list_req *dl;
        struct hci_dev_req *dr;
 -      struct list_head *p;
        int n = 0, size, err;
        __u16 dev_num;
  
  
        dr = dl->dev_req;
  
 -      read_lock_bh(&hci_dev_list_lock);
 -      list_for_each(p, &hci_dev_list) {
 -              struct hci_dev *hdev;
 -
 -              hdev = list_entry(p, struct hci_dev, list);
 -
 -              hci_del_off_timer(hdev);
 +      read_lock(&hci_dev_list_lock);
 +      list_for_each_entry(hdev, &hci_dev_list, list) {
 +              if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
 +                      cancel_delayed_work(&hdev->power_off);
  
                if (!test_bit(HCI_MGMT, &hdev->flags))
                        set_bit(HCI_PAIRABLE, &hdev->flags);
                if (++n >= dev_num)
                        break;
        }
 -      read_unlock_bh(&hci_dev_list_lock);
 +      read_unlock(&hci_dev_list_lock);
  
        dl->dev_num = n;
        size = sizeof(*dl) + n * sizeof(*dr);
@@@ -882,8 -855,7 +882,8 @@@ int hci_get_dev_info(void __user *arg
        if (!hdev)
                return -ENODEV;
  
 -      hci_del_off_timer(hdev);
 +      if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
 +              cancel_delayed_work_sync(&hdev->power_off);
  
        if (!test_bit(HCI_MGMT, &hdev->flags))
                set_bit(HCI_PAIRABLE, &hdev->flags);
@@@ -940,7 -912,6 +940,7 @@@ struct hci_dev *hci_alloc_dev(void
        if (!hdev)
                return NULL;
  
 +      hci_init_sysfs(hdev);
        skb_queue_head_init(&hdev->driver_init);
  
        return hdev;
@@@ -967,41 -938,39 +967,41 @@@ static void hci_power_on(struct work_st
                return;
  
        if (test_bit(HCI_AUTO_OFF, &hdev->flags))
 -              mod_timer(&hdev->off_timer,
 -                              jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 +              schedule_delayed_work(&hdev->power_off,
 +                                      msecs_to_jiffies(AUTO_OFF_TIMEOUT));
  
        if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
 -              mgmt_index_added(hdev->id);
 +              mgmt_index_added(hdev);
  }
  
  static void hci_power_off(struct work_struct *work)
  {
 -      struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
 +      struct hci_dev *hdev = container_of(work, struct hci_dev,
 +                                                      power_off.work);
  
        BT_DBG("%s", hdev->name);
  
 +      clear_bit(HCI_AUTO_OFF, &hdev->flags);
 +
        hci_dev_close(hdev->id);
  }
  
 -static void hci_auto_off(unsigned long data)
 +static void hci_discov_off(struct work_struct *work)
  {
 -      struct hci_dev *hdev = (struct hci_dev *) data;
 +      struct hci_dev *hdev;
 +      u8 scan = SCAN_PAGE;
 +
 +      hdev = container_of(work, struct hci_dev, discov_off.work);
  
        BT_DBG("%s", hdev->name);
  
 -      clear_bit(HCI_AUTO_OFF, &hdev->flags);
 +      hci_dev_lock(hdev);
  
 -      queue_work(hdev->workqueue, &hdev->power_off);
 -}
 +      hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
  
 -void hci_del_off_timer(struct hci_dev *hdev)
 -{
 -      BT_DBG("%s", hdev->name);
 +      hdev->discov_timeout = 0;
  
 -      clear_bit(HCI_AUTO_OFF, &hdev->flags);
 -      del_timer(&hdev->off_timer);
 +      hci_dev_unlock(hdev);
  }
  
  int hci_uuids_clear(struct hci_dev *hdev)
@@@ -1038,11 -1007,16 +1038,11 @@@ int hci_link_keys_clear(struct hci_dev 
  
  struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
  {
 -      struct list_head *p;
 -
 -      list_for_each(p, &hdev->link_keys) {
 -              struct link_key *k;
 -
 -              k = list_entry(p, struct link_key, list);
 +      struct link_key *k;
  
 +      list_for_each_entry(k, &hdev->link_keys, list)
                if (bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
 -      }
  
        return NULL;
  }
@@@ -1164,7 -1138,7 +1164,7 @@@ int hci_add_link_key(struct hci_dev *hd
  
        persistent = hci_persistent_key(hdev, conn, type, old_key_type);
  
 -      mgmt_new_key(hdev->id, key, persistent);
 +      mgmt_new_link_key(hdev, key, persistent);
  
        if (!persistent) {
                list_del(&key->list);
@@@ -1207,7 -1181,7 +1207,7 @@@ int hci_add_ltk(struct hci_dev *hdev, i
        memcpy(id->rand, rand, sizeof(id->rand));
  
        if (new_key)
 -              mgmt_new_key(hdev->id, key, old_key_type);
 +              mgmt_new_link_key(hdev, key, old_key_type);
  
        return 0;
  }
@@@ -1235,7 -1209,7 +1235,7 @@@ static void hci_cmd_timer(unsigned lon
  
        BT_ERR("%s command tx timeout", hdev->name);
        atomic_set(&hdev->cmd_cnt, 1);
 -      tasklet_schedule(&hdev->cmd_task);
 +      queue_work(hdev->workqueue, &hdev->cmd_work);
  }
  
  struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
@@@ -1305,11 -1279,16 +1305,11 @@@ int hci_add_remote_oob_data(struct hci_
  struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
                                                bdaddr_t *bdaddr)
  {
 -      struct list_head *p;
 -
 -      list_for_each(p, &hdev->blacklist) {
 -              struct bdaddr_list *b;
 -
 -              b = list_entry(p, struct bdaddr_list, list);
 +      struct bdaddr_list *b;
  
 +      list_for_each_entry(b, &hdev->blacklist, list)
                if (bacmp(bdaddr, &b->bdaddr) == 0)
                        return b;
 -      }
  
        return NULL;
  }
@@@ -1348,30 -1327,31 +1348,30 @@@ int hci_blacklist_add(struct hci_dev *h
  
        list_add(&entry->list, &hdev->blacklist);
  
 -      return mgmt_device_blocked(hdev->id, bdaddr);
 +      return mgmt_device_blocked(hdev, bdaddr);
  }
  
  int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
  {
        struct bdaddr_list *entry;
  
 -      if (bacmp(bdaddr, BDADDR_ANY) == 0) {
 +      if (bacmp(bdaddr, BDADDR_ANY) == 0)
                return hci_blacklist_clear(hdev);
 -      }
  
        entry = hci_blacklist_lookup(hdev, bdaddr);
 -      if (!entry) {
 +      if (!entry)
                return -ENOENT;
 -      }
  
        list_del(&entry->list);
        kfree(entry);
  
 -      return mgmt_device_unblocked(hdev->id, bdaddr);
 +      return mgmt_device_unblocked(hdev, bdaddr);
  }
  
 -static void hci_clear_adv_cache(unsigned long arg)
 +static void hci_clear_adv_cache(struct work_struct *work)
  {
 -      struct hci_dev *hdev = (void *) arg;
 +      struct hci_dev *hdev = container_of(work, struct hci_dev,
 +                                                      adv_work.work);
  
        hci_dev_lock(hdev);
  
@@@ -1445,7 -1425,7 +1445,7 @@@ int hci_add_adv_entry(struct hci_dev *h
  int hci_register_dev(struct hci_dev *hdev)
  {
        struct list_head *head = &hci_dev_list, *p;
 -      int i, id = 0;
 +      int i, id, error;
  
        BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
                                                hdev->bus, hdev->owner);
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
  
 -      write_lock_bh(&hci_dev_list_lock);
 +      /* Do not allow HCI_AMP devices to register at index 0,
 +       * so the index can be used as the AMP controller ID.
 +       */
 +      id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
 +
 +      write_lock(&hci_dev_list_lock);
  
        /* Find first available device id */
        list_for_each(p, &hci_dev_list) {
  
        sprintf(hdev->name, "hci%d", id);
        hdev->id = id;
 -      list_add(&hdev->list, head);
 +      list_add_tail(&hdev->list, head);
  
        atomic_set(&hdev->refcnt, 1);
 -      spin_lock_init(&hdev->lock);
 +      mutex_init(&hdev->lock);
  
        hdev->flags = 0;
 +      hdev->dev_flags = 0;
        hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
        hdev->esco_type = (ESCO_HV1);
        hdev->link_mode = (HCI_LM_ACCEPT);
        hdev->sniff_max_interval = 800;
        hdev->sniff_min_interval = 80;
  
 -      tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
 -      tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
 -      tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
 +      INIT_WORK(&hdev->rx_work, hci_rx_work);
 +      INIT_WORK(&hdev->cmd_work, hci_cmd_work);
 +      INIT_WORK(&hdev->tx_work, hci_tx_work);
 +
  
        skb_queue_head_init(&hdev->rx_q);
        skb_queue_head_init(&hdev->cmd_q);
  
        hci_conn_hash_init(hdev);
  
 +      INIT_LIST_HEAD(&hdev->mgmt_pending);
 +
        INIT_LIST_HEAD(&hdev->blacklist);
  
        INIT_LIST_HEAD(&hdev->uuids);
        INIT_LIST_HEAD(&hdev->remote_oob_data);
  
        INIT_LIST_HEAD(&hdev->adv_entries);
 -      setup_timer(&hdev->adv_timer, hci_clear_adv_cache,
 -                                              (unsigned long) hdev);
  
 +      INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache);
        INIT_WORK(&hdev->power_on, hci_power_on);
 -      INIT_WORK(&hdev->power_off, hci_power_off);
 -      setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
 +      INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
 +
 +      INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
  
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
  
        atomic_set(&hdev->promisc, 0);
  
 -      write_unlock_bh(&hci_dev_list_lock);
 +      write_unlock(&hci_dev_list_lock);
  
 -      hdev->workqueue = create_singlethread_workqueue(hdev->name);
 -      if (!hdev->workqueue)
 -              goto nomem;
 +      hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
 +                                                      WQ_MEM_RECLAIM, 1);
 +      if (!hdev->workqueue) {
 +              error = -ENOMEM;
 +              goto err;
 +      }
  
 -      hci_register_sysfs(hdev);
 +      error = hci_add_sysfs(hdev);
 +      if (error < 0)
 +              goto err_wqueue;
  
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
  
        set_bit(HCI_AUTO_OFF, &hdev->flags);
        set_bit(HCI_SETUP, &hdev->flags);
 -      queue_work(hdev->workqueue, &hdev->power_on);
 +      schedule_work(&hdev->power_on);
  
        hci_notify(hdev, HCI_DEV_REG);
  
        return id;
  
 -nomem:
 -      write_lock_bh(&hci_dev_list_lock);
 +err_wqueue:
 +      destroy_workqueue(hdev->workqueue);
 +err:
 +      write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
 -      write_unlock_bh(&hci_dev_list_lock);
 +      write_unlock(&hci_dev_list_lock);
  
 -      return -ENOMEM;
 +      return error;
  }
  EXPORT_SYMBOL(hci_register_dev);
  
  /* Unregister HCI device */
 -int hci_unregister_dev(struct hci_dev *hdev)
 +void hci_unregister_dev(struct hci_dev *hdev)
  {
        int i;
  
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
  
 -      write_lock_bh(&hci_dev_list_lock);
 +      write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
 -      write_unlock_bh(&hci_dev_list_lock);
 +      write_unlock(&hci_dev_list_lock);
  
        hci_dev_do_close(hdev);
  
                kfree_skb(hdev->reassembly[i]);
  
        if (!test_bit(HCI_INIT, &hdev->flags) &&
 -                                      !test_bit(HCI_SETUP, &hdev->flags))
 -              mgmt_index_removed(hdev->id);
 +                                      !test_bit(HCI_SETUP, &hdev->flags)) {
 +              hci_dev_lock(hdev);
 +              mgmt_index_removed(hdev);
 +              hci_dev_unlock(hdev);
 +      }
 +
 +      /* mgmt_index_removed should take care of emptying the
 +       * pending list */
 +      BUG_ON(!list_empty(&hdev->mgmt_pending));
  
        hci_notify(hdev, HCI_DEV_UNREG);
  
                rfkill_destroy(hdev->rfkill);
        }
  
 -      hci_unregister_sysfs(hdev);
 +      hci_del_sysfs(hdev);
  
 -      hci_del_off_timer(hdev);
 -      del_timer(&hdev->adv_timer);
 +      cancel_delayed_work_sync(&hdev->adv_work);
  
        destroy_workqueue(hdev->workqueue);
  
 -      hci_dev_lock_bh(hdev);
 +      hci_dev_lock(hdev);
        hci_blacklist_clear(hdev);
        hci_uuids_clear(hdev);
        hci_link_keys_clear(hdev);
        hci_remote_oob_data_clear(hdev);
        hci_adv_entries_clear(hdev);
 -      hci_dev_unlock_bh(hdev);
 +      hci_dev_unlock(hdev);
  
        __hci_dev_put(hdev);
 -
 -      return 0;
  }
  EXPORT_SYMBOL(hci_unregister_dev);
  
@@@ -1653,8 -1613,9 +1653,8 @@@ int hci_recv_frame(struct sk_buff *skb
        /* Time stamp */
        __net_timestamp(skb);
  
 -      /* Queue frame for rx task */
        skb_queue_tail(&hdev->rx_q, skb);
 -      tasklet_schedule(&hdev->rx_task);
 +      queue_work(hdev->workqueue, &hdev->rx_work);
  
        return 0;
  }
@@@ -1826,13 -1787,59 +1826,13 @@@ EXPORT_SYMBOL(hci_recv_stream_fragment)
  
  /* ---- Interface to upper protocols ---- */
  
 -/* Register/Unregister protocols.
 - * hci_task_lock is used to ensure that no tasks are running. */
 -int hci_register_proto(struct hci_proto *hp)
 -{
 -      int err = 0;
 -
 -      BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
 -
 -      if (hp->id >= HCI_MAX_PROTO)
 -              return -EINVAL;
 -
 -      write_lock_bh(&hci_task_lock);
 -
 -      if (!hci_proto[hp->id])
 -              hci_proto[hp->id] = hp;
 -      else
 -              err = -EEXIST;
 -
 -      write_unlock_bh(&hci_task_lock);
 -
 -      return err;
 -}
 -EXPORT_SYMBOL(hci_register_proto);
 -
 -int hci_unregister_proto(struct hci_proto *hp)
 -{
 -      int err = 0;
 -
 -      BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
 -
 -      if (hp->id >= HCI_MAX_PROTO)
 -              return -EINVAL;
 -
 -      write_lock_bh(&hci_task_lock);
 -
 -      if (hci_proto[hp->id])
 -              hci_proto[hp->id] = NULL;
 -      else
 -              err = -ENOENT;
 -
 -      write_unlock_bh(&hci_task_lock);
 -
 -      return err;
 -}
 -EXPORT_SYMBOL(hci_unregister_proto);
 -
  int hci_register_cb(struct hci_cb *cb)
  {
        BT_DBG("%p name %s", cb, cb->name);
  
 -      write_lock_bh(&hci_cb_list_lock);
 +      write_lock(&hci_cb_list_lock);
        list_add(&cb->list, &hci_cb_list);
 -      write_unlock_bh(&hci_cb_list_lock);
 +      write_unlock(&hci_cb_list_lock);
  
        return 0;
  }
@@@ -1842,9 -1849,9 +1842,9 @@@ int hci_unregister_cb(struct hci_cb *cb
  {
        BT_DBG("%p name %s", cb, cb->name);
  
 -      write_lock_bh(&hci_cb_list_lock);
 +      write_lock(&hci_cb_list_lock);
        list_del(&cb->list);
 -      write_unlock_bh(&hci_cb_list_lock);
 +      write_unlock(&hci_cb_list_lock);
  
        return 0;
  }
@@@ -1905,7 -1912,7 +1905,7 @@@ int hci_send_cmd(struct hci_dev *hdev, 
                hdev->init_last_cmd = opcode;
  
        skb_queue_tail(&hdev->cmd_q, skb);
 -      tasklet_schedule(&hdev->cmd_task);
 +      queue_work(hdev->workqueue, &hdev->cmd_work);
  
        return 0;
  }
@@@ -1941,18 -1948,23 +1941,18 @@@ static void hci_add_acl_hdr(struct sk_b
        hdr->dlen   = cpu_to_le16(len);
  }
  
 -void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 +static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
 +                              struct sk_buff *skb, __u16 flags)
  {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
  
 -      BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
 -
 -      skb->dev = (void *) hdev;
 -      bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
 -      hci_add_acl_hdr(skb, conn->handle, flags);
 -
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
                /* Non fragmented */
                BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
  
 -              skb_queue_tail(&conn->data_q, skb);
 +              skb_queue_tail(queue, skb);
        } else {
                /* Fragmented */
                BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
                skb_shinfo(skb)->frag_list = NULL;
  
                /* Queue all fragments atomically */
 -              spin_lock_bh(&conn->data_q.lock);
 +              spin_lock(&queue->lock);
  
 -              __skb_queue_tail(&conn->data_q, skb);
 +              __skb_queue_tail(queue, skb);
  
                flags &= ~ACL_START;
                flags |= ACL_CONT;
  
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
  
 -                      __skb_queue_tail(&conn->data_q, skb);
 +                      __skb_queue_tail(queue, skb);
                } while (list);
  
 -              spin_unlock_bh(&conn->data_q.lock);
 +              spin_unlock(&queue->lock);
        }
 +}
 +
 +void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 +{
 +      struct hci_conn *conn = chan->conn;
 +      struct hci_dev *hdev = conn->hdev;
 +
 +      BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
  
 -      tasklet_schedule(&hdev->tx_task);
 +      skb->dev = (void *) hdev;
 +      bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
 +      hci_add_acl_hdr(skb, conn->handle, flags);
 +
 +      hci_queue_acl(conn, &chan->data_q, skb, flags);
 +
 +      queue_work(hdev->workqueue, &hdev->tx_work);
  }
  EXPORT_SYMBOL(hci_send_acl);
  
@@@ -2018,7 -2016,7 +2018,7 @@@ void hci_send_sco(struct hci_conn *conn
        bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
  
        skb_queue_tail(&conn->data_q, skb);
 -      tasklet_schedule(&hdev->tx_task);
 +      queue_work(hdev->workqueue, &hdev->tx_work);
  }
  EXPORT_SYMBOL(hci_send_sco);
  
  static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
  {
        struct hci_conn_hash *h = &hdev->conn_hash;
 -      struct hci_conn *conn = NULL;
 +      struct hci_conn *conn = NULL, *c;
        int num = 0, min = ~0;
 -      struct list_head *p;
  
        /* We don't have to lock device here. Connections are always
         * added and removed with TX task disabled. */
 -      list_for_each(p, &h->list) {
 -              struct hci_conn *c;
 -              c = list_entry(p, struct hci_conn, list);
  
 +      rcu_read_lock();
 +
 +      list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type != type || skb_queue_empty(&c->data_q))
                        continue;
  
                        break;
        }
  
 +      rcu_read_unlock();
 +
        if (conn) {
                int cnt, q;
  
  static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
  {
        struct hci_conn_hash *h = &hdev->conn_hash;
 -      struct list_head *p;
 -      struct hci_conn  *c;
 +      struct hci_conn *c;
  
        BT_ERR("%s link tx timeout", hdev->name);
  
 +      rcu_read_lock();
 +
        /* Kill stalled connections */
 -      list_for_each(p, &h->list) {
 -              c = list_entry(p, struct hci_conn, list);
 +      list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
                                hdev->name, batostr(&c->dst));
                        hci_acl_disconn(c, 0x13);
                }
        }
 +
 +      rcu_read_unlock();
  }
  
 -static inline void hci_sched_acl(struct hci_dev *hdev)
 +static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
 +                                              int *quote)
  {
 +      struct hci_conn_hash *h = &hdev->conn_hash;
 +      struct hci_chan *chan = NULL;
 +      int num = 0, min = ~0, cur_prio = 0;
        struct hci_conn *conn;
 +      int cnt, q, conn_num = 0;
 +
 +      BT_DBG("%s", hdev->name);
 +
 +      rcu_read_lock();
 +
 +      list_for_each_entry_rcu(conn, &h->list, list) {
 +              struct hci_chan *tmp;
 +
 +              if (conn->type != type)
 +                      continue;
 +
 +              if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
 +                      continue;
 +
 +              conn_num++;
 +
 +              list_for_each_entry_rcu(tmp, &conn->chan_list, list) {
 +                      struct sk_buff *skb;
 +
 +                      if (skb_queue_empty(&tmp->data_q))
 +                              continue;
 +
 +                      skb = skb_peek(&tmp->data_q);
 +                      if (skb->priority < cur_prio)
 +                              continue;
 +
 +                      if (skb->priority > cur_prio) {
 +                              num = 0;
 +                              min = ~0;
 +                              cur_prio = skb->priority;
 +                      }
 +
 +                      num++;
 +
 +                      if (conn->sent < min) {
 +                              min  = conn->sent;
 +                              chan = tmp;
 +                      }
 +              }
 +
 +              if (hci_conn_num(hdev, type) == conn_num)
 +                      break;
 +      }
 +
 +      rcu_read_unlock();
 +
 +      if (!chan)
 +              return NULL;
 +
 +      switch (chan->conn->type) {
 +      case ACL_LINK:
 +              cnt = hdev->acl_cnt;
 +              break;
 +      case SCO_LINK:
 +      case ESCO_LINK:
 +              cnt = hdev->sco_cnt;
 +              break;
 +      case LE_LINK:
 +              cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
 +              break;
 +      default:
 +              cnt = 0;
 +              BT_ERR("Unknown link type");
 +      }
 +
 +      q = cnt / num;
 +      *quote = q ? q : 1;
 +      BT_DBG("chan %p quote %d", chan, *quote);
 +      return chan;
 +}
 +
 +static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 +{
 +      struct hci_conn_hash *h = &hdev->conn_hash;
 +      struct hci_conn *conn;
 +      int num = 0;
 +
 +      BT_DBG("%s", hdev->name);
 +
 +      rcu_read_lock();
 +
 +      list_for_each_entry_rcu(conn, &h->list, list) {
 +              struct hci_chan *chan;
 +
 +              if (conn->type != type)
 +                      continue;
 +
 +              if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
 +                      continue;
 +
 +              num++;
 +
 +              list_for_each_entry_rcu(chan, &conn->chan_list, list) {
 +                      struct sk_buff *skb;
 +
 +                      if (chan->sent) {
 +                              chan->sent = 0;
 +                              continue;
 +                      }
 +
 +                      if (skb_queue_empty(&chan->data_q))
 +                              continue;
 +
 +                      skb = skb_peek(&chan->data_q);
 +                      if (skb->priority >= HCI_PRIO_MAX - 1)
 +                              continue;
 +
 +                      skb->priority = HCI_PRIO_MAX - 1;
 +
 +                      BT_DBG("chan %p skb %p promoted to %d", chan, skb,
 +                                                              skb->priority);
 +              }
 +
 +              if (hci_conn_num(hdev, type) == num)
 +                      break;
 +      }
 +
 +      rcu_read_unlock();
 +
 +}
 +
 +static inline void hci_sched_acl(struct hci_dev *hdev)
 +{
 +      struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
 +      unsigned int cnt;
  
        BT_DBG("%s", hdev->name);
  
                        hci_link_tx_to(hdev, ACL_LINK);
        }
  
 -      while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
 -              while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
 -                      BT_DBG("skb %p len %d", skb, skb->len);
 +      cnt = hdev->acl_cnt;
  
 -                      hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
 +      while (hdev->acl_cnt &&
 +                      (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
 +              u32 priority = (skb_peek(&chan->data_q))->priority;
 +              while (quote-- && (skb = skb_peek(&chan->data_q))) {
 +                      BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
 +                                      skb->len, skb->priority);
 +
 +                      /* Stop if priority has changed */
 +                      if (skb->priority < priority)
 +                              break;
 +
 +                      skb = skb_dequeue(&chan->data_q);
 +
 +                      hci_conn_enter_active_mode(chan->conn,
 +                                              bt_cb(skb)->force_active);
  
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
  
                        hdev->acl_cnt--;
 -                      conn->sent++;
 +                      chan->sent++;
 +                      chan->conn->sent++;
                }
        }
 +
 +      if (cnt != hdev->acl_cnt)
 +              hci_prio_recalculate(hdev, ACL_LINK);
  }
  
  /* Schedule SCO */
@@@ -2333,9 -2182,9 +2333,9 @@@ static inline void hci_sched_esco(struc
  
  static inline void hci_sched_le(struct hci_dev *hdev)
  {
 -      struct hci_conn *conn;
 +      struct hci_chan *chan;
        struct sk_buff *skb;
 -      int quote, cnt;
 +      int quote, cnt, tmp;
  
        BT_DBG("%s", hdev->name);
  
        }
  
        cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
 -      while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
 -              while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
 -                      BT_DBG("skb %p len %d", skb, skb->len);
 +      tmp = cnt;
 +      while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
 +              u32 priority = (skb_peek(&chan->data_q))->priority;
 +              while (quote-- && (skb = skb_peek(&chan->data_q))) {
 +                      BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
 +                                      skb->len, skb->priority);
 +
 +                      /* Stop if priority has changed */
 +                      if (skb->priority < priority)
 +                              break;
 +
 +                      skb = skb_dequeue(&chan->data_q);
  
                        hci_send_frame(skb);
                        hdev->le_last_tx = jiffies;
  
                        cnt--;
 -                      conn->sent++;
 +                      chan->sent++;
 +                      chan->conn->sent++;
                }
        }
 +
        if (hdev->le_pkts)
                hdev->le_cnt = cnt;
        else
                hdev->acl_cnt = cnt;
 +
 +      if (cnt != tmp)
 +              hci_prio_recalculate(hdev, LE_LINK);
  }
  
 -static void hci_tx_task(unsigned long arg)
 +static void hci_tx_work(struct work_struct *work)
  {
 -      struct hci_dev *hdev = (struct hci_dev *) arg;
 +      struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work);
        struct sk_buff *skb;
  
 -      read_lock(&hci_task_lock);
 -
        BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
                hdev->sco_cnt, hdev->le_cnt);
  
        /* Send next queued raw (unknown type) packet */
        while ((skb = skb_dequeue(&hdev->raw_q)))
                hci_send_frame(skb);
 -
 -      read_unlock(&hci_task_lock);
  }
  
  /* ----- HCI RX task (incoming data processing) ----- */
@@@ -2429,11 -2268,16 +2429,11 @@@ static inline void hci_acldata_packet(s
        hci_dev_unlock(hdev);
  
        if (conn) {
 -              register struct hci_proto *hp;
 -
 -              hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
 +              hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
  
                /* Send to upper protocol */
 -              hp = hci_proto[HCI_PROTO_L2CAP];
 -              if (hp && hp->recv_acldata) {
 -                      hp->recv_acldata(conn, skb, flags);
 -                      return;
 -              }
 +              l2cap_recv_acldata(conn, skb, flags);
 +              return;
        } else {
                BT_ERR("%s ACL packet for unknown connection handle %d",
                        hdev->name, handle);
@@@ -2462,9 -2306,14 +2462,9 @@@ static inline void hci_scodata_packet(s
        hci_dev_unlock(hdev);
  
        if (conn) {
 -              register struct hci_proto *hp;
 -
                /* Send to upper protocol */
 -              hp = hci_proto[HCI_PROTO_SCO];
 -              if (hp && hp->recv_scodata) {
 -                      hp->recv_scodata(conn, skb);
 -                      return;
 -              }
 +              sco_recv_scodata(conn, skb);
 +              return;
        } else {
                BT_ERR("%s SCO packet for unknown connection handle %d",
                        hdev->name, handle);
        kfree_skb(skb);
  }
  
 -static void hci_rx_task(unsigned long arg)
 +static void hci_rx_work(struct work_struct *work)
  {
 -      struct hci_dev *hdev = (struct hci_dev *) arg;
 +      struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
        struct sk_buff *skb;
  
        BT_DBG("%s", hdev->name);
  
 -      read_lock(&hci_task_lock);
 -
        while ((skb = skb_dequeue(&hdev->rx_q))) {
                if (atomic_read(&hdev->promisc)) {
                        /* Send copy to the sockets */
                /* Process frame */
                switch (bt_cb(skb)->pkt_type) {
                case HCI_EVENT_PKT:
 +                      BT_DBG("%s Event packet", hdev->name);
                        hci_event_packet(hdev, skb);
                        break;
  
                        break;
                }
        }
 -
 -      read_unlock(&hci_task_lock);
  }
  
 -static void hci_cmd_task(unsigned long arg)
 +static void hci_cmd_work(struct work_struct *work)
  {
 -      struct hci_dev *hdev = (struct hci_dev *) arg;
 +      struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
        struct sk_buff *skb;
  
        BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
                                  jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
                } else {
                        skb_queue_head(&hdev->cmd_q, skb);
 -                      tasklet_schedule(&hdev->cmd_task);
 +                      queue_work(hdev->workqueue, &hdev->cmd_work);
                }
        }
  }
 +
 +int hci_do_inquiry(struct hci_dev *hdev, u8 length)
 +{
 +      /* General inquiry access code (GIAC) */
 +      u8 lap[3] = { 0x33, 0x8b, 0x9e };
 +      struct hci_cp_inquiry cp;
 +
 +      BT_DBG("%s", hdev->name);
 +
 +      if (test_bit(HCI_INQUIRY, &hdev->flags))
 +              return -EINPROGRESS;
 +
 +      memset(&cp, 0, sizeof(cp));
 +      memcpy(&cp.lap, lap, sizeof(cp.lap));
 +      cp.length  = length;
 +
 +      return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
 +}
 +
 +int hci_cancel_inquiry(struct hci_dev *hdev)
 +{
 +      BT_DBG("%s", hdev->name);
 +
 +      if (!test_bit(HCI_INQUIRY, &hdev->flags))
 +              return -EPERM;
 +
 +      return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
 +}
 +
 +module_param(enable_hs, bool, 0644);
 +MODULE_PARM_DESC(enable_hs, "Enable High Speed");
diff --combined net/sched/sch_qfq.c
index 2c5ff6148589db7a42700f30eea17394c6b36933,7b0325459e718c6c0fb8d259ef7e10ecc6353130..e68cb440756a4c33ce1108d464ea51b1c0b95631
@@@ -211,7 -211,6 +211,7 @@@ static int qfq_change_class(struct Qdis
        struct nlattr *tb[TCA_QFQ_MAX + 1];
        u32 weight, lmax, inv_w;
        int i, err;
 +      int delta_w;
  
        if (tca[TCA_OPTIONS] == NULL) {
                pr_notice("qfq: no options\n");
  
        inv_w = ONE_FP / weight;
        weight = ONE_FP / inv_w;
 -      if (q->wsum + weight > QFQ_MAX_WSUM) {
 +      delta_w = weight - (cl ? ONE_FP / cl->inv_w : 0);
 +      if (q->wsum + delta_w > QFQ_MAX_WSUM) {
                pr_notice("qfq: total weight out of range (%u + %u)\n",
 -                        weight, q->wsum);
 +                        delta_w, q->wsum);
                return -EINVAL;
        }
  
                                return err;
                }
  
 -              sch_tree_lock(sch);
 -              if (tb[TCA_QFQ_WEIGHT]) {
 -                      q->wsum = weight - ONE_FP / cl->inv_w;
 +              if (inv_w != cl->inv_w) {
 +                      sch_tree_lock(sch);
 +                      q->wsum += delta_w;
                        cl->inv_w = inv_w;
 +                      sch_tree_unlock(sch);
                }
 -              sch_tree_unlock(sch);
 -
                return 0;
        }
  
        i = qfq_calc_index(cl->inv_w, cl->lmax);
  
        cl->grp = &q->groups[i];
 -      q->wsum += weight;
  
        cl->qdisc = qdisc_create_dflt(sch->dev_queue,
                                      &pfifo_qdisc_ops, classid);
                        return err;
                }
        }
 +      q->wsum += weight;
  
        sch_tree_lock(sch);
        qdisc_class_hash_insert(&q->clhash, &cl->common);
@@@ -818,11 -817,11 +818,11 @@@ skip_unblock
  static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
  {
        unsigned long mask;
-       uint32_t limit, roundedF;
+       u64 limit, roundedF;
        int slot_shift = cl->grp->slot_shift;
  
        roundedF = qfq_round_down(cl->F, slot_shift);
-       limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift);
+       limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift);
  
        if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) {
                /* timestamp was stale */
This page took 0.175368 seconds and 4 git commands to generate.