|
@@ -80,10 +80,18 @@
|
|
|
#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;
|