Fix rt2x00 compilation and upgrade to the current mainline version (2.6.24)
[openwrt/openwrt.git] / package / rt2x00 / src / rt2x00mac.c
index 8835df2e2e01260355220ceddb1c12ed150eabe1..85ea8a8e658ef52641702a614d4d75b4e2857e60 100644 (file)
  */
 
 /*
-       Module: rt2x00lib
+       Module: rt2x00mac
        Abstract: rt2x00 generic mac80211 routines.
-       Supported chipsets: RT2460, RT2560, RT2570,
-       rt2561, rt2561s, rt2661, rt2571W & rt2671.
  */
 
 /*
  */
 #define DRV_NAME "rt2x00lib"
 
-#include <linux/netdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
-#include "rt2x00dev.h"
 
-static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
-       struct data_ring *ring, struct sk_buff *frag_skb,
-       struct ieee80211_tx_control *control)
+static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
+                               struct data_ring *ring,
+                               struct sk_buff *frag_skb,
+                               struct ieee80211_tx_control *control)
 {
        struct sk_buff *skb;
        int size;
@@ -58,13 +57,13 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        skb_put(skb, size);
 
        if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
-               ieee80211_ctstoself_get(rt2x00dev->hw,
-                       frag_skb->data, frag_skb->len, control,
-                       (struct ieee80211_cts*)(skb->data));
+               ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+                                       frag_skb->data, frag_skb->len, control,
+                                       (struct ieee80211_cts *)(skb->data));
        else
-               ieee80211_rts_get(rt2x00dev->hw,
-                       frag_skb->data, frag_skb->len, control,
-                       (struct ieee80211_rts*)(skb->data));
+               ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+                                 frag_skb->data, frag_skb->len, control,
+                                 (struct ieee80211_rts *)(skb->data));
 
        if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
                WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
@@ -74,23 +73,34 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        return NETDEV_TX_OK;
 }
 
-int rt2x00lib_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 ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        struct data_ring *ring;
        u16 frame_control;
 
+       /*
+        * Mac80211 might be calling this function while we are trying
+        * to remove the device or perhaps suspending it.
+        * Note that we can only stop the TX queues inside the TX path
+        * due to possible race conditions in mac80211.
+        */
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+               ieee80211_stop_queues(hw);
+               return 0;
+       }
+
        /*
         * Determine which ring to put packet on.
         */
-       ring = rt2x00_get_ring(rt2x00dev, control->queue);
+       ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
        if (unlikely(!ring)) {
                ERROR(rt2x00dev,
-                       "Attempt to send packet over invalid queue %d.\n"
-                       "Please file bug report to %s.\n",
-                       control->queue, DRV_PROJECT);
+                     "Attempt to send packet over invalid queue %d.\n"
+                     "Please file bug report to %s.\n",
+                     control->queue, DRV_PROJECT);
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
@@ -102,12 +112,13 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
         * frame as well as the data frame.
         */
        frame_control = le16_to_cpu(ieee80211hdr->frame_control);
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS &&
-           !is_cts_frame(frame_control) && !is_rts_frame(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 (rt2x00_ring_free(ring) <= 1)
                        return NETDEV_TX_BUSY;
 
-               if (rt2x00_tx_rts_cts(rt2x00dev, ring, skb, control))
+               if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
                        return NETDEV_TX_BUSY;
        }
 
@@ -119,130 +130,148 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        return NETDEV_TX_OK;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_tx);
+EXPORT_SYMBOL_GPL(rt2x00mac_tx);
 
-int rt2x00lib_reset(struct ieee80211_hw *hw)
+int rt2x00mac_start(struct ieee80211_hw *hw)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
+       int status;
+
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+           test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+               return 0;
+
+       /*
+        * If this is the first interface which is added,
+        * we should load the firmware now.
+        */
+       if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+               status = rt2x00lib_load_firmware(rt2x00dev);
+               if (status)
+                       return status;
+       }
+
+       /*
+        * Initialize the device.
+        */
+       status = rt2x00lib_initialize(rt2x00dev);
+       if (status)
+               return status;
+
+       /*
+        * Enable radio.
+        */
+       status = rt2x00lib_enable_radio(rt2x00dev);
+       if (status) {
+               rt2x00lib_uninitialize(rt2x00dev);
+               return status;
+       }
+
+       __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
 
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_start);
+
+void rt2x00mac_stop(struct ieee80211_hw *hw)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+               return;
+
+       /*
+        * Perhaps we can add something smarter here,
+        * but for now just disabling the radio should do.
+        */
        rt2x00lib_disable_radio(rt2x00dev);
-       return rt2x00lib_enable_radio(rt2x00dev);
+
+       __clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_reset);
+EXPORT_SYMBOL_GPL(rt2x00mac_stop);
 
