mwl8k: allow for different receive descriptor formats
Lennert Buytenhek [Thu, 22 Oct 2009 18:20:59 +0000 (20:20 +0200)]
As the receive descriptor format is determined by the firmware running
on the hardware and not by the hardware itself, and as these
descriptor formats vary a bit between different firmware releases,
abstract out the receive descriptor init/refill/process methods, and
allow choosing between different formats at run time depending on the
chip and firmware we're running on.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

drivers/net/wireless/mwl8k.c

index 49ae31b..c9a4c1e 100644 (file)
 #define MWL8K_RX_QUEUES                1
 #define MWL8K_TX_QUEUES                4
 
+struct rxd_ops {
+       int rxd_size;
+       void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
+       void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
+       int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status);
+};
+
 struct mwl8k_device_info {
        char *part_name;
        char *helper_image;
        char *fw_image;
+       struct rxd_ops *rxd_ops;
 };
 
 struct mwl8k_rx_queue {
@@ -95,7 +103,7 @@ struct mwl8k_rx_queue {
        /* refill descs here */
        int tail;
 
-       struct mwl8k_rx_desc *rxd;
+       void *rxd;
        dma_addr_t rxd_dma;
        struct {
                struct sk_buff *skb;
@@ -134,6 +142,7 @@ struct mwl8k_priv {
 
        struct mwl8k_device_info *device_info;
        bool ap_fw;
+       struct rxd_ops *rxd_ops;
 
        /* firmware files and meta data */
        struct mwl8k_firmware fw;
@@ -744,9 +753,7 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 /*
  * Packet reception.
  */
-#define MWL8K_RX_CTRL_OWNED_BY_HOST    0x02
-
-struct mwl8k_rx_desc {
+struct mwl8k_rxd_8687 {
        __le16 pkt_len;
        __u8 link_quality;
        __u8 noise_level;
@@ -763,16 +770,79 @@ struct mwl8k_rx_desc {
        __u8 pad2[2];
 } __attribute__((packed));
 
+#define MWL8K_8687_RATE_INFO_SHORTPRE          0x8000
+#define MWL8K_8687_RATE_INFO_ANTSELECT(x)      (((x) >> 11) & 0x3)
+#define MWL8K_8687_RATE_INFO_RATEID(x)         (((x) >> 3) & 0x3f)
+#define MWL8K_8687_RATE_INFO_40MHZ             0x0004
+#define MWL8K_8687_RATE_INFO_SHORTGI           0x0002
+#define MWL8K_8687_RATE_INFO_MCS_FORMAT                0x0001
+
+#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST       0x02
+
+static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
+{
+       struct mwl8k_rxd_8687 *rxd = _rxd;
+
+       rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
+       rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
+}
+
+static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
+{
+       struct mwl8k_rxd_8687 *rxd = _rxd;
+
+       rxd->pkt_len = cpu_to_le16(len);
+       rxd->pkt_phys_addr = cpu_to_le32(addr);
+       wmb();
+       rxd->rx_ctrl = 0;
+}
+
+static int
+mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status)
+{
+       struct mwl8k_rxd_8687 *rxd = _rxd;
+       u16 rate_info;
+
+       if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
+               return -1;
+       rmb();
+
+       rate_info = le16_to_cpu(rxd->rate_info);
+
+       memset(status, 0, sizeof(*status));
+
+       status->signal = -rxd->rssi;
+       status->noise = -rxd->noise_level;
+       status->qual = rxd->link_quality;
+       status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
+       status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
+
+       if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
+               status->flag |= RX_FLAG_SHORTPRE;
+       if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
+               status->flag |= RX_FLAG_40MHZ;
+       if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
+               status->flag |= RX_FLAG_SHORT_GI;
+       if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
+               status->flag |= RX_FLAG_HT;
+
+       status->band = IEEE80211_BAND_2GHZ;
+       status->freq = ieee80211_channel_to_frequency(rxd->channel);
+
+       return le16_to_cpu(rxd->pkt_len);
+}
+
+static struct rxd_ops rxd_8687_ops = {
+       .rxd_size       = sizeof(struct mwl8k_rxd_8687),
+       .rxd_init       = mwl8k_rxd_8687_init,
+       .rxd_refill     = mwl8k_rxd_8687_refill,
+       .rxd_process    = mwl8k_rxd_8687_process,
+};
+
+
 #define MWL8K_RX_DESCS         256
 #define MWL8K_RX_MAXSZ         3800
 
-#define RATE_INFO_SHORTPRE             0x8000
-#define RATE_INFO_ANTSELECT(x)         (((x) >> 11) & 0x3)
-#define RATE_INFO_RATEID(x)            (((x) >> 3) & 0x3f)
-#define RATE_INFO_40MHZ                        0x0004
-#define RATE_INFO_SHORTGI              0x0002
-#define RATE_INFO_MCS_FORMAT           0x0001
-
 static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
 {
        struct mwl8k_priv *priv = hw->priv;
@@ -784,7 +854,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
        rxq->head = 0;
        rxq->tail = 0;
 
-       size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc);
+       size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size;
 
        rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
        if (rxq->rxd == NULL) {
@@ -804,15 +874,20 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
        memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf));
 
        for (i = 0; i < MWL8K_RX_DESCS; i++) {
-               struct mwl8k_rx_desc *rx_desc;
+               int desc_size;
+               void *rxd;
                int nexti;
+               dma_addr_t next_dma_addr;
+
+               desc_size = priv->rxd_ops->rxd_size;
+               rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size);
 
-               rx_desc = rxq->rxd + i;
-               nexti = (i + 1) % MWL8K_RX_DESCS;
+               nexti = i + 1;
+               if (nexti == MWL8K_RX_DESCS)
+                       nexti = 0;
+               next_dma_addr = rxq->rxd_dma + (nexti * desc_size);
 
-               rx_desc->next_rxd_phys_addr =
-                       cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc));
-               rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST;
+               priv->rxd_ops->rxd_init(rxd, next_dma_addr);
        }
 
        return 0;
@@ -829,25 +904,24 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
                struct sk_buff *skb;
                dma_addr_t addr;
                int rx;
+               void *rxd;
 
                skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
                if (skb == NULL)
                        break;
 
-               rxq->rxd_count++;
-
-               rx = rxq->tail;
-               rxq->tail = (rx + 1) % MWL8K_RX_DESCS;
-
                addr = pci_map_single(priv->pdev, skb->data,
                                      MWL8K_RX_MAXSZ, DMA_FROM_DEVICE);
 
-               rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
-               rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr);
+               rxq->rxd_count++;
+               rx = rxq->tail++;
+               if (rxq->tail == MWL8K_RX_DESCS)
+                       rxq->tail = 0;
                rxq->buf[rx].skb = skb;
                pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
