Commit b3b66ae4 authored by John W. Linville's avatar John W. Linville

Merge branch 'master' of...

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem
parents bf414b36 7b2385b9
...@@ -94,11 +94,16 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); ...@@ -94,11 +94,16 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
#ifdef CONFIG_BCMA_DRIVER_GPIO #ifdef CONFIG_BCMA_DRIVER_GPIO
/* driver_gpio.c */ /* driver_gpio.c */
int bcma_gpio_init(struct bcma_drv_cc *cc); int bcma_gpio_init(struct bcma_drv_cc *cc);
int bcma_gpio_unregister(struct bcma_drv_cc *cc);
#else #else
static inline int bcma_gpio_init(struct bcma_drv_cc *cc) static inline int bcma_gpio_init(struct bcma_drv_cc *cc)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc)
{
return 0;
}
#endif /* CONFIG_BCMA_DRIVER_GPIO */ #endif /* CONFIG_BCMA_DRIVER_GPIO */
#endif #endif
...@@ -96,3 +96,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) ...@@ -96,3 +96,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
return gpiochip_add(chip); return gpiochip_add(chip);
} }
int bcma_gpio_unregister(struct bcma_drv_cc *cc)
{
return gpiochip_remove(&cc->gpio);
}
...@@ -268,6 +268,13 @@ int bcma_bus_register(struct bcma_bus *bus) ...@@ -268,6 +268,13 @@ int bcma_bus_register(struct bcma_bus *bus)
void bcma_bus_unregister(struct bcma_bus *bus) void bcma_bus_unregister(struct bcma_bus *bus)
{ {
struct bcma_device *cores[3]; struct bcma_device *cores[3];
int err;
err = bcma_gpio_unregister(&bus->drv_cc);
if (err == -EBUSY)
bcma_err(bus, "Some GPIOs are still in use.\n");
else if (err)
bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "debug.h" #include "debug.h"
#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
/* Flags we support */ /* Flags we support */
#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
...@@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) ...@@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
} }
static bool brcms_tx_flush_completed(struct brcms_info *wl)
{
bool result;
spin_lock_bh(&wl->lock);
result = brcms_c_tx_flush_completed(wl->wlc);
spin_unlock_bh(&wl->lock);
return result;
}
static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
{ {
struct brcms_info *wl = hw->priv; struct brcms_info *wl = hw->priv;
int ret;
no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
/* wait for packet queue and dma fifos to run empty */ ret = wait_event_timeout(wl->tx_flush_wq,
spin_lock_bh(&wl->lock); brcms_tx_flush_completed(wl),
brcms_c_wait_for_tx_completion(wl->wlc, drop); msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT));
spin_unlock_bh(&wl->lock);
brcms_dbg_mac80211(wl->wlc->hw->d11core,
"ret=%d\n", jiffies_to_msecs(ret));
} }
static const struct ieee80211_ops brcms_ops = { static const struct ieee80211_ops brcms_ops = {
...@@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data) ...@@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data)
done: done:
spin_unlock_bh(&wl->lock); spin_unlock_bh(&wl->lock);
wake_up(&wl->tx_flush_wq);
} }
/* /*
...@@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) ...@@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
atomic_set(&wl->callbacks, 0); atomic_set(&wl->callbacks, 0);
init_waitqueue_head(&wl->tx_flush_wq);
/* setup the bottom half handler */ /* setup the bottom half handler */
tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
...@@ -1609,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl) ...@@ -1609,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
spin_lock_bh(&wl->lock); spin_lock_bh(&wl->lock);
return blocked; return blocked;
} }
/*
* precondition: perimeter lock has been acquired
*/
void brcms_msleep(struct brcms_info *wl, uint ms)
{
spin_unlock_bh(&wl->lock);
msleep(ms);
spin_lock_bh(&wl->lock);
}
...@@ -68,6 +68,8 @@ struct brcms_info { ...@@ -68,6 +68,8 @@ struct brcms_info {
spinlock_t lock; /* per-device perimeter lock */ spinlock_t lock; /* per-device perimeter lock */
spinlock_t isr_lock; /* per-device ISR synchronization lock */ spinlock_t isr_lock; /* per-device ISR synchronization lock */
/* tx flush */
wait_queue_head_t tx_flush_wq;
/* timer related fields */ /* timer related fields */
atomic_t callbacks; /* # outstanding callback functions */ atomic_t callbacks; /* # outstanding callback functions */
...@@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, ...@@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
extern void brcms_free_timer(struct brcms_timer *timer); extern void brcms_free_timer(struct brcms_timer *timer);
extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic);
extern bool brcms_del_timer(struct brcms_timer *timer); extern bool brcms_del_timer(struct brcms_timer *timer);
extern void brcms_msleep(struct brcms_info *wl, uint ms);
extern void brcms_dpc(unsigned long data); extern void brcms_dpc(unsigned long data);
extern void brcms_timer(struct brcms_timer *t); extern void brcms_timer(struct brcms_timer *t);
extern void brcms_fatal_error(struct brcms_info *wl); extern void brcms_fatal_error(struct brcms_info *wl);
......
...@@ -7511,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc) ...@@ -7511,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc)
return wlc->band->bandunit; return wlc->band->bandunit;
} }
void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc)
{ {
int timeout = 20;
int i; int i;
/* Kick DMA to send any pending AMPDU */ /* Kick DMA to send any pending AMPDU */
for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
if (wlc->hw->di[i]) if (wlc->hw->di[i])
dma_txflush(wlc->hw->di[i]); dma_kick_tx(wlc->hw->di[i]);
/* wait for queue and DMA fifos to run dry */ return !brcms_txpktpendtot(wlc);
while (brcms_txpktpendtot(wlc) > 0) {
brcms_msleep(wlc->wl, 1);
if (--timeout == 0)
break;
}
WARN_ON_ONCE(timeout == 0);
} }
void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
......
...@@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); ...@@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state);
extern void brcms_c_scan_start(struct brcms_c_info *wlc); extern void brcms_c_scan_start(struct brcms_c_info *wlc);
extern void brcms_c_scan_stop(struct brcms_c_info *wlc); extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
extern int brcms_c_get_curband(struct brcms_c_info *wlc); extern int brcms_c_get_curband(struct brcms_c_info *wlc);
extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
bool drop);
extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
...@@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); ...@@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
#endif /* _BRCM_PUB_H_ */ #endif /* _BRCM_PUB_H_ */
...@@ -1004,7 +1004,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) ...@@ -1004,7 +1004,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
is_tx ? "Tx" : "Rx"); is_tx ? "Tx" : "Rx");
if (is_tx) { if (is_tx) {
rtl_lps_leave(hw); schedule_work(&rtlpriv->
works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies = ppsc->last_delaylps_stamp_jiffies =
jiffies; jiffies;
} }
...@@ -1014,7 +1015,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) ...@@ -1014,7 +1015,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
} }
} else if (ETH_P_ARP == ether_type) { } else if (ETH_P_ARP == ether_type) {
if (is_tx) { if (is_tx) {
rtl_lps_leave(hw); schedule_work(&rtlpriv->works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies = jiffies; ppsc->last_delaylps_stamp_jiffies = jiffies;
} }
...@@ -1024,7 +1025,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) ...@@ -1024,7 +1025,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
"802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
if (is_tx) { if (is_tx) {
rtl_lps_leave(hw); schedule_work(&rtlpriv->works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies = jiffies; ppsc->last_delaylps_stamp_jiffies = jiffies;
} }
......
...@@ -174,3 +174,15 @@ int ssb_gpio_init(struct ssb_bus *bus) ...@@ -174,3 +174,15 @@ int ssb_gpio_init(struct ssb_bus *bus)
return -1; return -1;
} }
int ssb_gpio_unregister(struct ssb_bus *bus)
{
if (ssb_chipco_available(&bus->chipco) ||
ssb_extif_available(&bus->extif)) {
return gpiochip_remove(&bus->gpio);
} else {
SSB_WARN_ON(1);
}
return -1;
}
...@@ -443,6 +443,15 @@ static void ssb_devices_unregister(struct ssb_bus *bus) ...@@ -443,6 +443,15 @@ static void ssb_devices_unregister(struct ssb_bus *bus)
void ssb_bus_unregister(struct ssb_bus *bus) void ssb_bus_unregister(struct ssb_bus *bus)
{ {
int err;
err = ssb_gpio_unregister(bus);
if (err == -EBUSY)
ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n");
else if (err)
ssb_dprintk(KERN_ERR PFX
"Can not unregister GPIO driver: %i\n", err);
ssb_buses_lock(); ssb_buses_lock();
ssb_devices_unregister(bus); ssb_devices_unregister(bus);
list_del(&bus->list); list_del(&bus->list);
......
...@@ -252,11 +252,16 @@ static inline void ssb_extif_init(struct ssb_extif *extif) ...@@ -252,11 +252,16 @@ static inline void ssb_extif_init(struct ssb_extif *extif)
#ifdef CONFIG_SSB_DRIVER_GPIO #ifdef CONFIG_SSB_DRIVER_GPIO
extern int ssb_gpio_init(struct ssb_bus *bus); extern int ssb_gpio_init(struct ssb_bus *bus);
extern int ssb_gpio_unregister(struct ssb_bus *bus);
#else /* CONFIG_SSB_DRIVER_GPIO */ #else /* CONFIG_SSB_DRIVER_GPIO */
static inline int ssb_gpio_init(struct ssb_bus *bus) static inline int ssb_gpio_init(struct ssb_bus *bus)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
static inline int ssb_gpio_unregister(struct ssb_bus *bus)
{
return 0;
}
#endif /* CONFIG_SSB_DRIVER_GPIO */ #endif /* CONFIG_SSB_DRIVER_GPIO */
#endif /* LINUX_SSB_PRIVATE_H_ */ #endif /* LINUX_SSB_PRIVATE_H_ */
...@@ -249,12 +249,12 @@ static void hci_conn_disconnect(struct hci_conn *conn) ...@@ -249,12 +249,12 @@ static void hci_conn_disconnect(struct hci_conn *conn)
__u8 reason = hci_proto_disconn_ind(conn); __u8 reason = hci_proto_disconn_ind(conn);
switch (conn->type) { switch (conn->type) {
case ACL_LINK:
hci_acl_disconn(conn, reason);
break;
case AMP_LINK: case AMP_LINK:
hci_amp_disconn(conn, reason); hci_amp_disconn(conn, reason);
break; break;
default:
hci_acl_disconn(conn, reason);
break;
} }
} }
......
...@@ -859,6 +859,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -859,6 +859,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(code)); skb_pull(skb, sizeof(code));
/*
* The SMP context must be initialized for all other PDUs except
* pairing and security requests. If we get any other PDU when
* not initialized simply disconnect (done if this function
* returns an error).
*/
if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
!conn->smp_chan) {
BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
kfree_skb(skb);
return -ENOTSUPP;
}
switch (code) { switch (code) {
case SMP_CMD_PAIRING_REQ: case SMP_CMD_PAIRING_REQ:
reason = smp_cmd_pairing_req(conn, skb); reason = smp_cmd_pairing_req(conn, skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment