struct ieee80211_vif *vif)
{
struct sk_buff *beacon;
- __le32 old_beacon_req_id;
int ret;
beacon = ieee80211_beacon_get(priv->hw, vif);
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;
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);
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;
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;
range = (void *) info->rate_driver_data;
range->start_addr = target_addr;
range->end_addr = target_addr + len;
+ data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ if (IS_DATA_FRAME(skb) &&
+ unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+ priv->beacon_req_id = data->req_id;
+
__skb_queue_after(&priv->tx_queue, target_skb, skb);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- data->req_id = cpu_to_le32(target_addr + priv->headroom);
return 0;
}
struct sk_buff *skb)
{
if (IS_DATA_FRAME(skb)) {
- struct p54_hdr *hdr = (void *) skb->data;
- struct p54_tx_data *data = (void *) hdr->data;
unsigned long flags;
spin_lock_irqsave(&priv->tx_stats_lock, flags);
- priv->tx_stats[data->hw_queue].len--;
+ priv->tx_stats[GET_HW_QUEUE(skb)].len--;
spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+ if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+ if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+ /* this is the active beacon set anymore */
+ priv->beacon_req_id = 0;
+ }
+ complete(&priv->beacon_comp);
+ }
}
p54_wake_queues(priv);
}
* and we don't want to confuse the mac80211 stack.
*/
if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
- if (entry_data->hw_queue == P54_QUEUE_BEACON &&
- hdr->req_id == priv->beacon_req_id)
- priv->beacon_req_id = cpu_to_le32(0);
-
dev_kfree_skb_any(entry);
return ;
}