apex: Create both 8MB and 16MB apex binaries
[openwrt.git] / package / rt2x00 / src / rt2x00pci.c
index 4156ea3..04663eb 100644 (file)
@@ -21,7 +21,6 @@
 /*
        Module: rt2x00pci
        Abstract: rt2x00 generic pci device routines.
-       Supported chipsets: rt2460, rt2560, rt2561, rt2561s & rt2661.
  */
 
 /*
  */
 #define DRV_NAME "rt2x00pci"
 
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 
 #include "rt2x00.h"
  * Beacon handlers.
  */
 int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-       struct ieee80211_tx_control *control)
+                           struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct data_ring *ring =
-               rt2x00_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+           rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
        struct data_entry *entry = rt2x00_get_data_entry(ring);
 
        /*
-        * Just in case the ieee80211 doesn't set this,
+        * Just in case mac80211 doesn't set this correctly,
         * but we need this queue set for the descriptor
         * initialization.
         */
@@ -60,8 +58,9 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
         * Update the beacon entry.
         */
        memcpy(entry->data_addr, skb->data, skb->len);
-       rt2x00lib_write_tx_desc(rt2x00dev, entry, entry->priv,
-               (struct ieee80211_hdr*)skb->data, skb->len, control);
+       rt2x00lib_write_tx_desc(rt2x00dev, entry->priv,
+                               (struct ieee80211_hdr *)skb->data,
+                               skb->len, control);
 
        /*
         * Enable beacon generation.
@@ -72,32 +71,14 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update);
 
-void rt2x00pci_beacondone(struct rt2x00_dev *rt2x00dev, const int queue)
-{
-       struct data_ring *ring = rt2x00_get_ring(rt2x00dev, queue);
-       struct data_entry *entry = rt2x00_get_data_entry(ring);
-       struct sk_buff *skb;
-
-       skb = ieee80211_beacon_get(rt2x00dev->hw,
-               rt2x00dev->interface.id, &entry->tx_status.control);
-       if (!skb)
-               return;
-
-       rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
-               &entry->tx_status.control);
-
-       dev_kfree_skb(skb);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_beacondone);
-
 /*
  * TX data handlers.
  */
 int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
-       struct data_ring *ring, struct sk_buff *skb,
-       struct ieee80211_tx_control *control)
+                           struct data_ring *ring, struct sk_buff *skb,
+                           struct ieee80211_tx_control *control)
 {
-       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        struct data_entry *entry = rt2x00_get_data_entry(ring);
        struct data_desc *txd = entry->priv;
        u32 word;
@@ -109,20 +90,21 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_desc_read(txd, 0, &word);
 
-       if (rt2x00_get_field32(word, TXD_ENTRY_AVAILABLE)) {
+       if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
+           rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
                ERROR(rt2x00dev,
-                       "Arrived at non-free entry in the non-full queue %d.\n"
-                       "Please file bug report to %s.\n",
-                       control->queue, DRV_PROJECT);
+                     "Arrived at non-free entry in the non-full queue %d.\n"
+                     "Please file bug report to %s.\n",
+                     control->queue, DRV_PROJECT);
                ieee80211_stop_queue(rt2x00dev->hw, control->queue);
                return -EINVAL;
        }
 
-       memcpy(entry->data_addr, skb->data, skb->len);
-       rt2x00lib_write_tx_desc(rt2x00dev, entry, txd, ieee80211hdr,
-               skb->len, control);
-       memcpy(&entry->tx_status.control, control, sizeof(*control));
        entry->skb = skb;
+       memcpy(&entry->tx_status.control, control, sizeof(*control));
+       memcpy(entry->data_addr, skb->data, skb->len);
+       rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr,
+                               skb->len, control);
 
        rt2x00_ring_index_inc(ring);
 