-int rt2x00lib_add_interface(struct ieee80211_hw *hw,
-       struct ieee80211_if_init_conf *conf)
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+                           struct ieee80211_if_init_conf *conf)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct interface *intf = &rt2x00dev->interface;
-       int status;
+
+       /* FIXME: Beaconing is broken in rt2x00. */
+       if (conf->type == IEEE80211_IF_TYPE_IBSS ||
+           conf->type == IEEE80211_IF_TYPE_AP) {
+               ERROR(rt2x00dev,
+                     "rt2x00 does not support Adhoc or Master mode");
+               return -EOPNOTSUPP;
+       }
 
        /*
-        * We only support 1 non-monitor interface.
+        * Don't allow interfaces to be added while
+        * either the device has disappeared or when
+        * another interface is already present.
         */
-       if (conf->type != IEEE80211_IF_TYPE_MNTR &&
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
            is_interface_present(intf))
                return -ENOBUFS;
 
-       /*
-        * We support muliple monitor mode interfaces.
-        * All we need to do is increase the monitor_count.
-        */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               intf->monitor_count++;
-       } else {
-               intf->id = conf->if_id;
-               intf->type = conf->type;
-               if (conf->type == IEEE80211_IF_TYPE_AP)
-                       memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
-               intf->promisc = 0;
-       }
+       intf->id = conf->if_id;
+       intf->type = conf->type;
+       if (conf->type == IEEE80211_IF_TYPE_AP)
+               memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+       memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
 
        /*
-        * Initialize interface, and enable the radio when this
-        * is the first interface that is brought up.
+        * The MAC adddress must be configured after the device
+        * has been initialized. Otherwise the device can reset
+        * the MAC registers.
         */
-       if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
-               /*
-                * We must wait on the firmware before
-                * we can safely continue.
-                */
-               status = rt2x00lib_load_firmware_wait(rt2x00dev);
-               if (status)
-                       return status;
-
-               /*
-                * Before initialization, the mac address should
-                * be configured.
-                */
-               rt2x00dev->ops->lib->config_mac_addr(rt2x00dev,
-                       conf->mac_addr);
-               /*
-                * Initialize the device.
-                */
-               status = rt2x00lib_initialize(rt2x00dev);
-               if (status)
-                       return status;
-
-               /*
-                * Enable radio.
-                */
-               status = rt2x00lib_enable_radio(rt2x00dev);
-               if (status)
-                       return status;
-       }
+       rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+       rt2x00lib_config_type(rt2x00dev, conf->type);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_add_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
 
-void rt2x00lib_remove_interface(struct ieee80211_hw *hw,
-       struct ieee80211_if_init_conf *conf)
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_if_init_conf *conf)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct interface *intf = &rt2x00dev->interface;
 
        /*
-        * We only support 1 non-monitor interface.
+        * Don't allow interfaces to be remove while
+        * either the device has disappeared or when
+        * no interface is present.
         */
-       if (conf->type != IEEE80211_IF_TYPE_MNTR &&
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
            !is_interface_present(intf))
                return;
 
-       /*
-        * When removing an monitor interface, decrease monitor_count.
-        * For non-monitor interfaces, all interface data needs to be reset.
-        */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               intf->monitor_count--;
-       } else if (intf->type == conf->type) {
-               intf->id = 0;
-               intf->type = -EINVAL;
-               memset(&intf->bssid, 0x00, ETH_ALEN);
-               intf->promisc = 0;
-       }
+       intf->id = 0;
+       intf->type = INVALID_INTERFACE;
+       memset(&intf->bssid, 0x00, ETH_ALEN);
+       memset(&intf->mac, 0x00, ETH_ALEN);
 
        /*
-        * If this was the last interface,
-        * this is the time to disable the radio.
-        * If this is not the last interface, then we should
-        * check if we should switch completely to monitor
-        * mode or completely switch to the non-monitor mode.
+        * Make sure the bssid and mac address registers
+        * are cleared to prevent false ACKing of frames.
         */
-       if (!is_monitor_present(intf) && !is_interface_present(intf))
-               rt2x00lib_disable_radio(rt2x00dev);
-       else if (is_monitor_present(intf) ^ is_interface_present(intf))
-               rt2x00lib_config_type(rt2x00dev,
-                       is_interface_present(intf) ?
-                               intf->type : IEEE80211_IF_TYPE_MNTR);
+       rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+       rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+       rt2x00lib_config_type(rt2x00dev, intf->type);
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_remove_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 
-int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
 
+       /*
+        * Mac80211 might be calling this function while we are trying
+        * to remove the device or perhaps suspending it.
+        */
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+               return 0;
+
        /*
         * Check if we need to disable the radio,
         * if this is not the case, at least the RX must be disabled.
@@ -251,46 +280,42 @@ int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
                if (!conf->radio_enabled)
                        rt2x00lib_disable_radio(rt2x00dev);
                else
-                       rt2x00lib_toggle_rx(rt2x00dev, 0);
+                       rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
        }
 
-       rt2x00lib_config_phymode(rt2x00dev, conf->phymode);
-       rt2x00lib_config_channel(rt2x00dev, conf->channel_val,
-               conf->channel, conf->freq, conf->power_level);
-       rt2x00lib_config_txpower(rt2x00dev, conf->power_level);
-       rt2x00lib_config_antenna(rt2x00dev,
-               conf->antenna_sel_tx, conf->antenna_sel_rx);
-       rt2x00dev->ops->lib->config_duration(rt2x00dev,
-               (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME),
-               conf->beacon_int);
+       rt2x00lib_config(rt2x00dev, conf, 0);
 
        /*
         * Reenable RX only if the radio should be on.
         */
        if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
