staticinline void free_descriptor_buffer(struct b43legacy_dmaring *ring, struct b43legacy_dmadesc_meta *meta, int irq_context)
{ if (meta->skb) { if (irq_context)
dev_kfree_skb_irq(meta->skb); else
dev_kfree_skb(meta->skb);
meta->skb = NULL;
}
}
staticint alloc_ringmemory(struct b43legacy_dmaring *ring)
{ /* GFP flags must match the flags in free_ringmemory()! */
ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
B43legacy_DMA_RINGMEMSIZE,
&(ring->dmabase), GFP_KERNEL); if (!ring->descbase) return -ENOMEM;
/* Main initialization function. */ static struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, int controller_index, int for_tx, enum b43legacy_dmatype type)
{ struct b43legacy_dmaring *ring; int err; int nr_slots;
dma_addr_t dma_test;
ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) goto out;
ring->type = type;
ring->dev = dev;
nr_slots = B43legacy_RXRING_SLOTS; if (for_tx)
nr_slots = B43legacy_TXRING_SLOTS;
ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta),
GFP_KERNEL); if (!ring->meta) goto err_kfree_ring; if (for_tx) {
ring->txhdr_cache = kcalloc(nr_slots, sizeof(struct b43legacy_txhdr_fw3),
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, sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
int b43legacy_dma_init(struct b43legacy_wldev *dev)
{ struct b43legacy_dma *dma = &dev->dma; struct b43legacy_dmaring *ring; enum b43legacy_dmatype type = b43legacy_engine_type(dev); int err;
err = dma_set_mask_and_coherent(dev->dev->dma_dev, DMA_BIT_MASK(type)); if (err) { #ifdef CONFIG_B43LEGACY_PIO
b43legacywarn(dev->wl, "DMA for this device not supported. " "Falling back to PIO\n");
dev->__using_pio = true; return -EAGAIN; #else
b43legacyerr(dev->wl, "DMA for this device not supported and " "no PIO support compiled in\n"); return -EOPNOTSUPP; #endif
}
dma->translation = ssb_dma_translation(dev->dev);
/* Inspect a cookie and find out to which controller/slot it belongs. */ static struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
u16 cookie, int *slot)
{ struct b43legacy_dma *dma = &dev->dma; struct b43legacy_dmaring *ring = NULL;
switch (cookie & 0xF000) { case0xA000:
ring = dma->tx_ring0; break; case0xB000:
ring = dma->tx_ring1; break; case0xC000:
ring = dma->tx_ring2; break; case0xD000:
ring = dma->tx_ring3; break; case0xE000:
ring = dma->tx_ring4; break; case0xF000:
ring = dma->tx_ring5; break; default:
B43legacy_WARN_ON(1);
}
*slot = (cookie & 0x0FFF);
B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
staticinline int should_inject_overflow(struct b43legacy_dmaring *ring)
{ #ifdef CONFIG_B43LEGACY_DEBUG if (unlikely(b43legacy_debug(ring->dev,
B43legacy_DBG_DMAOVERFLOW))) { /* Check if we should inject another ringbuffer overflow
* to test handling of this situation in the stack. */ unsignedlong next_overflow;
int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb)
{ struct b43legacy_dmaring *ring; int err = 0;
ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
B43legacy_WARN_ON(!ring->tx);
if (unlikely(ring->stopped)) { /* We get here only because of a bug in mac80211. *Becauseofarace,onepacketmaybequeuedafter *thequeueisstopped,thuswegotcalledwhenweshouldn't.
* For now, just refuse the transmit. */ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
b43legacyerr(dev->wl, "Packet after queue stopped\n"); return -ENOSPC;
}
if (WARN_ON(free_slots(ring) < SLOTS_PER_PACKET)) { /* If we get here, we have a real error with the queue
* full, but queues not stopped. */
b43legacyerr(dev->wl, "DMA queue overflow\n"); return -ENOSPC;
}
/* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
* into the skb data or cb now. */
err = dma_tx_fragment(ring, &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); return0;
} if (unlikely(err)) {
b43legacyerr(dev->wl, "DMA tx mapping failure\n"); return err;
} if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) { /* This TX ring is full. */ unsignedint skb_mapping = skb_get_queue_mapping(skb);
ieee80211_stop_queue(dev->wl->hw, skb_mapping);
dev->wl->tx_queue_stopped[skb_mapping] = 1;
ring->stopped = true; if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
b43legacydbg(dev->wl, "Stopped TX ring %d\n",
ring->index);
} return err;
}
void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, conststruct b43legacy_txstatus *status)
{ struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_meta *meta; int retry_limit; int slot; int firstused;
ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return;
B43legacy_WARN_ON(!ring->tx);
/* Sanity check: TX packets are processed in-order on one ring. *Checkiftheslotdeducedfromthecookiereallyisthefirst
* 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,memoryleaksand/orstallofDMAfunctionality.
*/
b43legacydbg(dev->wl, "Out of order TX status report on DMA " "ring %d. Expected %d, but got %d\n",
ring->index, firstused, slot); return;
}
if (meta->is_last_fragment) { struct ieee80211_tx_info *info;
BUG_ON(!meta->skb);
info = IEEE80211_SKB_CB(meta->skb);
/* preserve the confiured retry limit before clearing the status *Thexmitfunctionhasoverwrittentherc'svaluewiththeactual
* retry limit done by the hardware */
retry_limit = info->status.rates[0].count;
ieee80211_tx_info_clear_status(info);
if (status->acked)
info->flags |= IEEE80211_TX_STAT_ACK;
/* Call back to inform the ieee80211 subsystem about the *statusofthetransmission. *Somefieldsoftxstatarealreadyfilledindma_tx().
*/
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
} else { /* No need to call free_descriptor_buffer here, as *thisisonlythetxhdr,whichisnotallocated.
*/
B43legacy_WARN_ON(meta->skb != NULL);
}
/* Everything unmapped and free'd. So it's not used anymore. */
ring->used_slots--;
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 (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
b43legacydbg(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);
}
if (ring->index == 3) { /* We received an xmit status. */ struct b43legacy_hwtxstatus *hw =
(struct b43legacy_hwtxstatus *)skb->data; int i = 0;
while (hw->cookie == 0) { if (i > 100) break;
i++;
udelay(2);
barrier();
}
b43legacy_handle_hwtxstatus(ring->dev, hw); /* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
return;
}
rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data;
len = le16_to_cpu(rxhdr->frame_len); if (len == 0) { int i = 0;
do {
udelay(2);
barrier();
len = le16_to_cpu(rxhdr->frame_len);
} while (len == 0 && i++ < 5); if (unlikely(len == 0)) { /* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize); goto drop;
}
} if (unlikely(len > ring->rx_buffersize)) { /* The data did not fit into one descriptor buffer *andissplitovermultiplebuffers. *Thisshouldneverhappen,aswetrytoallocatebuffers *bigenough.Sosimplyignorethispacket.
*/ int cnt = 0;
s32 tmp = len;
while (1) {
desc = op32_idx2desc(ring, *slot, &meta); /* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
*slot = next_slot(ring, *slot);
cnt++;
tmp -= ring->rx_buffersize; if (tmp <= 0) break;
}
b43legacyerr(ring->dev->wl, "DMA RX buffer too small " "(len: %u, buffer: %u, nr-dropped: %d)\n",
len, ring->rx_buffersize, cnt); goto drop;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
(vorverarbeitet am 2026-10-03)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.