@@ -133,6 +115,68 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_ring *ring = rt2x00dev->rx;
+       struct data_entry *entry;
+       struct data_desc *rxd;
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       struct rxdata_entry_desc desc;
+       int header_size;
+       int align;
+       u32 word;
+
+       while (1) {
+               entry = rt2x00_get_data_entry(ring);
+               rxd = entry->priv;
+               rt2x00_desc_read(rxd, 0, &word);
+
+               if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+                       break;
+
+               memset(&desc, 0x00, sizeof(desc));
+               rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+               hdr = (struct ieee80211_hdr *)entry->data_addr;
+               header_size =
+                   ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+
+               /*
+                * The data behind the ieee80211 header must be
+                * aligned on a 4 byte boundary.
+                */
+               align = header_size % 4;
+
+               /*
+                * Allocate the sk_buffer, initialize it and copy
+                * all data into it.
+                */
+               skb = dev_alloc_skb(desc.size + align);
+               if (!skb)
+                       return;
+
+               skb_reserve(skb, align);
+               memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size);
+
+               /*
+                * Send the frame to rt2x00lib for further processing.
+                */
+               rt2x00lib_rxdone(entry, skb, &desc);
+
+               if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+                       rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+                       rt2x00_desc_write(rxd, 0, word);
+               }
+
+               rt2x00_ring_index_inc(ring);
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
 /*
  * Device initialization handlers.
  */
@@ -143,20 +187,20 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 
 #define data_addr_offset(__ring, __i)                          \
 ({                                                             \
-       (__ring)->data_addr                                     \
-               + ((__ring)->stats.limit * (__ring)->desc_size) \
-               + ((__i) * (__ring)->data_size);                \
+       (__ring)->data_addr +                                   \
+           ((__ring)->stats.limit * (__ring)->desc_size) +     \
+           ((__i) * (__ring)->data_size);                      \
 })
 
 #define data_dma_offset(__ring, __i)                           \
 ({                                                             \
-       (__ring)->data_dma                                      \
-               + ((__ring)->stats.limit * (__ring)->desc_size) \
-               + ((__i) * (__ring)->data_size);                \
+       (__ring)->data_dma +                                    \
+           ((__ring)->stats.limit * (__ring)->desc_size) +     \
+           ((__i) * (__ring)->data_size);                      \
 })
 
-static int rt2x00pci_alloc_ring(struct rt2x00_dev *rt2x00dev,
-       struct data_ring *ring)
+static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev,
+                              struct data_ring *ring)
 {
        unsigned int i;
 
@@ -164,7 +208,8 @@ static int rt2x00pci_alloc_ring(struct rt2x00_dev *rt2x00dev,
         * Allocate DMA memory for descriptor and buffer.
         */
        ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev),
-               rt2x00_get_ring_size(ring), &ring->data_dma);
+                                              rt2x00_get_ring_size(ring),
+                                              &ring->data_dma);
        if (!ring->data_addr)
                return -ENOMEM;
 
@@ -181,6 +226,16 @@ static int rt2x00pci_alloc_ring(struct rt2x00_dev *rt2x00dev,
        return 0;
 }
 
+static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev,
+                              struct data_ring *ring)
+{
+       if (ring->data_addr)
+               pci_free_consistent(rt2x00dev_pci(rt2x00dev),
+                                   rt2x00_get_ring_size(ring),
+                                   ring->data_addr, ring->data_dma);
+       ring->data_addr = NULL;
+}
+
 int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
 {
        struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
@@ -191,7 +246,7 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
         * Allocate DMA
         */
        ring_for_each(rt2x00dev, ring) {
-               status = rt2x00pci_alloc_ring(rt2x00dev, ring);
+               status = rt2x00pci_alloc_dma(rt2x00dev, ring);
                if (status)
                        goto exit;
        }
@@ -200,10 +255,10 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
         * Register interrupt handler.
         */
        status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
-               IRQF_SHARED, pci_dev->driver->name, rt2x00dev);
+                            IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
        if (status) {
                ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
-                       pci_dev->irq, status);
+                     pci_dev->irq, status);
                return status;
        }
 
@@ -228,43 +283,58 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
        /*
         * Free DMA
         */
