aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/p54/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/p54/main.c')
-rw-r--r--drivers/net/wireless/p54/main.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index f19add2c3ca..955f6d7ec16 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -130,7 +130,6 @@ static int p54_beacon_update(struct p54_common *priv,
struct ieee80211_vif *vif)
{
struct sk_buff *beacon;
- __le32 old_beacon_req_id;
int ret;
beacon = ieee80211_beacon_get(priv->hw, vif);
@@ -140,15 +139,16 @@ static int p54_beacon_update(struct p54_common *priv,
if (ret)
return ret;
- old_beacon_req_id = priv->beacon_req_id;
- priv->beacon_req_id = GET_REQ_ID(beacon);
-
- ret = p54_tx_80211(priv->hw, beacon);
- if (ret) {
- priv->beacon_req_id = old_beacon_req_id;
- return -ENOSPC;
- }
-
+ /*
+ * During operation, the firmware takes care of beaconing.
+ * The driver only needs to upload a new beacon template, once
+ * the template was changed by the stack or userspace.
+ *
+ * LMAC API 3.2.2 also specifies that the driver does not need
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+ WARN_ON(p54_tx_80211(priv->hw, beacon));
priv->tsf_high32 = 0;
priv->tsf_low32 = 0;
@@ -253,9 +253,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
mutex_lock(&priv->conf_mutex);
priv->vif = NULL;
- if (priv->beacon_req_id) {
+
+ /*
+ * LMAC API 3.2.2 states that any active beacon template must be
+ * canceled by the driver before attempting a mode transition.
+ */
+ if (le32_to_cpu(priv->beacon_req_id) != 0) {
p54_tx_cancel(priv, priv->beacon_req_id);
- priv->beacon_req_id = cpu_to_le32(0);
+ wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
}
priv->mode = NL80211_IFTYPE_MONITOR;
memset(priv->mac_addr, 0, ETH_ALEN);
@@ -544,6 +549,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
BIT(NL80211_IFTYPE_MESH_POINT);
dev->channel_change_time = 1000; /* TODO: find actual value */
+ priv->beacon_req_id = cpu_to_le32(0);
priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
@@ -567,6 +573,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
mutex_init(&priv->conf_mutex);
mutex_init(&priv->eeprom_mutex);
init_completion(&priv->eeprom_comp);
+ init_completion(&priv->beacon_comp);
INIT_DELAYED_WORK(&priv->work, p54_work);
return dev;