struct sk_buff **rx_skb;
};
-struct mwl8k_skb {
- /*
- * The DMA engine requires a modification to the payload.
- * If the skbuff is shared/cloned, it needs to be unshared.
- * This method is used to ensure the stack always gets back
- * the skbuff it sent for transmission.
- */
- struct sk_buff *clone;
- struct sk_buff *skb;
-};
-
struct mwl8k_tx_queue {
/* hw transmits here */
int tx_head;
struct ieee80211_tx_queue_stats tx_stats;
struct mwl8k_tx_desc *tx_desc_area;
dma_addr_t tx_desc_dma;
- struct mwl8k_skb *tx_skb;
+ struct sk_buff **tx_skb;
};
/* Pointers to the firmware data and meta information about it. */
{ .bitrate = 540, .hw_value = 108, },
};
-/* Slot time */
-
-/* Short Slot: 9us slot time */
-#define MWL8K_SHORT_SLOTTIME 1
-
-/* Long slot: 20us slot time */
-#define MWL8K_LONG_SLOTTIME 0
-
/* Set or get info from Firmware */
#define MWL8K_CMD_SET 0x0001
#define MWL8K_CMD_GET 0x0000
} __attribute__((packed));
/* Routines to add/remove DMA header from skb. */
-static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
+static inline void mwl8k_remove_dma_header(struct sk_buff *skb)
{
- struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
+ struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data;
void *dst, *src = &tr->wh;
- __le16 fc = tr->wh.frame_control;
- int hdrlen = ieee80211_hdrlen(fc);
+ int hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
dst = (void *)tr + space;
memmove(dst, src, hdrlen);
skb_pull(skb, space);
}
-
- return 0;
}
-static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
+static inline void mwl8k_add_dma_header(struct sk_buff *skb)
{
struct ieee80211_hdr *wh;
u32 hdrlen, pktlen;
* This includes all crypto material including the MIC.
*/
tr->fwlen = cpu_to_le16(pktlen - hdrlen);
-
- return skb;
}
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
- if (mwl8k_remove_dma_header(skb)) {
- dev_kfree_skb(skb);
- continue;
- }
+ mwl8k_remove_dma_header(skb);
wh = (struct ieee80211_hdr *)skb->data;
while (txq->tx_stats.len > 0) {
int tx;
- int rc;
struct mwl8k_tx_desc *tx_desc;
unsigned long addr;
int size;
struct ieee80211_tx_info *info;
u32 status;
- rc = 0;
tx = txq->tx_head;
tx_desc = txq->tx_desc_area + tx;
addr = le32_to_cpu(tx_desc->pkt_phys_addr);
size = le16_to_cpu(tx_desc->pkt_len);
- skb = txq->tx_skb[tx].skb;
- txq->tx_skb[tx].skb = NULL;
+ skb = txq->tx_skb[tx];
+ txq->tx_skb[tx] = NULL;
BUG_ON(skb == NULL);
pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
- rc = mwl8k_remove_dma_header(skb);
+ mwl8k_remove_dma_header(skb);
/* Mark descriptor as unused */
tx_desc->pkt_phys_addr = 0;
tx_desc->pkt_len = 0;
- if (txq->tx_skb[tx].clone) {
- /* Replace with original skb
- * before returning to stack
- * as buffer has been cloned
- */
- dev_kfree_skb(skb);
- skb = txq->tx_skb[tx].clone;
- txq->tx_skb[tx].clone = NULL;
- }
-
- if (rc) {
- /* Something has gone wrong here.
- * Failed to remove DMA header.
- * Print error message and drop packet.
- */
- printk(KERN_ERR "%s: Error removing DMA header from "
- "tx skb 0x%p.\n", priv->name, skb);
-
- dev_kfree_skb(skb);
- continue;
- }
-
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
if (MWL8K_TXD_SUCCESS(status))
struct mwl8k_tx_desc *tx;
struct mwl8k_dma_data *tr;
struct mwl8k_vif *mwl8k_vif;
- struct sk_buff *org_skb = skb;
dma_addr_t dma;
u16 qos = 0;
bool qosframe = false, ampduframe = false;
txq = priv->txq + index;
tx = txq->tx_desc_area + txq->tx_tail;
- BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
+ BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
/*
- * Append HW DMA header to start of packet. Drop packet if
- * there is not enough space or a failure to unshare/unclone
- * the skb.
+ * Append HW DMA header to start of packet.
*/
- skb = mwl8k_add_dma_header(skb);
-
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: failed to prepend HW DMA "
- "header, dropping TX frame.\n", priv->name);
- dev_kfree_skb(org_skb);
- return NETDEV_TX_OK;
- }
+ mwl8k_add_dma_header(skb);
tx_info = IEEE80211_SKB_CB(skb);
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
printk(KERN_DEBUG "%s: failed to dma map skb, "
"dropping TX frame.\n", priv->name);
- if (org_skb != NULL)
- dev_kfree_skb(org_skb);
if (skb != NULL)
dev_kfree_skb(skb);
return NETDEV_TX_OK;
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
- txq->tx_skb[txq->tx_tail].skb = skb;
- txq->tx_skb[txq->tx_tail].clone =
- skb == org_skb ? NULL : org_skb;
+ txq->tx_skb[txq->tx_tail] = skb;
spin_lock_bh(&priv->tx_lock);
#define MWL8K_ENABLE_RX_MULTICAST 0x000F
-static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
- int mc_count,
- struct dev_addr_list *mclist)
+static struct mwl8k_cmd_pkt *
+__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
{
+ struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_mac_multicast_adr *cmd;
- int index = 0;
- int rc;
- int size = sizeof(*cmd) + mc_count * ETH_ALEN;
+ int size;
+ int i;
+
+ if (mc_count > priv->num_mcaddrs)
+ mc_count = priv->num_mcaddrs;
- cmd = kzalloc(size, GFP_KERNEL);
+ size = sizeof(*cmd) + mc_count * ETH_ALEN;
+
+ cmd = kzalloc(size, GFP_ATOMIC);
if (cmd == NULL)
- return -ENOMEM;
+ return NULL;
cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
cmd->header.length = cpu_to_le16(size);
cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
cmd->numaddr = cpu_to_le16(mc_count);
- while (index < mc_count && mclist) {
+ for (i = 0; i < mc_count && mclist; i++) {
if (mclist->da_addrlen != ETH_ALEN) {
- rc = -EINVAL;
- goto mwl8k_cmd_mac_multicast_adr_exit;
+ kfree(cmd);
+ return NULL;
}
- memcpy(cmd->addr[index++], mclist->da_addr, ETH_ALEN);
+ memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
mclist = mclist->next;
}
- rc = mwl8k_post_cmd(hw, &cmd->header);
-
-mwl8k_cmd_mac_multicast_adr_exit:
- kfree(cmd);
- return rc;
+ return &cmd->header;
}
/*
__u8 short_slot;
} __attribute__((packed));
-static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time)
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
{
struct mwl8k_cmd_set_slot *cmd;
int rc;
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
cmd->header.length = cpu_to_le16(sizeof(*cmd));
cmd->action = cpu_to_le16(MWL8K_CMD_SET);
- cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0;
+ cmd->short_slot = short_slot_time;
rc = mwl8k_post_cmd(hw, &cmd->header);
kfree(cmd);
/*
* We only support managed interfaces for now.
*/
- if (conf->type != NL80211_IFTYPE_STATION &&
- conf->type != NL80211_IFTYPE_MONITOR)
+ if (conf->type != NL80211_IFTYPE_STATION)
return -EINVAL;
/* Clean out driver private area */
goto mwl8k_bss_info_changed_exit;
/* Set slot time */
- if (mwl8k_cmd_set_slot(hw, info->use_short_slot ?
- MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME))
+ if (mwl8k_cmd_set_slot(hw, info->use_short_slot))
goto mwl8k_bss_info_changed_exit;
/* Update peer rate info */
printk(KERN_ERR "%s() timed out\n", __func__);
}
+static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ struct mwl8k_cmd_pkt *cmd;
+
+ cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
+
+ return (unsigned long)cmd;
+}
+
struct mwl8k_configure_filter_worker {
struct mwl8k_work_struct header;
unsigned int changed_flags;
- unsigned int *total_flags;
- int mc_count;
- struct dev_addr_list *mclist;
+ unsigned int total_flags;
+ struct mwl8k_cmd_pkt *multicast_adr_cmd;
};
#define MWL8K_SUPPORTED_IF_FLAGS FIF_BCN_PRBRESP_PROMISC
{
struct mwl8k_configure_filter_worker *worker =
(struct mwl8k_configure_filter_worker *)wt;
-
struct ieee80211_hw *hw = worker->header.hw;
- unsigned int changed_flags = worker->changed_flags;
- unsigned int *total_flags = worker->total_flags;
- int mc_count = worker->mc_count;
- struct dev_addr_list *mclist = worker->mclist;
-
struct mwl8k_priv *priv = hw->priv;
int rc = 0;
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ if (worker->changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (worker->total_flags & FIF_BCN_PRBRESP_PROMISC)
rc = mwl8k_cmd_set_pre_scan(hw);
else {
u8 *bssid;
}
}
- if (rc)
- goto mwl8k_configure_filter_exit;
- if (mc_count) {
- if (mc_count > priv->num_mcaddrs)
- mc_count = priv->num_mcaddrs;
-
- rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
- if (rc)
- printk(KERN_ERR
- "%s()Error setting multicast addresses\n",
- __func__);
- }
+ if (!rc && worker->multicast_adr_cmd != NULL)
+ rc = mwl8k_post_cmd(hw, worker->multicast_adr_cmd);
+ kfree(worker->multicast_adr_cmd);
-mwl8k_configure_filter_exit:
return rc;
}
-static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
- int mc_count, struct dev_addr_list *mclist)
-{
- struct mwl8k_configure_filter_worker *worker;
-
- worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
-
- if (!worker)
- return 0;
-
- /*
- * XXX: This is _HORRIBLY_ broken!!
- *
- * No locking, the mclist pointer might be invalid as soon as this
- * function returns, something in the list might be invalidated
- * once we get to the worker, etc...
- */
- worker->mc_count = mc_count;
- worker->mclist = mclist;
-
- return (u64)worker;
-}
-
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
-
- struct mwl8k_configure_filter_worker *worker = (void *)multicast;
struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_configure_filter_worker *worker;
/* Clear unsupported feature flags */
*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
return;
+ worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
if (worker == NULL)
return;
- worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
worker->changed_flags = changed_flags;
- worker->total_flags = total_flags;
+ worker->total_flags = *total_flags;
+ worker->multicast_adr_cmd = (void *)(unsigned long)multicast;
mwl8k_queue_work(hw, &worker->header, priv->config_wq,
mwl8k_configure_filter_wt);
hw->queues = MWL8K_TX_QUEUES;
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
/* Set rssi and noise values to dBm */
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;