adm8211: Restore frame header after TX This patch makes the adm8211 driver restore the TX frame's header to the original 802.11 header before returning it to the 802.11 stack. This allows the d80211 rate control algorithm to work correctly.
Signed-off-by: Michael Wu <[EMAIL PROTECTED]> --- drivers/net/wireless/d80211/adm8211/adm8211.c | 79 +++++++++++++------------ drivers/net/wireless/d80211/adm8211/adm8211.h | 13 +++- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.c b/drivers/net/wireless/d80211/adm8211/adm8211.c index 4cfddf1..be4a058 100644 --- a/drivers/net/wireless/d80211/adm8211/adm8211.c +++ b/drivers/net/wireless/d80211/adm8211/adm8211.c @@ -423,7 +423,6 @@ static void adm8211_interrupt_tci(struct priv->cur_tx - dirty_tx > 0; dirty_tx++) { unsigned entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); - struct sk_buff *skb; if (status & TDES0_CONTROL_OWN || !(status & TDES0_CONTROL_DONE)) @@ -438,15 +437,19 @@ static void adm8211_interrupt_tci(struct } else priv->tx_buffers[entry].tx_status.ack = 1; - skb = priv->tx_buffers[entry].skb; pci_unmap_single(priv->pdev, priv->tx_buffers[entry].mapping, - skb->len, PCI_DMA_TODEVICE); + priv->tx_buffers[entry].skb->len, PCI_DMA_TODEVICE); if (priv->tx_buffers[entry].tx_status.control.req_tx_status || - priv->tx_buffers[entry].unicast) + !is_multicast_ether_addr(ieee80211_get_DA(&priv->tx_buffers[entry].hdr))) { + struct ieee80211_hdr *hdr; + size_t hdrlen = ieee80211_get_hdrlen(le16_to_cpu(priv->tx_buffers[entry].hdr.frame_control)); + hdr = (struct ieee80211_hdr *) skb_pull(priv->tx_buffers[entry].skb, + sizeof(struct adm8211_tx_hdr) - hdrlen); + memcpy(hdr, &priv->tx_buffers[entry].hdr, hdrlen); ieee80211_tx_status_irqsafe(dev, priv->tx_buffers[entry].skb, &priv->tx_buffers[entry].tx_status); - else + } else dev_kfree_skb_irq(priv->tx_buffers[entry].skb); priv->tx_buffers[entry].skb = NULL; } @@ -1527,7 +1530,8 @@ static int adm8211_init_rings(struct net { struct adm8211_priv *priv = ieee80211_dev_hw_data(dev); struct adm8211_desc *desc = NULL; - struct adm8211_ring_info *info; + struct adm8211_rx_ring_info *rx_info; + struct adm8211_tx_ring_info *tx_info; unsigned int i; for (i = 0; i < priv->rx_ring_size; i++) { @@ -1542,26 +1546,26 @@ static int adm8211_init_rings(struct net for (i = 0; i < priv->rx_ring_size; i++) { desc = &priv->rx_ring[i]; - info = &priv->rx_buffers[i]; + rx_info = &priv->rx_buffers[i]; - info->skb = dev_alloc_skb(RX_PKT_SIZE); - if (info->skb == NULL) + rx_info->skb = dev_alloc_skb(RX_PKT_SIZE); + if (rx_info->skb == NULL) break; - info->mapping = pci_map_single(priv->pdev, info->skb->tail, - RX_PKT_SIZE, - PCI_DMA_FROMDEVICE); - info->skb->dev = dev; - desc->buffer1 = cpu_to_le32(info->mapping); - desc->status = cpu_to_le32( RDES0_STATUS_OWN | RDES0_STATUS_SQL ); + rx_info->mapping = pci_map_single(priv->pdev, rx_info->skb->tail, + RX_PKT_SIZE, + PCI_DMA_FROMDEVICE); + rx_info->skb->dev = dev; + desc->buffer1 = cpu_to_le32(rx_info->mapping); + desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); } /* Setup TX ring. TX buffers descriptors will be filled in as needed */ for (i = 0; i < priv->tx_ring_size; i++) { desc = &priv->tx_ring[i]; - info = &priv->tx_buffers[i]; + tx_info = &priv->tx_buffers[i]; - info->skb = NULL; - info->mapping = 0; + tx_info->skb = NULL; + tx_info->mapping = 0; desc->status = 0; } desc->length = cpu_to_le32(TDES1_CONTROL_TER); @@ -1750,7 +1754,8 @@ #define IEEE80211_DUR_DS_SIFS 10 /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ static void adm8211_tx_raw(struct net_device *dev, struct sk_buff *skb, - u16 plcp_signal, struct ieee80211_tx_control *control, int unicast) + u16 plcp_signal, struct ieee80211_tx_control *control, + struct ieee80211_hdr *hdr) { struct adm8211_priv *priv = ieee80211_dev_hw_data(dev); unsigned long flags; @@ -1780,7 +1785,7 @@ static void adm8211_tx_raw(struct net_de priv->tx_buffers[entry].skb = skb; priv->tx_buffers[entry].mapping = mapping; memcpy(&priv->tx_buffers[entry].tx_status.control, control, sizeof(*control)); - priv->tx_buffers[entry].unicast = unicast; + memcpy(&priv->tx_buffers[entry].hdr, hdr, sizeof(*hdr)); priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); if (entry == priv->tx_ring_size - 1) @@ -1806,14 +1811,12 @@ static int adm8211_tx(struct net_device struct ieee80211_tx_control *control) { struct adm8211_tx_hdr *txhdr; - struct ieee80211_hdr *hdr; - u16 fc_; - __le16 fc; - u8 dst[ETH_ALEN]; + u16 fc; size_t payload_len, hdrlen; int plcp, dur, len; int plcp_signal; int short_preamble; + struct ieee80211_hdr hdr; if (control->tx_rate < 0) { short_preamble = 1; @@ -1823,14 +1826,11 @@ static int adm8211_tx(struct net_device plcp_signal = control->tx_rate; } - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - fc_ = le16_to_cpu(fc); - memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(&hdr, skb->data, sizeof(hdr)); - hdrlen = ieee80211_get_hdrlen(fc_); + fc = le16_to_cpu(hdr.frame_control) & ~WLAN_FC_ISWEP; + hdrlen = ieee80211_get_hdrlen(fc); skb_pull(skb, hdrlen); - fc_ &= ~WLAN_FC_ISWEP; payload_len = skb->len; if (skb_headroom(skb) < sizeof(struct adm8211_tx_hdr)) { @@ -1844,13 +1844,13 @@ static int adm8211_tx(struct net_device txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr)); memset(txhdr, 0, sizeof(*txhdr)); - memcpy(txhdr->da, dst, ETH_ALEN); + memcpy(txhdr->da, ieee80211_get_DA(&hdr), ETH_ALEN); txhdr->signal = plcp_signal; txhdr->frame_body_size = cpu_to_le16(payload_len); - txhdr->frame_control = fc; + txhdr->frame_control = hdr.frame_control; len = hdrlen + payload_len + FCS_LEN; - if (fc_ & WLAN_FC_ISWEP) + if (fc & WLAN_FC_ISWEP) len += 8; txhdr->frag = cpu_to_le16(0x0FFF); @@ -1869,12 +1869,12 @@ static int adm8211_tx(struct net_device if (control->use_rts_cts) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - if (fc_ & WLAN_FC_ISWEP) + if (fc & WLAN_FC_ISWEP) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); txhdr->retry_limit = control->retry_limit; - adm8211_tx_raw(dev, skb, plcp_signal, control, !is_multicast_ether_addr(dst)); + adm8211_tx_raw(dev, skb, plcp_signal, control, &hdr); return NETDEV_TX_OK; } @@ -1884,12 +1884,12 @@ static int adm8211_alloc_rings(struct ne struct adm8211_priv *priv = ieee80211_dev_hw_data(dev); unsigned int ring_size; - priv->rx_buffers = kmalloc(sizeof(struct adm8211_ring_info) * - (priv->rx_ring_size + priv->tx_ring_size), GFP_KERNEL); + priv->rx_buffers = kmalloc(sizeof(struct adm8211_rx_ring_info) * priv->rx_ring_size + + sizeof(struct adm8211_tx_ring_info) * priv->tx_ring_size, GFP_KERNEL); if (!priv->rx_buffers) return -ENOMEM; - priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct adm8211_ring_info) * priv->tx_ring_size; + priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct adm8211_rx_ring_info) * priv->rx_ring_size; /* Allocate TX/RX descriptors */ ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size + @@ -1899,7 +1899,8 @@ static int adm8211_alloc_rings(struct ne if (!priv->rx_ring) { kfree(priv->rx_buffers); - priv->rx_buffers = priv->tx_buffers = NULL; + priv->rx_buffers = NULL; + priv->tx_buffers = NULL; return -ENOMEM; } diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.h b/drivers/net/wireless/d80211/adm8211/adm8211.h index 13965b4..89e0fdf 100644 --- a/drivers/net/wireless/d80211/adm8211/adm8211.h +++ b/drivers/net/wireless/d80211/adm8211/adm8211.h @@ -439,11 +439,16 @@ #define ADM8211_SRAM_A_SIZE 0x0200 #define ADM8211_SRAM_B_SIZE 0x01c0 #define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE) -struct adm8211_ring_info { +struct adm8211_rx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct adm8211_tx_ring_info { struct sk_buff *skb; dma_addr_t mapping; struct ieee80211_tx_status tx_status; - int unicast; + struct ieee80211_hdr hdr; }; struct adm8211_eeprom { @@ -521,8 +526,8 @@ struct adm8211_priv { struct adm8211_desc *tx_ring; dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; - struct adm8211_ring_info *rx_buffers; - struct adm8211_ring_info *tx_buffers; + struct adm8211_rx_ring_info *rx_buffers; + struct adm8211_tx_ring_info *tx_buffers; unsigned rx_ring_size, tx_ring_size; unsigned cur_tx, dirty_tx, cur_rx;
pgpVxaxRFSwVX.pgp
Description: PGP signature