-       ring_for_each(rt2x00dev, ring) {
-               if (ring->data_addr)
-                       pci_free_consistent(rt2x00dev_pci(rt2x00dev),
-                               rt2x00_get_ring_size(ring),
-                               ring->data_addr, ring->data_dma);
-               ring->data_addr = NULL;
-       }
+       ring_for_each(rt2x00dev, ring)
+               rt2x00pci_free_dma(rt2x00dev, ring);
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
 
 /*
  * PCI driver handlers.
  */
-static int rt2x00pci_alloc_csr(struct rt2x00_dev *rt2x00dev)
+static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
 {
-       rt2x00dev->csr_addr = ioremap(
-               pci_resource_start(rt2x00dev_pci(rt2x00dev), 0),
-               pci_resource_len(rt2x00dev_pci(rt2x00dev), 0));
-       if (!rt2x00dev->csr_addr) {
-               ERROR(rt2x00dev, "Ioremap failed.\n");
-               return -ENOMEM;
-       }
+       kfree(rt2x00dev->rf);
+       rt2x00dev->rf = NULL;
 
-       return 0;
-}
+       kfree(rt2x00dev->eeprom);
+       rt2x00dev->eeprom = NULL;
 
-static void rt2x00pci_free_csr(struct rt2x00_dev *rt2x00dev)
-{
        if (rt2x00dev->csr_addr) {
                iounmap(rt2x00dev->csr_addr);
                rt2x00dev->csr_addr = NULL;
        }
 }
 
+static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+       struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+
+       rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0),
+                                     pci_resource_len(pci_dev, 0));
+       if (!rt2x00dev->csr_addr)
+               goto exit;
+
+       rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+       if (!rt2x00dev->eeprom)
+               goto exit;
+
+       rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+       if (!rt2x00dev->rf)
+               goto exit;
+
+       return 0;
+
+exit:
+       ERROR_PROBE("Failed to allocate registers.\n");
+
+       rt2x00pci_free_reg(rt2x00dev);
+
+       return -ENOMEM;
+}
+
 int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
-       struct rt2x00_ops *ops = (struct rt2x00_ops*)id->driver_data;
+       struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
        struct ieee80211_hw *hw;
        struct rt2x00_dev *rt2x00dev;
        int retval;
@@ -304,22 +374,21 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 
        rt2x00dev = hw->priv;
        rt2x00dev->dev = pci_dev;
-       rt2x00dev->device = &pci_dev->dev;
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
 
-       retval = rt2x00pci_alloc_csr(rt2x00dev);
+       retval = rt2x00pci_alloc_reg(rt2x00dev);
        if (retval)
                goto exit_free_device;
 
        retval = rt2x00lib_probe_dev(rt2x00dev);
        if (retval)
-               goto exit_free_csr;
+               goto exit_free_reg;
 
        return 0;
 
-exit_free_csr:
-       rt2x00pci_free_csr(rt2x00dev);
+exit_free_reg:
+       rt2x00pci_free_reg(rt2x00dev);
 
 exit_free_device:
        ieee80211_free_hw(hw);
@@ -346,6 +415,7 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
         * Free all allocated data.
         */
        rt2x00lib_remove_dev(rt2x00dev);
+       rt2x00pci_free_reg(rt2x00dev);
        ieee80211_free_hw(hw);
 
        /*
@@ -368,7 +438,7 @@ int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
        if (retval)
                return retval;
 
-       rt2x00pci_free_csr(rt2x00dev);
+       rt2x00pci_free_reg(rt2x00dev);
 
        pci_save_state(pci_dev);
        pci_disable_device(pci_dev);
@@ -389,11 +459,20 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
                return -EIO;
        }
 
-       retval = rt2x00pci_alloc_csr(rt2x00dev);
+       retval = rt2x00pci_alloc_reg(rt2x00dev);
        if (retval)
                return retval;
 
-       return rt2x00lib_resume(rt2x00dev);
+       retval = rt2x00lib_resume(rt2x00dev);
+       if (retval)
+               goto exit_free_reg;
+
+       return 0;
+
+exit_free_reg:
+       rt2x00pci_free_reg(rt2x00dev);
+
+       return retval;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_resume);
 #endif /* CONFIG_PM */
This page took 0.040757 seconds and 4 git commands to generate.