-               wmb();
-               rxq->rxd[rx].rx_ctrl = 0;
+
+               rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
+               priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
 
                refilled++;
        }
@@ -878,7 +952,7 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
        rxq->buf = NULL;
 
        pci_free_consistent(priv->pdev,
-                           MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
+                           MWL8K_RX_DESCS * priv->rxd_ops->rxd_size,
                            rxq->rxd, rxq->rxd_dma);
        rxq->rxd = NULL;
 }
@@ -922,20 +996,21 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
 
        processed = 0;
        while (rxq->rxd_count && limit--) {
-               struct mwl8k_rx_desc *rx_desc;
                struct sk_buff *skb;
+               void *rxd;
+               int pkt_len;
                struct ieee80211_rx_status status;
-               struct ieee80211_hdr *wh;
-               u16 rate_info;
-
-               rx_desc = rxq->rxd + rxq->head;
-               if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
-                       break;
-               rmb();
 
                skb = rxq->buf[rxq->head].skb;
                if (skb == NULL)
                        break;
+
+               rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
+
+               pkt_len = priv->rxd_ops->rxd_process(rxd, &status);
+               if (pkt_len < 0)
+                       break;
+
                rxq->buf[rxq->head].skb = NULL;
 
                pci_unmap_single(priv->pdev,
@@ -943,42 +1018,23 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
                                 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
                pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
 
-               rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS;
+               rxq->head++;
+               if (rxq->head == MWL8K_RX_DESCS)
+                       rxq->head = 0;
+
                rxq->rxd_count--;
 
-               skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
+               skb_put(skb, pkt_len);
                mwl8k_remove_dma_header(skb);
 
-               wh = (struct ieee80211_hdr *)skb->data;
-
                /*
                 * Check for a pending join operation.  Save a
                 * copy of the beacon and schedule a tasklet to
                 * send a FINALIZE_JOIN command to the firmware.
                 */
-               if (mwl8k_capture_bssid(priv, wh))
+               if (mwl8k_capture_bssid(priv, (void *)skb->data))
                        mwl8k_save_beacon(hw, skb);
 
-               rate_info = le16_to_cpu(rx_desc->rate_info);
-
-               memset(&status, 0, sizeof(status));
-               status.mactime = 0;
-               status.signal = -rx_desc->rssi;
-               status.noise = -rx_desc->noise_level;
-               status.qual = rx_desc->link_quality;
-               status.antenna = RATE_INFO_ANTSELECT(rate_info);
-               status.rate_idx = RATE_INFO_RATEID(rate_info);
-               status.flag = 0;
-               if (rate_info & RATE_INFO_SHORTPRE)
-                       status.flag |= RX_FLAG_SHORTPRE;
-               if (rate_info & RATE_INFO_40MHZ)
-                       status.flag |= RX_FLAG_40MHZ;
-               if (rate_info & RATE_INFO_SHORTGI)
-                       status.flag |= RX_FLAG_SHORT_GI;
-               if (rate_info & RATE_INFO_MCS_FORMAT)
-                       status.flag |= RX_FLAG_HT;
-               status.band = IEEE80211_BAND_2GHZ;
-               status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
                memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
                ieee80211_rx_irqsafe(hw, skb);
 
@@ -2959,6 +3015,7 @@ static struct mwl8k_device_info di_8687 = {
        .part_name      = "88w8687",
        .helper_image   = "mwl8k/helper_8687.fw",
        .fw_image       = "mwl8k/fmimage_8687.fw",
+       .rxd_ops        = &rxd_8687_ops,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
@@ -3014,6 +3071,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        priv->hw = hw;
        priv->pdev = pdev;
        priv->device_info = (void *)id->driver_data;
+       priv->rxd_ops = priv->device_info->rxd_ops;
        priv->sniffer_enabled = false;
        priv->wmm_enabled = false;
        priv->pending_tx_pkts = 0;