summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00mac.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c172
1 files changed, 92 insertions, 80 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 9cb023e..f1dcbaa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -31,14 +31,14 @@
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue,
- struct sk_buff *frag_skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *frag_skb)
{
- struct skb_frame_desc *skbdesc;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
+ struct ieee80211_tx_info *rts_info;
struct sk_buff *skb;
int size;
- if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
size = sizeof(struct ieee80211_cts);
else
size = sizeof(struct ieee80211_rts);
@@ -52,23 +52,37 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
skb_put(skb, size);
- if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- ieee80211_ctstoself_get(rt2x00dev->hw, control->vif,
- frag_skb->data, frag_skb->len, control,
+ /*
+ * Copy TX information over from original frame to
+ * RTS/CTS frame. Note that we set the no encryption flag
+ * since we don't want this frame to be encrypted.
+ * RTS frames should be acked, while CTS-to-self frames
+ * should not. The ready for TX flag is cleared to prevent
+ * it being automatically send when the descriptor is
+ * written to the hardware.
+ */
+ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
+ rts_info = IEEE80211_SKB_CB(skb);
+ rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
+ rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+ rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else
+ rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
+ frag_skb->data, size, tx_info,
(struct ieee80211_cts *)(skb->data));
else
- ieee80211_rts_get(rt2x00dev->hw, control->vif,
- frag_skb->data, frag_skb->len, control,
+ ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
+ frag_skb->data, size, tx_info,
(struct ieee80211_rts *)(skb->data));
- /*
- * Initialize skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
-
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
+ if (rt2x00queue_write_tx_frame(queue, skb)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY;
}
@@ -76,13 +90,14 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
return NETDEV_TX_OK;
}
-int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ enum data_queue_qid qid = skb_get_queue_mapping(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct data_queue *queue;
- struct skb_frame_desc *skbdesc;
u16 frame_control;
/*
@@ -100,57 +115,62 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
/*
* Determine which queue to put packet on.
*/
- if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM &&
+ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
- queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+ queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM);
else
- queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
+ queue = rt2x00queue_get_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
- "Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ "Please file bug report to %s.\n", qid, DRV_PROJECT);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
/*
- * If CTS/RTS is required. and this frame is not CTS or RTS,
- * create and queue that frame first. But make sure we have
- * at least enough entries available to send this CTS/RTS
- * frame as well as the data frame.
+ * If CTS/RTS is required. create and queue that frame first.
+ * Make sure we have at least enough entries available to send
+ * this CTS/RTS frame as well as the data frame.
+ * Note that when the driver has set the set_rts_threshold()
+ * callback function it doesn't need software generation of
+ * either RTS or CTS-to-self frame and handles everything
+ * inside the hardware.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
- if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
- (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
- IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+ if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
+ IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+ !rt2x00dev->ops->hw->set_rts_threshold) {
if (rt2x00queue_available(queue) <= 1) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
- if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) {
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
}
/*
- * Initialize skb descriptor
+ * XXX: This is as wrong as the old mac80211 code was,
+ * due to beacons not getting sequence numbers assigned
+ * properly.
*/
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ intf->seqno += 0x10;
+ ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+ }
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ if (rt2x00queue_write_tx_frame(queue, skb)) {
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
- if (rt2x00queue_full(queue))
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
-
- if (rt2x00dev->ops->lib->kick_tx_queue)
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+ if (rt2x00queue_threshold(queue))
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_OK;
}
@@ -183,8 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
- struct data_queue *queue =
- rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+ struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
struct queue_entry *entry = NULL;
unsigned int i;
@@ -197,13 +216,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
return -ENODEV;
/*
- * When we don't support mixed interfaces (a combination
- * of sta and ap virtual interfaces) then we can only
- * add this interface when the rival interface count is 0.
+ * We don't support mixed combinations of sta and ap virtual
+ * interfaces. We can only add this interface when the rival
+ * interface count is 0.
*/
- if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) &&
- ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
- (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)))
+ if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
+ (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))
return -ENOBUFS;
/*
@@ -343,7 +361,8 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int status;
+ int update_bssid = 0;
+ int status = 0;
/*
* Mac80211 might be calling this function while we are trying
@@ -355,12 +374,13 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
spin_lock(&intf->lock);
/*
- * If the interface does not work in master mode,
- * then the bssid value in the interface structure
- * should now be set.
+ * conf->bssid can be NULL if coming from the internal
+ * beacon update routine.
*/
- if (conf->type != IEEE80211_IF_TYPE_AP)
+ if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
+ update_bssid = 1;
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+ }
spin_unlock(&intf->lock);
@@ -370,19 +390,14 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
* values as arguments we make keep access to rt2x00_intf thread safe
* even without the lock.
*/
- rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
+ update_bssid ? conf->bssid : NULL);
/*
- * We only need to initialize the beacon when master mode is enabled.
+ * Update the beacon.
*/
- if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
- return 0;
-
- status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
- conf->beacon,
- conf->beacon_control);
- if (status)
- dev_kfree_skb(conf->beacon);
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ status = rt2x00queue_update_beacon(rt2x00dev, vif);
return status;
}
@@ -428,7 +443,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
else
- queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
@@ -454,10 +469,10 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
- for (i = 0; i < hw->queues; i++) {
- stats->data[i].len = rt2x00dev->tx[i].length;
- stats->data[i].limit = rt2x00dev->tx[i].limit;
- stats->data[i].count = rt2x00dev->tx[i].count;
+ for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
+ stats[i].len = rt2x00dev->tx[i].length;
+ stats[i].limit = rt2x00dev->tx[i].limit;
+ stats[i].count = rt2x00dev->tx[i].count;
}
return 0;
@@ -498,7 +513,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
- if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+ if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
else
@@ -509,13 +524,13 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
if (delayed) {
intf->delayed_flags |= delayed;
- queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
+ schedule_work(&rt2x00dev->intf_work);
}
spin_unlock(&intf->lock);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -539,10 +554,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx,
else
queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
- if (params->aifs >= 0)
- queue->aifs = params->aifs;
- else
- queue->aifs = 2;
+ queue->aifs = params->aifs;
INFO(rt2x00dev,
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
OpenPOWER on IntegriCloud