-               rt2x00lib_toggle_rx(rt2x00dev, 1);
+               rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
        else if (conf->radio_enabled)
                return rt2x00lib_enable_radio(rt2x00dev);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_config);
+EXPORT_SYMBOL_GPL(rt2x00mac_config);
 
-int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
-       struct ieee80211_if_conf *conf)
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+                              struct ieee80211_if_conf *conf)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct interface *intf = &rt2x00dev->interface;
        int status;
 
        /*
-        * Monitor mode does not need configuring.
+        * Mac80211 might be calling this function while we are trying
+        * to remove the device or perhaps suspending it.
+        */
+       if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+               return 0;
+
+       /*
         * If the given type does not match the configured type,
         * there has been a problem.
         */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR)
-               return 0;
-       else if (conf->type != intf->type)
+       if (conf->type != intf->type)
                return -EINVAL;
 
        /*
@@ -300,14 +325,7 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
         */
        if (conf->type != IEEE80211_IF_TYPE_AP)
                memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
-
-       /*
-        * Enable configuration.
-        * For Monitor mode, promisc mode will be forced on.
-        */
-       rt2x00lib_config_type(rt2x00dev, conf->type);
-       rt2x00lib_config_promisc(rt2x00dev, rt2x00dev->interface.promisc);
-       rt2x00dev->ops->lib->config_bssid(rt2x00dev, intf->bssid);
+       rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
 
        /*
         * We only need to initialize the beacon when master mode is enabled.
@@ -316,65 +334,86 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
                return 0;
 
        status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
-               conf->beacon, conf->beacon_control);
+                                                  conf->beacon,
+                                                  conf->beacon_control);
        if (status)
                dev_kfree_skb(conf->beacon);
 
        return status;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_config_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
 
-void rt2x00lib_set_multicast_list(struct ieee80211_hw *hw,
-       unsigned short flags, int mc_count)
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+                       struct ieee80211_low_level_stats *stats)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
 
        /*
-        * Promisc mode is forced on for Monitor interfaces.
+        * The dot11ACKFailureCount, dot11RTSFailureCount and
+        * dot11RTSSuccessCount are updated in interrupt time.
+        * dot11FCSErrorCount is updated in the link tuner.
         */
-       if (is_monitor_present(&rt2x00dev->interface))
-               return;
+       memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
 
-       /*
-        * Check if the new state is different then the old state.
-        */
-       if (test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags) ==
-           !!(flags & IFF_PROMISC))
-               return;
-
-       rt2x00dev->interface.promisc = !!(flags & IFF_PROMISC);
-
-       /*
-        * Schedule the link tuner if this does not run
-        * automatically. The link tuner will be automatically
-        * switched off when it is not required.
-        */
-       if (!work_pending(&rt2x00dev->link.work.work))
-               queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work.work);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_set_multicast_list);
+EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
 
-int rt2x00lib_get_tx_stats(struct ieee80211_hw *hw,
-       struct ieee80211_tx_queue_stats *stats)
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+                          struct ieee80211_tx_queue_stats *stats)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        unsigned int i;
 
        for (i = 0; i < hw->queues; i++)
                memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
-                       sizeof(rt2x00dev->tx[i].stats));
+                      sizeof(rt2x00dev->tx[i].stats));
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_get_tx_stats);
+EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
+
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+                             int cts_protection, int preamble)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       int short_preamble;
+       int ack_timeout;
+       int ack_consume_time;
+       int difs;
+
+       /*
+        * We only support changing preamble mode.
+        */
+       if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+               return;
+
+       short_preamble = !preamble;
+       preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+
+       difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
+               SHORT_DIFS : DIFS;
+       ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+       ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+       if (short_preamble)
+               __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+       else
+               __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+       rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
+                                            ack_timeout, ack_consume_time);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
 
-int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue,
-       const struct ieee80211_tx_queue_params *params)
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+                     const struct ieee80211_tx_queue_params *params)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct data_ring *ring;
 
-       ring = rt2x00_get_ring(rt2x00dev, queue);
+       ring = rt2x00lib_get_ring(rt2x00dev, queue);
        if (unlikely(!ring))
                return -EINVAL;
 
@@ -398,10 +437,10 @@ int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue,
                ring->tx_params.aifs = 2;
 
        INFO(rt2x00dev,
-               "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
-               queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
-               ring->tx_params.aifs);
+            "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+            queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
+            ring->tx_params.aifs);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00lib_conf_tx);
+EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);