void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { struct b43_pio_txqueue *q; struct b43_pio_txpacket *pack = NULL; unsigned int total_len; struct ieee80211_tx_info *info; q = parse_cookie(dev, status->cookie, &pack); if (unlikely(!q)) return; B43_WARN_ON(!pack); info = IEEE80211_SKB_CB(pack->skb); b43_fill_txstatus_report(dev, info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); q->buffer_used -= total_len; q->free_packet_slots += 1; ieee80211_tx_status(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); if (q->stopped) { ieee80211_wake_queue(dev->wl->hw, q->queue_prio); q->stopped = 0; } }
static int pio_tx_frame(struct b43_pio_txqueue *q, struct sk_buff *skb) { struct b43_wldev *dev = q->dev; struct b43_wl *wl = dev->wl; struct b43_pio_txpacket *pack; u16 cookie; int err; unsigned int hdrlen; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace; B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(dev); BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr)); B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen); err = b43_generate_txhdr(dev, (u8 *)txhdr, skb, info, cookie); if (err) return err; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MCASTCOOKIE, cookie); } pack->skb = skb; if (q->rev >= 8) pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen); else pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen); /* Remove it from the list of available packet slots. * It will be put back when we receive the status report. */ list_del(&pack->list); /* Update the queue statistics. */ q->buffer_used += roundup(skb->len + hdrlen, 4); q->free_packet_slots -= 1; return 0; }
static int pio_tx_frame(struct b43_pio_txqueue *q, struct sk_buff *skb) { struct b43_wldev *dev = q->dev; struct b43_wl *wl = dev->wl; struct b43_pio_txpacket *pack; u16 cookie; int err; unsigned int hdrlen; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace; B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(dev); BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr)); B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen); err = b43_generate_txhdr(dev, (u8 *)txhdr, skb, info, cookie); if (err) return err; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MCASTCOOKIE, cookie); } pack->skb = skb; if (q->rev >= 8) pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen); else pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen); list_del(&pack->list); q->buffer_used += roundup(skb->len + hdrlen, 4); q->free_packet_slots -= 1; return 0; }
/* Main initialization function. */ static struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, int controller_index, int for_tx, enum b43_dmatype type) { struct b43_dmaring *ring; int i, err; dma_addr_t dma_test; ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) goto out; ring->nr_slots = B43_RXRING_SLOTS; if (for_tx) ring->nr_slots = B43_TXRING_SLOTS; ring->meta = kcalloc(ring->nr_slots, sizeof(struct b43_dmadesc_meta), GFP_KERNEL); if (!ring->meta) goto err_kfree_ring; for (i = 0; i < ring->nr_slots; i++) ring->meta->skb = B43_DMA_PTR_POISON; ring->type = type; ring->dev = dev; ring->mmio_base = b43_dmacontroller_base(type, controller_index); ring->index = controller_index; if (type == B43_DMA_64BIT) ring->ops = &dma64_ops; else ring->ops = &dma32_ops; if (for_tx) { ring->tx = true; ring->current_slot = -1; } else { if (ring->index == 0) { switch (dev->fw.hdr_format) { case B43_FW_HDR_598: ring->rx_buffersize = B43_DMA0_RX_FW598_BUFSIZE; ring->frameoffset = B43_DMA0_RX_FW598_FO; break; case B43_FW_HDR_410: case B43_FW_HDR_351: ring->rx_buffersize = B43_DMA0_RX_FW351_BUFSIZE; ring->frameoffset = B43_DMA0_RX_FW351_FO; break; } } else B43_WARN_ON(1); } #ifdef CPTCFG_B43_DEBUG ring->last_injected_overflow = jiffies; #endif if (for_tx) { /* Assumption: B43_TXRING_SLOTS can be divided by TX_SLOTS_PER_FRAME */ BUILD_BUG_ON(B43_TXRING_SLOTS % TX_SLOTS_PER_FRAME != 0); ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME, b43_txhdr_size(dev), GFP_KERNEL); if (!ring->txhdr_cache) goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { /* ugh realloc */ kfree(ring->txhdr_cache); ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME, b43_txhdr_size(dev), GFP_KERNEL | GFP_DMA); if (!ring->txhdr_cache) goto err_kfree_meta; dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, b43_txhdr_size(dev), DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { b43err(dev->wl, "TXHDR DMA allocation failed\n"); goto err_kfree_txhdr_cache; } } dma_unmap_single(dev->dev->dma_dev, dma_test, b43_txhdr_size(dev), DMA_TO_DEVICE); } err = alloc_ringmemory(ring); if (err) goto err_kfree_txhdr_cache; err = dmacontroller_setup(ring); if (err) goto err_free_ringmemory; out: return ring; err_free_ringmemory: free_ringmemory(ring); err_kfree_txhdr_cache: kfree(ring->txhdr_cache); err_kfree_meta: kfree(ring->meta); err_kfree_ring: kfree(ring); ring = NULL; goto out; }
void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { const struct b43_dma_ops *ops; struct b43_dmaring *ring; struct b43_dmadesc_meta *meta; static const struct b43_txstatus fake; /* filled with 0 */ const struct b43_txstatus *txstat; int slot, firstused; bool frame_succeed; int skip; static u8 err_out1, err_out2; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return; B43_WARN_ON(!ring->tx); /* Sanity check: TX packets are processed in-order on one ring. * Check if the slot deduced from the cookie really is the first * used slot. */ firstused = ring->current_slot - ring->used_slots + 1; if (firstused < 0) firstused = ring->nr_slots + firstused; skip = 0; if (unlikely(slot != firstused)) { /* This possibly is a firmware bug and will result in * malfunction, memory leaks and/or stall of DMA functionality. */ if (slot == next_slot(ring, next_slot(ring, firstused))) { /* If a single header/data pair was missed, skip over * the first two slots in an attempt to recover. */ slot = firstused; skip = 2; if (!err_out1) { /* Report the error once. */ b43dbg(dev->wl, "Skip on DMA ring %d slot %d.\n", ring->index, slot); err_out1 = 1; } } else { /* More than a single header/data pair were missed. * Report this error once. */ if (!err_out2) b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", ring->index, firstused, slot); err_out2 = 1; return; } } ops = ring->ops; while (1) { B43_WARN_ON(slot < 0 || slot >= ring->nr_slots); /* get meta - ignore returned value */ ops->idx2desc(ring, slot, &meta); if (b43_dma_ptr_is_poisoned(meta->skb)) { b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) " "on ring %d\n", slot, firstused, ring->index); break; } if (meta->skb) { struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); kfree(priv_info->bouncebuffer); priv_info->bouncebuffer = NULL; } else { unmap_descbuffer(ring, meta->dmaaddr, b43_txhdr_size(dev), 1); } if (meta->is_last_fragment) { struct ieee80211_tx_info *info; if (unlikely(!meta->skb)) { /* This is a scatter-gather fragment of a frame, * so the skb pointer must not be NULL. */ b43dbg(dev->wl, "TX status unexpected NULL skb " "at slot %d (first=%d) on ring %d\n", slot, firstused, ring->index); break; } info = IEEE80211_SKB_CB(meta->skb); /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. When skipping over * a missed TX status report, use a status structure * filled with zeros to indicate that the frame was not * sent (frame_count 0) and not acknowledged */ if (unlikely(skip)) txstat = &fake; else txstat = status; frame_succeed = b43_fill_txstatus_report(dev, info, txstat); #ifdef CPTCFG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; else ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ ieee80211_tx_status(dev->wl->hw, meta->skb); /* skb will be freed by ieee80211_tx_status(). * Poison our pointer. */ meta->skb = B43_DMA_PTR_POISON; } else { /* No need to call free_descriptor_buffer here, as * this is only the txhdr, which is not allocated. */ if (unlikely(meta->skb)) { b43dbg(dev->wl, "TX status unexpected non-NULL skb " "at slot %d (first=%d) on ring %d\n", slot, firstused, ring->index); break; } } /* Everything unmapped and free'd. So it's not used anymore. */ ring->used_slots--; if (meta->is_last_fragment && !skip) { /* This is the last scatter-gather * fragment of the frame. We are done. */ break; } slot = next_slot(ring, slot); if (skip > 0) --skip; } if (ring->stopped) { B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); ring->stopped = false; } if (dev->wl->tx_queue_stopped[ring->queue_prio]) { dev->wl->tx_queue_stopped[ring->queue_prio] = 0; } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } } /* Add work to the queue. */ ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work); }
static int dma_tx_fragment(struct b43_dmaring *ring, struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info); u8 *header; int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; struct b43_dmadesc_meta *meta_hdr; u16 cookie; size_t hdrsize = b43_txhdr_size(ring->dev); /* Important note: If the number of used DMA slots per TX frame * is changed here, the TX_SLOTS_PER_FRAME definition at the top of * the file has to be updated, too! */ old_top_slot = ring->current_slot; old_used_slots = ring->used_slots; /* Get a slot for the header. */ slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta_hdr); memset(meta_hdr, 0, sizeof(*meta_hdr)); header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; return err; } meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, hdrsize, 1); if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; return -EIO; } ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, hdrsize, 1, 0, 0); /* Get a slot for the payload. */ slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); meta->skb = skb; meta->is_last_fragment = true; priv_info->bouncebuffer = NULL; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { priv_info->bouncebuffer = kmemdup(skb->data, skb->len, GFP_ATOMIC | GFP_DMA); if (!priv_info->bouncebuffer) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { kfree(priv_info->bouncebuffer); priv_info->bouncebuffer = NULL; ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO; goto out_unmap_hdr; } } ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(ring->dev, B43_SHM_SHARED, B43_SHM_SH_MCASTCOOKIE, cookie); } /* Now transfer the whole frame. */ wmb(); ops->poke_tx(ring, next_slot(ring, slot)); return 0; out_unmap_hdr: unmap_descbuffer(ring, meta_hdr->dmaaddr, hdrsize, 1); return err; }
int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned int hdrlen, total_len; int err = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast queue will be sent after the DTIM. */ q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it * for us on the last frame. */ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); if (unlikely(total_len > q->buffer_size)) { err = -ENOBUFS; b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); goto out; } if (unlikely(q->free_packet_slots == 0)) { err = -ENOBUFS; b43warn(dev->wl, "PIO: TX packet overflow.\n"); goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out; } /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ dev_kfree_skb_any(skb); err = 0; goto out; } if (unlikely(err)) { b43err(dev->wl, "PIO transmission failure\n"); goto out; } q->nr_tx_packets++; B43_WARN_ON(q->buffer_used > q->buffer_size); if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } out: return err; }
static int dma_tx_fragment(struct b43_dmaring *ring, struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info); u8 *header; int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; struct b43_dmadesc_meta *meta_hdr; u16 cookie; size_t hdrsize = b43_txhdr_size(ring->dev); old_top_slot = ring->current_slot; old_used_slots = ring->used_slots; slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta_hdr); memset(meta_hdr, 0, sizeof(*meta_hdr)); header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, skb, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; return err; } meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, hdrsize, 1); if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; return -EIO; } ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, hdrsize, 1, 0, 0); slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); meta->skb = skb; meta->is_last_fragment = true; priv_info->bouncebuffer = NULL; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { priv_info->bouncebuffer = kmemdup(skb->data, skb->len, GFP_ATOMIC | GFP_DMA); if (!priv_info->bouncebuffer) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { kfree(priv_info->bouncebuffer); priv_info->bouncebuffer = NULL; ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO; goto out_unmap_hdr; } } ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { b43_shm_write16(ring->dev, B43_SHM_SHARED, B43_SHM_SH_MCASTCOOKIE, cookie); } wmb(); ops->poke_tx(ring, next_slot(ring, slot)); return 0; out_unmap_hdr: unmap_descbuffer(ring, meta_hdr->dmaaddr, hdrsize, 1); return err; }
int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned int hdrlen, total_len; int err = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { q = dev->pio.tx_queue_mcast; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); if (unlikely(total_len > q->buffer_size)) { err = -ENOBUFS; b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); goto out; } if (unlikely(q->free_packet_slots == 0)) { err = -ENOBUFS; b43warn(dev->wl, "PIO: TX packet overflow.\n"); goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); if (total_len > (q->buffer_size - q->buffer_used)) { err = -EBUSY; ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = true; goto out; } q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { dev_kfree_skb_any(skb); err = 0; goto out; } if (unlikely(err)) { b43err(dev->wl, "PIO transmission failure\n"); goto out; } B43_WARN_ON(q->buffer_used > q->buffer_size); if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = true; } out: return err; }
void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status) { const struct b43_dma_ops *ops; struct b43_dmaring *ring; struct b43_dmadesc_meta *meta; int slot, firstused; bool frame_succeed; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return; B43_WARN_ON(!ring->tx); /* Sanity check: TX packets are processed in-order on one ring. * Check if the slot deduced from the cookie really is the first * used slot. */ firstused = ring->current_slot - ring->used_slots + 1; if (firstused < 0) firstused = ring->nr_slots + firstused; if (unlikely(slot != firstused)) { /* This possibly is a firmware bug and will result in * malfunction, memory leaks and/or stall of DMA functionality. */ b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " "Expected %d, but got %d\n", ring->index, firstused, slot); return; } ops = ring->ops; while (1) { B43_WARN_ON(slot < 0 || slot >= ring->nr_slots); /* get meta - ignore returned value */ ops->idx2desc(ring, slot, &meta); if (b43_dma_ptr_is_poisoned(meta->skb)) { b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) " "on ring %d\n", slot, firstused, ring->index); break; } if (meta->skb) { struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); kfree(priv_info->bouncebuffer); priv_info->bouncebuffer = NULL; } else { unmap_descbuffer(ring, meta->dmaaddr, b43_txhdr_size(dev), 1); } if (meta->is_last_fragment) { struct ieee80211_tx_info *info; if (unlikely(!meta->skb)) { /* This is a scatter-gather fragment of a frame, so * the skb pointer must not be NULL. */ b43dbg(dev->wl, "TX status unexpected NULL skb " "at slot %d (first=%d) on ring %d\n", slot, firstused, ring->index); break; } info = IEEE80211_SKB_CB(meta->skb); /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. */ frame_succeed = b43_fill_txstatus_report(dev, info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; else ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ ieee80211_tx_status(dev->wl->hw, meta->skb); /* skb will be freed by ieee80211_tx_status(). * Poison our pointer. */ meta->skb = B43_DMA_PTR_POISON; } else { /* No need to call free_descriptor_buffer here, as * this is only the txhdr, which is not allocated. */ if (unlikely(meta->skb)) { b43dbg(dev->wl, "TX status unexpected non-NULL skb " "at slot %d (first=%d) on ring %d\n", slot, firstused, ring->index); break; } } /* Everything unmapped and free'd. So it's not used anymore. */ ring->used_slots--; if (meta->is_last_fragment) { /* This is the last scatter-gather * fragment of the frame. We are done. */ break; } slot = next_slot(ring, slot); } if (ring->stopped) { B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); ring->stopped = 0; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } } }