1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2423e3ce3SKalle Valo /* 3423e3ce3SKalle Valo 4423e3ce3SKalle Valo Broadcom B43legacy wireless driver 5423e3ce3SKalle Valo 6423e3ce3SKalle Valo DMA ringbuffer and descriptor allocation/management 7423e3ce3SKalle Valo 8423e3ce3SKalle Valo Copyright (c) 2005, 2006 Michael Buesch <m@bues.ch> 9423e3ce3SKalle Valo 10423e3ce3SKalle Valo Some code in this file is derived from the b44.c driver 11423e3ce3SKalle Valo Copyright (C) 2002 David S. Miller 12423e3ce3SKalle Valo Copyright (C) Pekka Pietikainen 13423e3ce3SKalle Valo 14423e3ce3SKalle Valo 15423e3ce3SKalle Valo */ 16423e3ce3SKalle Valo 17423e3ce3SKalle Valo #include "b43legacy.h" 18423e3ce3SKalle Valo #include "dma.h" 19423e3ce3SKalle Valo #include "main.h" 20423e3ce3SKalle Valo #include "debugfs.h" 21423e3ce3SKalle Valo #include "xmit.h" 22423e3ce3SKalle Valo 23423e3ce3SKalle Valo #include <linux/dma-mapping.h> 24423e3ce3SKalle Valo #include <linux/pci.h> 25423e3ce3SKalle Valo #include <linux/delay.h> 26423e3ce3SKalle Valo #include <linux/skbuff.h> 27423e3ce3SKalle Valo #include <linux/slab.h> 28423e3ce3SKalle Valo #include <net/dst.h> 29423e3ce3SKalle Valo 30423e3ce3SKalle Valo /* 32bit DMA ops. */ 31423e3ce3SKalle Valo static 32423e3ce3SKalle Valo struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring, 33423e3ce3SKalle Valo int slot, 34423e3ce3SKalle Valo struct b43legacy_dmadesc_meta **meta) 35423e3ce3SKalle Valo { 36423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc; 37423e3ce3SKalle Valo 38423e3ce3SKalle Valo *meta = &(ring->meta[slot]); 39423e3ce3SKalle Valo desc = ring->descbase; 40423e3ce3SKalle Valo desc = &(desc[slot]); 41423e3ce3SKalle Valo 42423e3ce3SKalle Valo return desc; 43423e3ce3SKalle Valo } 44423e3ce3SKalle Valo 45423e3ce3SKalle Valo static void op32_fill_descriptor(struct b43legacy_dmaring *ring, 46423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc, 47423e3ce3SKalle Valo dma_addr_t dmaaddr, u16 bufsize, 48423e3ce3SKalle Valo int start, int end, int irq) 49423e3ce3SKalle Valo { 50423e3ce3SKalle Valo struct b43legacy_dmadesc32 *descbase = ring->descbase; 51423e3ce3SKalle Valo int slot; 52423e3ce3SKalle Valo u32 ctl; 53423e3ce3SKalle Valo u32 addr; 54423e3ce3SKalle Valo u32 addrext; 55423e3ce3SKalle Valo 56423e3ce3SKalle Valo slot = (int)(desc - descbase); 57423e3ce3SKalle Valo B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); 58423e3ce3SKalle Valo 59423e3ce3SKalle Valo addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); 60423e3ce3SKalle Valo addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK) 61423e3ce3SKalle Valo >> SSB_DMA_TRANSLATION_SHIFT; 62423e3ce3SKalle Valo addr |= ring->dev->dma.translation; 63423e3ce3SKalle Valo ctl = (bufsize - ring->frameoffset) 64423e3ce3SKalle Valo & B43legacy_DMA32_DCTL_BYTECNT; 65423e3ce3SKalle Valo if (slot == ring->nr_slots - 1) 66423e3ce3SKalle Valo ctl |= B43legacy_DMA32_DCTL_DTABLEEND; 67423e3ce3SKalle Valo if (start) 68423e3ce3SKalle Valo ctl |= B43legacy_DMA32_DCTL_FRAMESTART; 69423e3ce3SKalle Valo if (end) 70423e3ce3SKalle Valo ctl |= B43legacy_DMA32_DCTL_FRAMEEND; 71423e3ce3SKalle Valo if (irq) 72423e3ce3SKalle Valo ctl |= B43legacy_DMA32_DCTL_IRQ; 73423e3ce3SKalle Valo ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) 74423e3ce3SKalle Valo & B43legacy_DMA32_DCTL_ADDREXT_MASK; 75423e3ce3SKalle Valo 76423e3ce3SKalle Valo desc->control = cpu_to_le32(ctl); 77423e3ce3SKalle Valo desc->address = cpu_to_le32(addr); 78423e3ce3SKalle Valo } 79423e3ce3SKalle Valo 80423e3ce3SKalle Valo static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) 81423e3ce3SKalle Valo { 82423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX, 83423e3ce3SKalle Valo (u32)(slot * sizeof(struct b43legacy_dmadesc32))); 84423e3ce3SKalle Valo } 85423e3ce3SKalle Valo 86423e3ce3SKalle Valo static void op32_tx_suspend(struct b43legacy_dmaring *ring) 87423e3ce3SKalle Valo { 88423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, 89423e3ce3SKalle Valo b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) 90423e3ce3SKalle Valo | B43legacy_DMA32_TXSUSPEND); 91423e3ce3SKalle Valo } 92423e3ce3SKalle Valo 93423e3ce3SKalle Valo static void op32_tx_resume(struct b43legacy_dmaring *ring) 94423e3ce3SKalle Valo { 95423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, 96423e3ce3SKalle Valo b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) 97423e3ce3SKalle Valo & ~B43legacy_DMA32_TXSUSPEND); 98423e3ce3SKalle Valo } 99423e3ce3SKalle Valo 100423e3ce3SKalle Valo static int op32_get_current_rxslot(struct b43legacy_dmaring *ring) 101423e3ce3SKalle Valo { 102423e3ce3SKalle Valo u32 val; 103423e3ce3SKalle Valo 104423e3ce3SKalle Valo val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS); 105423e3ce3SKalle Valo val &= B43legacy_DMA32_RXDPTR; 106423e3ce3SKalle Valo 107423e3ce3SKalle Valo return (val / sizeof(struct b43legacy_dmadesc32)); 108423e3ce3SKalle Valo } 109423e3ce3SKalle Valo 110423e3ce3SKalle Valo static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, 111423e3ce3SKalle Valo int slot) 112423e3ce3SKalle Valo { 113423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 114423e3ce3SKalle Valo (u32)(slot * sizeof(struct b43legacy_dmadesc32))); 115423e3ce3SKalle Valo } 116423e3ce3SKalle Valo 117423e3ce3SKalle Valo static inline int free_slots(struct b43legacy_dmaring *ring) 118423e3ce3SKalle Valo { 119423e3ce3SKalle Valo return (ring->nr_slots - ring->used_slots); 120423e3ce3SKalle Valo } 121423e3ce3SKalle Valo 122423e3ce3SKalle Valo static inline int next_slot(struct b43legacy_dmaring *ring, int slot) 123423e3ce3SKalle Valo { 124423e3ce3SKalle Valo B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); 125423e3ce3SKalle Valo if (slot == ring->nr_slots - 1) 126423e3ce3SKalle Valo return 0; 127423e3ce3SKalle Valo return slot + 1; 128423e3ce3SKalle Valo } 129423e3ce3SKalle Valo 130423e3ce3SKalle Valo static inline int prev_slot(struct b43legacy_dmaring *ring, int slot) 131423e3ce3SKalle Valo { 132423e3ce3SKalle Valo B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); 133423e3ce3SKalle Valo if (slot == 0) 134423e3ce3SKalle Valo return ring->nr_slots - 1; 135423e3ce3SKalle Valo return slot - 1; 136423e3ce3SKalle Valo } 137423e3ce3SKalle Valo 138423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG 139423e3ce3SKalle Valo static void update_max_used_slots(struct b43legacy_dmaring *ring, 140423e3ce3SKalle Valo int current_used_slots) 141423e3ce3SKalle Valo { 142423e3ce3SKalle Valo if (current_used_slots <= ring->max_used_slots) 143423e3ce3SKalle Valo return; 144423e3ce3SKalle Valo ring->max_used_slots = current_used_slots; 145423e3ce3SKalle Valo if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE)) 146423e3ce3SKalle Valo b43legacydbg(ring->dev->wl, 147423e3ce3SKalle Valo "max_used_slots increased to %d on %s ring %d\n", 148423e3ce3SKalle Valo ring->max_used_slots, 149423e3ce3SKalle Valo ring->tx ? "TX" : "RX", 150423e3ce3SKalle Valo ring->index); 151423e3ce3SKalle Valo } 152423e3ce3SKalle Valo #else 153423e3ce3SKalle Valo static inline 154423e3ce3SKalle Valo void update_max_used_slots(struct b43legacy_dmaring *ring, 155423e3ce3SKalle Valo int current_used_slots) 156423e3ce3SKalle Valo { } 157423e3ce3SKalle Valo #endif /* DEBUG */ 158423e3ce3SKalle Valo 159423e3ce3SKalle Valo /* Request a slot for usage. */ 160423e3ce3SKalle Valo static inline 161423e3ce3SKalle Valo int request_slot(struct b43legacy_dmaring *ring) 162423e3ce3SKalle Valo { 163423e3ce3SKalle Valo int slot; 164423e3ce3SKalle Valo 165423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 166423e3ce3SKalle Valo B43legacy_WARN_ON(ring->stopped); 167423e3ce3SKalle Valo B43legacy_WARN_ON(free_slots(ring) == 0); 168423e3ce3SKalle Valo 169423e3ce3SKalle Valo slot = next_slot(ring, ring->current_slot); 170423e3ce3SKalle Valo ring->current_slot = slot; 171423e3ce3SKalle Valo ring->used_slots++; 172423e3ce3SKalle Valo 173423e3ce3SKalle Valo update_max_used_slots(ring, ring->used_slots); 174423e3ce3SKalle Valo 175423e3ce3SKalle Valo return slot; 176423e3ce3SKalle Valo } 177423e3ce3SKalle Valo 178423e3ce3SKalle Valo /* Mac80211-queue to b43legacy-ring mapping */ 179423e3ce3SKalle Valo static struct b43legacy_dmaring *priority_to_txring( 180423e3ce3SKalle Valo struct b43legacy_wldev *dev, 181423e3ce3SKalle Valo int queue_priority) 182423e3ce3SKalle Valo { 183423e3ce3SKalle Valo struct b43legacy_dmaring *ring; 184423e3ce3SKalle Valo 185423e3ce3SKalle Valo /*FIXME: For now we always run on TX-ring-1 */ 186423e3ce3SKalle Valo return dev->dma.tx_ring1; 187423e3ce3SKalle Valo 188423e3ce3SKalle Valo /* 0 = highest priority */ 189423e3ce3SKalle Valo switch (queue_priority) { 190423e3ce3SKalle Valo default: 191423e3ce3SKalle Valo B43legacy_WARN_ON(1); 192423e3ce3SKalle Valo /* fallthrough */ 193423e3ce3SKalle Valo case 0: 194423e3ce3SKalle Valo ring = dev->dma.tx_ring3; 195423e3ce3SKalle Valo break; 196423e3ce3SKalle Valo case 1: 197423e3ce3SKalle Valo ring = dev->dma.tx_ring2; 198423e3ce3SKalle Valo break; 199423e3ce3SKalle Valo case 2: 200423e3ce3SKalle Valo ring = dev->dma.tx_ring1; 201423e3ce3SKalle Valo break; 202423e3ce3SKalle Valo case 3: 203423e3ce3SKalle Valo ring = dev->dma.tx_ring0; 204423e3ce3SKalle Valo break; 205423e3ce3SKalle Valo case 4: 206423e3ce3SKalle Valo ring = dev->dma.tx_ring4; 207423e3ce3SKalle Valo break; 208423e3ce3SKalle Valo case 5: 209423e3ce3SKalle Valo ring = dev->dma.tx_ring5; 210423e3ce3SKalle Valo break; 211423e3ce3SKalle Valo } 212423e3ce3SKalle Valo 213423e3ce3SKalle Valo return ring; 214423e3ce3SKalle Valo } 215423e3ce3SKalle Valo 216423e3ce3SKalle Valo /* Bcm4301-ring to mac80211-queue mapping */ 217423e3ce3SKalle Valo static inline int txring_to_priority(struct b43legacy_dmaring *ring) 218423e3ce3SKalle Valo { 219423e3ce3SKalle Valo static const u8 idx_to_prio[] = 220423e3ce3SKalle Valo { 3, 2, 1, 0, 4, 5, }; 221423e3ce3SKalle Valo 222423e3ce3SKalle Valo /*FIXME: have only one queue, for now */ 223423e3ce3SKalle Valo return 0; 224423e3ce3SKalle Valo 225423e3ce3SKalle Valo return idx_to_prio[ring->index]; 226423e3ce3SKalle Valo } 227423e3ce3SKalle Valo 228423e3ce3SKalle Valo 229423e3ce3SKalle Valo static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, 230423e3ce3SKalle Valo int controller_idx) 231423e3ce3SKalle Valo { 232423e3ce3SKalle Valo static const u16 map32[] = { 233423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE0, 234423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE1, 235423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE2, 236423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE3, 237423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE4, 238423e3ce3SKalle Valo B43legacy_MMIO_DMA32_BASE5, 239423e3ce3SKalle Valo }; 240423e3ce3SKalle Valo 241423e3ce3SKalle Valo B43legacy_WARN_ON(!(controller_idx >= 0 && 242423e3ce3SKalle Valo controller_idx < ARRAY_SIZE(map32))); 243423e3ce3SKalle Valo return map32[controller_idx]; 244423e3ce3SKalle Valo } 245423e3ce3SKalle Valo 246423e3ce3SKalle Valo static inline 247423e3ce3SKalle Valo dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring, 248423e3ce3SKalle Valo unsigned char *buf, 249423e3ce3SKalle Valo size_t len, 250423e3ce3SKalle Valo int tx) 251423e3ce3SKalle Valo { 252423e3ce3SKalle Valo dma_addr_t dmaaddr; 253423e3ce3SKalle Valo 254423e3ce3SKalle Valo if (tx) 255423e3ce3SKalle Valo dmaaddr = dma_map_single(ring->dev->dev->dma_dev, 256423e3ce3SKalle Valo buf, len, 257423e3ce3SKalle Valo DMA_TO_DEVICE); 258423e3ce3SKalle Valo else 259423e3ce3SKalle Valo dmaaddr = dma_map_single(ring->dev->dev->dma_dev, 260423e3ce3SKalle Valo buf, len, 261423e3ce3SKalle Valo DMA_FROM_DEVICE); 262423e3ce3SKalle Valo 263423e3ce3SKalle Valo return dmaaddr; 264423e3ce3SKalle Valo } 265423e3ce3SKalle Valo 266423e3ce3SKalle Valo static inline 267423e3ce3SKalle Valo void unmap_descbuffer(struct b43legacy_dmaring *ring, 268423e3ce3SKalle Valo dma_addr_t addr, 269423e3ce3SKalle Valo size_t len, 270423e3ce3SKalle Valo int tx) 271423e3ce3SKalle Valo { 272423e3ce3SKalle Valo if (tx) 273423e3ce3SKalle Valo dma_unmap_single(ring->dev->dev->dma_dev, 274423e3ce3SKalle Valo addr, len, 275423e3ce3SKalle Valo DMA_TO_DEVICE); 276423e3ce3SKalle Valo else 277423e3ce3SKalle Valo dma_unmap_single(ring->dev->dev->dma_dev, 278423e3ce3SKalle Valo addr, len, 279423e3ce3SKalle Valo DMA_FROM_DEVICE); 280423e3ce3SKalle Valo } 281423e3ce3SKalle Valo 282423e3ce3SKalle Valo static inline 283423e3ce3SKalle Valo void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring, 284423e3ce3SKalle Valo dma_addr_t addr, 285423e3ce3SKalle Valo size_t len) 286423e3ce3SKalle Valo { 287423e3ce3SKalle Valo B43legacy_WARN_ON(ring->tx); 288423e3ce3SKalle Valo 289423e3ce3SKalle Valo dma_sync_single_for_cpu(ring->dev->dev->dma_dev, 290423e3ce3SKalle Valo addr, len, DMA_FROM_DEVICE); 291423e3ce3SKalle Valo } 292423e3ce3SKalle Valo 293423e3ce3SKalle Valo static inline 294423e3ce3SKalle Valo void sync_descbuffer_for_device(struct b43legacy_dmaring *ring, 295423e3ce3SKalle Valo dma_addr_t addr, 296423e3ce3SKalle Valo size_t len) 297423e3ce3SKalle Valo { 298423e3ce3SKalle Valo B43legacy_WARN_ON(ring->tx); 299423e3ce3SKalle Valo 300423e3ce3SKalle Valo dma_sync_single_for_device(ring->dev->dev->dma_dev, 301423e3ce3SKalle Valo addr, len, DMA_FROM_DEVICE); 302423e3ce3SKalle Valo } 303423e3ce3SKalle Valo 304423e3ce3SKalle Valo static inline 305423e3ce3SKalle Valo void free_descriptor_buffer(struct b43legacy_dmaring *ring, 306423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta, 307423e3ce3SKalle Valo int irq_context) 308423e3ce3SKalle Valo { 309423e3ce3SKalle Valo if (meta->skb) { 310423e3ce3SKalle Valo if (irq_context) 311423e3ce3SKalle Valo dev_kfree_skb_irq(meta->skb); 312423e3ce3SKalle Valo else 313423e3ce3SKalle Valo dev_kfree_skb(meta->skb); 314423e3ce3SKalle Valo meta->skb = NULL; 315423e3ce3SKalle Valo } 316423e3ce3SKalle Valo } 317423e3ce3SKalle Valo 318423e3ce3SKalle Valo static int alloc_ringmemory(struct b43legacy_dmaring *ring) 319423e3ce3SKalle Valo { 320423e3ce3SKalle Valo /* GFP flags must match the flags in free_ringmemory()! */ 321750afb08SLuis Chamberlain ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, 322423e3ce3SKalle Valo B43legacy_DMA_RINGMEMSIZE, 323423e3ce3SKalle Valo &(ring->dmabase), GFP_KERNEL); 324423e3ce3SKalle Valo if (!ring->descbase) 325423e3ce3SKalle Valo return -ENOMEM; 326423e3ce3SKalle Valo 327423e3ce3SKalle Valo return 0; 328423e3ce3SKalle Valo } 329423e3ce3SKalle Valo 330423e3ce3SKalle Valo static void free_ringmemory(struct b43legacy_dmaring *ring) 331423e3ce3SKalle Valo { 332423e3ce3SKalle Valo dma_free_coherent(ring->dev->dev->dma_dev, B43legacy_DMA_RINGMEMSIZE, 333423e3ce3SKalle Valo ring->descbase, ring->dmabase); 334423e3ce3SKalle Valo } 335423e3ce3SKalle Valo 336423e3ce3SKalle Valo /* Reset the RX DMA channel */ 337423e3ce3SKalle Valo static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, 338423e3ce3SKalle Valo u16 mmio_base, 339423e3ce3SKalle Valo enum b43legacy_dmatype type) 340423e3ce3SKalle Valo { 341423e3ce3SKalle Valo int i; 342423e3ce3SKalle Valo u32 value; 343423e3ce3SKalle Valo u16 offset; 344423e3ce3SKalle Valo 345423e3ce3SKalle Valo might_sleep(); 346423e3ce3SKalle Valo 347423e3ce3SKalle Valo offset = B43legacy_DMA32_RXCTL; 348423e3ce3SKalle Valo b43legacy_write32(dev, mmio_base + offset, 0); 349423e3ce3SKalle Valo for (i = 0; i < 10; i++) { 350423e3ce3SKalle Valo offset = B43legacy_DMA32_RXSTATUS; 351423e3ce3SKalle Valo value = b43legacy_read32(dev, mmio_base + offset); 352423e3ce3SKalle Valo value &= B43legacy_DMA32_RXSTATE; 353423e3ce3SKalle Valo if (value == B43legacy_DMA32_RXSTAT_DISABLED) { 354423e3ce3SKalle Valo i = -1; 355423e3ce3SKalle Valo break; 356423e3ce3SKalle Valo } 357423e3ce3SKalle Valo msleep(1); 358423e3ce3SKalle Valo } 359423e3ce3SKalle Valo if (i != -1) { 360423e3ce3SKalle Valo b43legacyerr(dev->wl, "DMA RX reset timed out\n"); 361423e3ce3SKalle Valo return -ENODEV; 362423e3ce3SKalle Valo } 363423e3ce3SKalle Valo 364423e3ce3SKalle Valo return 0; 365423e3ce3SKalle Valo } 366423e3ce3SKalle Valo 367423e3ce3SKalle Valo /* Reset the RX DMA channel */ 368423e3ce3SKalle Valo static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, 369423e3ce3SKalle Valo u16 mmio_base, 370423e3ce3SKalle Valo enum b43legacy_dmatype type) 371423e3ce3SKalle Valo { 372423e3ce3SKalle Valo int i; 373423e3ce3SKalle Valo u32 value; 374423e3ce3SKalle Valo u16 offset; 375423e3ce3SKalle Valo 376423e3ce3SKalle Valo might_sleep(); 377423e3ce3SKalle Valo 378423e3ce3SKalle Valo for (i = 0; i < 10; i++) { 379423e3ce3SKalle Valo offset = B43legacy_DMA32_TXSTATUS; 380423e3ce3SKalle Valo value = b43legacy_read32(dev, mmio_base + offset); 381423e3ce3SKalle Valo value &= B43legacy_DMA32_TXSTATE; 382423e3ce3SKalle Valo if (value == B43legacy_DMA32_TXSTAT_DISABLED || 383423e3ce3SKalle Valo value == B43legacy_DMA32_TXSTAT_IDLEWAIT || 384423e3ce3SKalle Valo value == B43legacy_DMA32_TXSTAT_STOPPED) 385423e3ce3SKalle Valo break; 386423e3ce3SKalle Valo msleep(1); 387423e3ce3SKalle Valo } 388423e3ce3SKalle Valo offset = B43legacy_DMA32_TXCTL; 389423e3ce3SKalle Valo b43legacy_write32(dev, mmio_base + offset, 0); 390423e3ce3SKalle Valo for (i = 0; i < 10; i++) { 391423e3ce3SKalle Valo offset = B43legacy_DMA32_TXSTATUS; 392423e3ce3SKalle Valo value = b43legacy_read32(dev, mmio_base + offset); 393423e3ce3SKalle Valo value &= B43legacy_DMA32_TXSTATE; 394423e3ce3SKalle Valo if (value == B43legacy_DMA32_TXSTAT_DISABLED) { 395423e3ce3SKalle Valo i = -1; 396423e3ce3SKalle Valo break; 397423e3ce3SKalle Valo } 398423e3ce3SKalle Valo msleep(1); 399423e3ce3SKalle Valo } 400423e3ce3SKalle Valo if (i != -1) { 401423e3ce3SKalle Valo b43legacyerr(dev->wl, "DMA TX reset timed out\n"); 402423e3ce3SKalle Valo return -ENODEV; 403423e3ce3SKalle Valo } 404423e3ce3SKalle Valo /* ensure the reset is completed. */ 405423e3ce3SKalle Valo msleep(1); 406423e3ce3SKalle Valo 407423e3ce3SKalle Valo return 0; 408423e3ce3SKalle Valo } 409423e3ce3SKalle Valo 410423e3ce3SKalle Valo /* Check if a DMA mapping address is invalid. */ 411423e3ce3SKalle Valo static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, 412423e3ce3SKalle Valo dma_addr_t addr, 413423e3ce3SKalle Valo size_t buffersize, 414423e3ce3SKalle Valo bool dma_to_device) 415423e3ce3SKalle Valo { 416423e3ce3SKalle Valo if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr))) 417423e3ce3SKalle Valo return true; 418423e3ce3SKalle Valo 419423e3ce3SKalle Valo switch (ring->type) { 420423e3ce3SKalle Valo case B43legacy_DMA_30BIT: 421423e3ce3SKalle Valo if ((u64)addr + buffersize > (1ULL << 30)) 422423e3ce3SKalle Valo goto address_error; 423423e3ce3SKalle Valo break; 424423e3ce3SKalle Valo case B43legacy_DMA_32BIT: 425423e3ce3SKalle Valo if ((u64)addr + buffersize > (1ULL << 32)) 426423e3ce3SKalle Valo goto address_error; 427423e3ce3SKalle Valo break; 428423e3ce3SKalle Valo } 429423e3ce3SKalle Valo 430423e3ce3SKalle Valo /* The address is OK. */ 431423e3ce3SKalle Valo return false; 432423e3ce3SKalle Valo 433423e3ce3SKalle Valo address_error: 434423e3ce3SKalle Valo /* We can't support this address. Unmap it again. */ 435423e3ce3SKalle Valo unmap_descbuffer(ring, addr, buffersize, dma_to_device); 436423e3ce3SKalle Valo 437423e3ce3SKalle Valo return true; 438423e3ce3SKalle Valo } 439423e3ce3SKalle Valo 440423e3ce3SKalle Valo static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, 441423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc, 442423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta, 443423e3ce3SKalle Valo gfp_t gfp_flags) 444423e3ce3SKalle Valo { 445423e3ce3SKalle Valo struct b43legacy_rxhdr_fw3 *rxhdr; 446423e3ce3SKalle Valo struct b43legacy_hwtxstatus *txstat; 447423e3ce3SKalle Valo dma_addr_t dmaaddr; 448423e3ce3SKalle Valo struct sk_buff *skb; 449423e3ce3SKalle Valo 450423e3ce3SKalle Valo B43legacy_WARN_ON(ring->tx); 451423e3ce3SKalle Valo 452423e3ce3SKalle Valo skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); 453423e3ce3SKalle Valo if (unlikely(!skb)) 454423e3ce3SKalle Valo return -ENOMEM; 455423e3ce3SKalle Valo dmaaddr = map_descbuffer(ring, skb->data, 456423e3ce3SKalle Valo ring->rx_buffersize, 0); 457423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { 458423e3ce3SKalle Valo /* ugh. try to realloc in zone_dma */ 459423e3ce3SKalle Valo gfp_flags |= GFP_DMA; 460423e3ce3SKalle Valo 461423e3ce3SKalle Valo dev_kfree_skb_any(skb); 462423e3ce3SKalle Valo 463423e3ce3SKalle Valo skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); 464423e3ce3SKalle Valo if (unlikely(!skb)) 465423e3ce3SKalle Valo return -ENOMEM; 466423e3ce3SKalle Valo dmaaddr = map_descbuffer(ring, skb->data, 467423e3ce3SKalle Valo ring->rx_buffersize, 0); 468423e3ce3SKalle Valo } 469423e3ce3SKalle Valo 470423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { 471423e3ce3SKalle Valo dev_kfree_skb_any(skb); 472423e3ce3SKalle Valo return -EIO; 473423e3ce3SKalle Valo } 474423e3ce3SKalle Valo 475423e3ce3SKalle Valo meta->skb = skb; 476423e3ce3SKalle Valo meta->dmaaddr = dmaaddr; 477423e3ce3SKalle Valo op32_fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); 478423e3ce3SKalle Valo 479423e3ce3SKalle Valo rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); 480423e3ce3SKalle Valo rxhdr->frame_len = 0; 481423e3ce3SKalle Valo txstat = (struct b43legacy_hwtxstatus *)(skb->data); 482423e3ce3SKalle Valo txstat->cookie = 0; 483423e3ce3SKalle Valo 484423e3ce3SKalle Valo return 0; 485423e3ce3SKalle Valo } 486423e3ce3SKalle Valo 487423e3ce3SKalle Valo /* Allocate the initial descbuffers. 488423e3ce3SKalle Valo * This is used for an RX ring only. 489423e3ce3SKalle Valo */ 490423e3ce3SKalle Valo static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring) 491423e3ce3SKalle Valo { 492423e3ce3SKalle Valo int i; 493423e3ce3SKalle Valo int err = -ENOMEM; 494423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc; 495423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta; 496423e3ce3SKalle Valo 497423e3ce3SKalle Valo for (i = 0; i < ring->nr_slots; i++) { 498423e3ce3SKalle Valo desc = op32_idx2desc(ring, i, &meta); 499423e3ce3SKalle Valo 500423e3ce3SKalle Valo err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); 501423e3ce3SKalle Valo if (err) { 502423e3ce3SKalle Valo b43legacyerr(ring->dev->wl, 503423e3ce3SKalle Valo "Failed to allocate initial descbuffers\n"); 504423e3ce3SKalle Valo goto err_unwind; 505423e3ce3SKalle Valo } 506423e3ce3SKalle Valo } 507423e3ce3SKalle Valo mb(); /* all descbuffer setup before next line */ 508423e3ce3SKalle Valo ring->used_slots = ring->nr_slots; 509423e3ce3SKalle Valo err = 0; 510423e3ce3SKalle Valo out: 511423e3ce3SKalle Valo return err; 512423e3ce3SKalle Valo 513423e3ce3SKalle Valo err_unwind: 514423e3ce3SKalle Valo for (i--; i >= 0; i--) { 515423e3ce3SKalle Valo desc = op32_idx2desc(ring, i, &meta); 516423e3ce3SKalle Valo 517423e3ce3SKalle Valo unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); 518423e3ce3SKalle Valo dev_kfree_skb(meta->skb); 519423e3ce3SKalle Valo } 520423e3ce3SKalle Valo goto out; 521423e3ce3SKalle Valo } 522423e3ce3SKalle Valo 523423e3ce3SKalle Valo /* Do initial setup of the DMA controller. 524423e3ce3SKalle Valo * Reset the controller, write the ring busaddress 525423e3ce3SKalle Valo * and switch the "enable" bit on. 526423e3ce3SKalle Valo */ 527423e3ce3SKalle Valo static int dmacontroller_setup(struct b43legacy_dmaring *ring) 528423e3ce3SKalle Valo { 529423e3ce3SKalle Valo int err = 0; 530423e3ce3SKalle Valo u32 value; 531423e3ce3SKalle Valo u32 addrext; 532423e3ce3SKalle Valo u32 trans = ring->dev->dma.translation; 533423e3ce3SKalle Valo u32 ringbase = (u32)(ring->dmabase); 534423e3ce3SKalle Valo 535423e3ce3SKalle Valo if (ring->tx) { 536423e3ce3SKalle Valo addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) 537423e3ce3SKalle Valo >> SSB_DMA_TRANSLATION_SHIFT; 538423e3ce3SKalle Valo value = B43legacy_DMA32_TXENABLE; 539423e3ce3SKalle Valo value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) 540423e3ce3SKalle Valo & B43legacy_DMA32_TXADDREXT_MASK; 541423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, value); 542423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 543423e3ce3SKalle Valo (ringbase & ~SSB_DMA_TRANSLATION_MASK) 544423e3ce3SKalle Valo | trans); 545423e3ce3SKalle Valo } else { 546423e3ce3SKalle Valo err = alloc_initial_descbuffers(ring); 547423e3ce3SKalle Valo if (err) 548423e3ce3SKalle Valo goto out; 549423e3ce3SKalle Valo 550423e3ce3SKalle Valo addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) 551423e3ce3SKalle Valo >> SSB_DMA_TRANSLATION_SHIFT; 552423e3ce3SKalle Valo value = (ring->frameoffset << 553423e3ce3SKalle Valo B43legacy_DMA32_RXFROFF_SHIFT); 554423e3ce3SKalle Valo value |= B43legacy_DMA32_RXENABLE; 555423e3ce3SKalle Valo value |= (addrext << B43legacy_DMA32_RXADDREXT_SHIFT) 556423e3ce3SKalle Valo & B43legacy_DMA32_RXADDREXT_MASK; 557423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, value); 558423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 559423e3ce3SKalle Valo (ringbase & ~SSB_DMA_TRANSLATION_MASK) 560423e3ce3SKalle Valo | trans); 561423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 200); 562423e3ce3SKalle Valo } 563423e3ce3SKalle Valo 564423e3ce3SKalle Valo out: 565423e3ce3SKalle Valo return err; 566423e3ce3SKalle Valo } 567423e3ce3SKalle Valo 568423e3ce3SKalle Valo /* Shutdown the DMA controller. */ 569423e3ce3SKalle Valo static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) 570423e3ce3SKalle Valo { 571423e3ce3SKalle Valo if (ring->tx) { 572423e3ce3SKalle Valo b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, 573423e3ce3SKalle Valo ring->type); 574423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); 575423e3ce3SKalle Valo } else { 576423e3ce3SKalle Valo b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, 577423e3ce3SKalle Valo ring->type); 578423e3ce3SKalle Valo b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); 579423e3ce3SKalle Valo } 580423e3ce3SKalle Valo } 581423e3ce3SKalle Valo 582423e3ce3SKalle Valo static void free_all_descbuffers(struct b43legacy_dmaring *ring) 583423e3ce3SKalle Valo { 584423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta; 585423e3ce3SKalle Valo int i; 586423e3ce3SKalle Valo 587423e3ce3SKalle Valo if (!ring->used_slots) 588423e3ce3SKalle Valo return; 589423e3ce3SKalle Valo for (i = 0; i < ring->nr_slots; i++) { 590423e3ce3SKalle Valo op32_idx2desc(ring, i, &meta); 591423e3ce3SKalle Valo 592423e3ce3SKalle Valo if (!meta->skb) { 593423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 594423e3ce3SKalle Valo continue; 595423e3ce3SKalle Valo } 596423e3ce3SKalle Valo if (ring->tx) 597423e3ce3SKalle Valo unmap_descbuffer(ring, meta->dmaaddr, 598423e3ce3SKalle Valo meta->skb->len, 1); 599423e3ce3SKalle Valo else 600423e3ce3SKalle Valo unmap_descbuffer(ring, meta->dmaaddr, 601423e3ce3SKalle Valo ring->rx_buffersize, 0); 602423e3ce3SKalle Valo free_descriptor_buffer(ring, meta, 0); 603423e3ce3SKalle Valo } 604423e3ce3SKalle Valo } 605423e3ce3SKalle Valo 606*80372782SChristoph Hellwig static enum b43legacy_dmatype b43legacy_engine_type(struct b43legacy_wldev *dev) 607423e3ce3SKalle Valo { 608423e3ce3SKalle Valo u32 tmp; 609423e3ce3SKalle Valo u16 mmio_base; 610423e3ce3SKalle Valo 611423e3ce3SKalle Valo mmio_base = b43legacy_dmacontroller_base(0, 0); 612423e3ce3SKalle Valo b43legacy_write32(dev, 613423e3ce3SKalle Valo mmio_base + B43legacy_DMA32_TXCTL, 614423e3ce3SKalle Valo B43legacy_DMA32_TXADDREXT_MASK); 615423e3ce3SKalle Valo tmp = b43legacy_read32(dev, mmio_base + 616423e3ce3SKalle Valo B43legacy_DMA32_TXCTL); 617423e3ce3SKalle Valo if (tmp & B43legacy_DMA32_TXADDREXT_MASK) 618423e3ce3SKalle Valo return B43legacy_DMA_32BIT; 619423e3ce3SKalle Valo return B43legacy_DMA_30BIT; 620423e3ce3SKalle Valo } 621423e3ce3SKalle Valo 622423e3ce3SKalle Valo /* Main initialization function. */ 623423e3ce3SKalle Valo static 624423e3ce3SKalle Valo struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, 625423e3ce3SKalle Valo int controller_index, 626423e3ce3SKalle Valo int for_tx, 627423e3ce3SKalle Valo enum b43legacy_dmatype type) 628423e3ce3SKalle Valo { 629423e3ce3SKalle Valo struct b43legacy_dmaring *ring; 630423e3ce3SKalle Valo int err; 631423e3ce3SKalle Valo int nr_slots; 632423e3ce3SKalle Valo dma_addr_t dma_test; 633423e3ce3SKalle Valo 634423e3ce3SKalle Valo ring = kzalloc(sizeof(*ring), GFP_KERNEL); 635423e3ce3SKalle Valo if (!ring) 636423e3ce3SKalle Valo goto out; 637423e3ce3SKalle Valo ring->type = type; 638423e3ce3SKalle Valo ring->dev = dev; 639423e3ce3SKalle Valo 640423e3ce3SKalle Valo nr_slots = B43legacy_RXRING_SLOTS; 641423e3ce3SKalle Valo if (for_tx) 642423e3ce3SKalle Valo nr_slots = B43legacy_TXRING_SLOTS; 643423e3ce3SKalle Valo 644423e3ce3SKalle Valo ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta), 645423e3ce3SKalle Valo GFP_KERNEL); 646423e3ce3SKalle Valo if (!ring->meta) 647423e3ce3SKalle Valo goto err_kfree_ring; 648423e3ce3SKalle Valo if (for_tx) { 649423e3ce3SKalle Valo ring->txhdr_cache = kcalloc(nr_slots, 650423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 651423e3ce3SKalle Valo GFP_KERNEL); 652423e3ce3SKalle Valo if (!ring->txhdr_cache) 653423e3ce3SKalle Valo goto err_kfree_meta; 654423e3ce3SKalle Valo 655423e3ce3SKalle Valo /* test for ability to dma to txhdr_cache */ 656423e3ce3SKalle Valo dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache, 657423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 658423e3ce3SKalle Valo DMA_TO_DEVICE); 659423e3ce3SKalle Valo 660423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, dma_test, 661423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1)) { 662423e3ce3SKalle Valo /* ugh realloc */ 663423e3ce3SKalle Valo kfree(ring->txhdr_cache); 664423e3ce3SKalle Valo ring->txhdr_cache = kcalloc(nr_slots, 665423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 666423e3ce3SKalle Valo GFP_KERNEL | GFP_DMA); 667423e3ce3SKalle Valo if (!ring->txhdr_cache) 668423e3ce3SKalle Valo goto err_kfree_meta; 669423e3ce3SKalle Valo 670423e3ce3SKalle Valo dma_test = dma_map_single(dev->dev->dma_dev, 671423e3ce3SKalle Valo ring->txhdr_cache, 672423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 673423e3ce3SKalle Valo DMA_TO_DEVICE); 674423e3ce3SKalle Valo 675423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, dma_test, 676423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1)) 677423e3ce3SKalle Valo goto err_kfree_txhdr_cache; 678423e3ce3SKalle Valo } 679423e3ce3SKalle Valo 680423e3ce3SKalle Valo dma_unmap_single(dev->dev->dma_dev, dma_test, 681423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 682423e3ce3SKalle Valo DMA_TO_DEVICE); 683423e3ce3SKalle Valo } 684423e3ce3SKalle Valo 685423e3ce3SKalle Valo ring->nr_slots = nr_slots; 686423e3ce3SKalle Valo ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); 687423e3ce3SKalle Valo ring->index = controller_index; 688423e3ce3SKalle Valo if (for_tx) { 689423e3ce3SKalle Valo ring->tx = true; 690423e3ce3SKalle Valo ring->current_slot = -1; 691423e3ce3SKalle Valo } else { 692423e3ce3SKalle Valo if (ring->index == 0) { 693423e3ce3SKalle Valo ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE; 694423e3ce3SKalle Valo ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET; 695423e3ce3SKalle Valo } else if (ring->index == 3) { 696423e3ce3SKalle Valo ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE; 697423e3ce3SKalle Valo ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET; 698423e3ce3SKalle Valo } else 699423e3ce3SKalle Valo B43legacy_WARN_ON(1); 700423e3ce3SKalle Valo } 701423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG 702423e3ce3SKalle Valo ring->last_injected_overflow = jiffies; 703423e3ce3SKalle Valo #endif 704423e3ce3SKalle Valo 705423e3ce3SKalle Valo err = alloc_ringmemory(ring); 706423e3ce3SKalle Valo if (err) 707423e3ce3SKalle Valo goto err_kfree_txhdr_cache; 708423e3ce3SKalle Valo err = dmacontroller_setup(ring); 709423e3ce3SKalle Valo if (err) 710423e3ce3SKalle Valo goto err_free_ringmemory; 711423e3ce3SKalle Valo 712423e3ce3SKalle Valo out: 713423e3ce3SKalle Valo return ring; 714423e3ce3SKalle Valo 715423e3ce3SKalle Valo err_free_ringmemory: 716423e3ce3SKalle Valo free_ringmemory(ring); 717423e3ce3SKalle Valo err_kfree_txhdr_cache: 718423e3ce3SKalle Valo kfree(ring->txhdr_cache); 719423e3ce3SKalle Valo err_kfree_meta: 720423e3ce3SKalle Valo kfree(ring->meta); 721423e3ce3SKalle Valo err_kfree_ring: 722423e3ce3SKalle Valo kfree(ring); 723423e3ce3SKalle Valo ring = NULL; 724423e3ce3SKalle Valo goto out; 725423e3ce3SKalle Valo } 726423e3ce3SKalle Valo 727423e3ce3SKalle Valo /* Main cleanup function. */ 728423e3ce3SKalle Valo static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring) 729423e3ce3SKalle Valo { 730423e3ce3SKalle Valo if (!ring) 731423e3ce3SKalle Valo return; 732423e3ce3SKalle Valo 733423e3ce3SKalle Valo b43legacydbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots:" 734423e3ce3SKalle Valo " %d/%d\n", (unsigned int)(ring->type), ring->mmio_base, 735423e3ce3SKalle Valo (ring->tx) ? "TX" : "RX", ring->max_used_slots, 736423e3ce3SKalle Valo ring->nr_slots); 737423e3ce3SKalle Valo /* Device IRQs are disabled prior entering this function, 738423e3ce3SKalle Valo * so no need to take care of concurrency with rx handler stuff. 739423e3ce3SKalle Valo */ 740423e3ce3SKalle Valo dmacontroller_cleanup(ring); 741423e3ce3SKalle Valo free_all_descbuffers(ring); 742423e3ce3SKalle Valo free_ringmemory(ring); 743423e3ce3SKalle Valo 744423e3ce3SKalle Valo kfree(ring->txhdr_cache); 745423e3ce3SKalle Valo kfree(ring->meta); 746423e3ce3SKalle Valo kfree(ring); 747423e3ce3SKalle Valo } 748423e3ce3SKalle Valo 749423e3ce3SKalle Valo void b43legacy_dma_free(struct b43legacy_wldev *dev) 750423e3ce3SKalle Valo { 751423e3ce3SKalle Valo struct b43legacy_dma *dma; 752423e3ce3SKalle Valo 753423e3ce3SKalle Valo if (b43legacy_using_pio(dev)) 754423e3ce3SKalle Valo return; 755423e3ce3SKalle Valo dma = &dev->dma; 756423e3ce3SKalle Valo 757423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->rx_ring3); 758423e3ce3SKalle Valo dma->rx_ring3 = NULL; 759423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->rx_ring0); 760423e3ce3SKalle Valo dma->rx_ring0 = NULL; 761423e3ce3SKalle Valo 762423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring5); 763423e3ce3SKalle Valo dma->tx_ring5 = NULL; 764423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring4); 765423e3ce3SKalle Valo dma->tx_ring4 = NULL; 766423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring3); 767423e3ce3SKalle Valo dma->tx_ring3 = NULL; 768423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring2); 769423e3ce3SKalle Valo dma->tx_ring2 = NULL; 770423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring1); 771423e3ce3SKalle Valo dma->tx_ring1 = NULL; 772423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring0); 773423e3ce3SKalle Valo dma->tx_ring0 = NULL; 774423e3ce3SKalle Valo } 775423e3ce3SKalle Valo 776423e3ce3SKalle Valo int b43legacy_dma_init(struct b43legacy_wldev *dev) 777423e3ce3SKalle Valo { 778423e3ce3SKalle Valo struct b43legacy_dma *dma = &dev->dma; 779423e3ce3SKalle Valo struct b43legacy_dmaring *ring; 780*80372782SChristoph Hellwig enum b43legacy_dmatype type = b43legacy_engine_type(dev); 781423e3ce3SKalle Valo int err; 782423e3ce3SKalle Valo 783*80372782SChristoph Hellwig err = dma_set_mask_and_coherent(dev->dev->dma_dev, DMA_BIT_MASK(type)); 784423e3ce3SKalle Valo if (err) { 785423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_PIO 786423e3ce3SKalle Valo b43legacywarn(dev->wl, "DMA for this device not supported. " 787423e3ce3SKalle Valo "Falling back to PIO\n"); 788423e3ce3SKalle Valo dev->__using_pio = true; 789423e3ce3SKalle Valo return -EAGAIN; 790423e3ce3SKalle Valo #else 791423e3ce3SKalle Valo b43legacyerr(dev->wl, "DMA for this device not supported and " 792423e3ce3SKalle Valo "no PIO support compiled in\n"); 793423e3ce3SKalle Valo return -EOPNOTSUPP; 794423e3ce3SKalle Valo #endif 795423e3ce3SKalle Valo } 796423e3ce3SKalle Valo dma->translation = ssb_dma_translation(dev->dev); 797423e3ce3SKalle Valo 798423e3ce3SKalle Valo err = -ENOMEM; 799423e3ce3SKalle Valo /* setup TX DMA channels. */ 800423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 0, 1, type); 801423e3ce3SKalle Valo if (!ring) 802423e3ce3SKalle Valo goto out; 803423e3ce3SKalle Valo dma->tx_ring0 = ring; 804423e3ce3SKalle Valo 805423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 1, 1, type); 806423e3ce3SKalle Valo if (!ring) 807423e3ce3SKalle Valo goto err_destroy_tx0; 808423e3ce3SKalle Valo dma->tx_ring1 = ring; 809423e3ce3SKalle Valo 810423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 2, 1, type); 811423e3ce3SKalle Valo if (!ring) 812423e3ce3SKalle Valo goto err_destroy_tx1; 813423e3ce3SKalle Valo dma->tx_ring2 = ring; 814423e3ce3SKalle Valo 815423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 3, 1, type); 816423e3ce3SKalle Valo if (!ring) 817423e3ce3SKalle Valo goto err_destroy_tx2; 818423e3ce3SKalle Valo dma->tx_ring3 = ring; 819423e3ce3SKalle Valo 820423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 4, 1, type); 821423e3ce3SKalle Valo if (!ring) 822423e3ce3SKalle Valo goto err_destroy_tx3; 823423e3ce3SKalle Valo dma->tx_ring4 = ring; 824423e3ce3SKalle Valo 825423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 5, 1, type); 826423e3ce3SKalle Valo if (!ring) 827423e3ce3SKalle Valo goto err_destroy_tx4; 828423e3ce3SKalle Valo dma->tx_ring5 = ring; 829423e3ce3SKalle Valo 830423e3ce3SKalle Valo /* setup RX DMA channels. */ 831423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 0, 0, type); 832423e3ce3SKalle Valo if (!ring) 833423e3ce3SKalle Valo goto err_destroy_tx5; 834423e3ce3SKalle Valo dma->rx_ring0 = ring; 835423e3ce3SKalle Valo 836423e3ce3SKalle Valo if (dev->dev->id.revision < 5) { 837423e3ce3SKalle Valo ring = b43legacy_setup_dmaring(dev, 3, 0, type); 838423e3ce3SKalle Valo if (!ring) 839423e3ce3SKalle Valo goto err_destroy_rx0; 840423e3ce3SKalle Valo dma->rx_ring3 = ring; 841423e3ce3SKalle Valo } 842423e3ce3SKalle Valo 843423e3ce3SKalle Valo b43legacydbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type); 844423e3ce3SKalle Valo err = 0; 845423e3ce3SKalle Valo out: 846423e3ce3SKalle Valo return err; 847423e3ce3SKalle Valo 848423e3ce3SKalle Valo err_destroy_rx0: 849423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->rx_ring0); 850423e3ce3SKalle Valo dma->rx_ring0 = NULL; 851423e3ce3SKalle Valo err_destroy_tx5: 852423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring5); 853423e3ce3SKalle Valo dma->tx_ring5 = NULL; 854423e3ce3SKalle Valo err_destroy_tx4: 855423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring4); 856423e3ce3SKalle Valo dma->tx_ring4 = NULL; 857423e3ce3SKalle Valo err_destroy_tx3: 858423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring3); 859423e3ce3SKalle Valo dma->tx_ring3 = NULL; 860423e3ce3SKalle Valo err_destroy_tx2: 861423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring2); 862423e3ce3SKalle Valo dma->tx_ring2 = NULL; 863423e3ce3SKalle Valo err_destroy_tx1: 864423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring1); 865423e3ce3SKalle Valo dma->tx_ring1 = NULL; 866423e3ce3SKalle Valo err_destroy_tx0: 867423e3ce3SKalle Valo b43legacy_destroy_dmaring(dma->tx_ring0); 868423e3ce3SKalle Valo dma->tx_ring0 = NULL; 869423e3ce3SKalle Valo goto out; 870423e3ce3SKalle Valo } 871423e3ce3SKalle Valo 872423e3ce3SKalle Valo /* Generate a cookie for the TX header. */ 873423e3ce3SKalle Valo static u16 generate_cookie(struct b43legacy_dmaring *ring, 874423e3ce3SKalle Valo int slot) 875423e3ce3SKalle Valo { 876423e3ce3SKalle Valo u16 cookie = 0x1000; 877423e3ce3SKalle Valo 878423e3ce3SKalle Valo /* Use the upper 4 bits of the cookie as 879423e3ce3SKalle Valo * DMA controller ID and store the slot number 880423e3ce3SKalle Valo * in the lower 12 bits. 881423e3ce3SKalle Valo * Note that the cookie must never be 0, as this 882423e3ce3SKalle Valo * is a special value used in RX path. 883423e3ce3SKalle Valo */ 884423e3ce3SKalle Valo switch (ring->index) { 885423e3ce3SKalle Valo case 0: 886423e3ce3SKalle Valo cookie = 0xA000; 887423e3ce3SKalle Valo break; 888423e3ce3SKalle Valo case 1: 889423e3ce3SKalle Valo cookie = 0xB000; 890423e3ce3SKalle Valo break; 891423e3ce3SKalle Valo case 2: 892423e3ce3SKalle Valo cookie = 0xC000; 893423e3ce3SKalle Valo break; 894423e3ce3SKalle Valo case 3: 895423e3ce3SKalle Valo cookie = 0xD000; 896423e3ce3SKalle Valo break; 897423e3ce3SKalle Valo case 4: 898423e3ce3SKalle Valo cookie = 0xE000; 899423e3ce3SKalle Valo break; 900423e3ce3SKalle Valo case 5: 901423e3ce3SKalle Valo cookie = 0xF000; 902423e3ce3SKalle Valo break; 903423e3ce3SKalle Valo } 904423e3ce3SKalle Valo B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000)); 905423e3ce3SKalle Valo cookie |= (u16)slot; 906423e3ce3SKalle Valo 907423e3ce3SKalle Valo return cookie; 908423e3ce3SKalle Valo } 909423e3ce3SKalle Valo 910423e3ce3SKalle Valo /* Inspect a cookie and find out to which controller/slot it belongs. */ 911423e3ce3SKalle Valo static 912423e3ce3SKalle Valo struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, 913423e3ce3SKalle Valo u16 cookie, int *slot) 914423e3ce3SKalle Valo { 915423e3ce3SKalle Valo struct b43legacy_dma *dma = &dev->dma; 916423e3ce3SKalle Valo struct b43legacy_dmaring *ring = NULL; 917423e3ce3SKalle Valo 918423e3ce3SKalle Valo switch (cookie & 0xF000) { 919423e3ce3SKalle Valo case 0xA000: 920423e3ce3SKalle Valo ring = dma->tx_ring0; 921423e3ce3SKalle Valo break; 922423e3ce3SKalle Valo case 0xB000: 923423e3ce3SKalle Valo ring = dma->tx_ring1; 924423e3ce3SKalle Valo break; 925423e3ce3SKalle Valo case 0xC000: 926423e3ce3SKalle Valo ring = dma->tx_ring2; 927423e3ce3SKalle Valo break; 928423e3ce3SKalle Valo case 0xD000: 929423e3ce3SKalle Valo ring = dma->tx_ring3; 930423e3ce3SKalle Valo break; 931423e3ce3SKalle Valo case 0xE000: 932423e3ce3SKalle Valo ring = dma->tx_ring4; 933423e3ce3SKalle Valo break; 934423e3ce3SKalle Valo case 0xF000: 935423e3ce3SKalle Valo ring = dma->tx_ring5; 936423e3ce3SKalle Valo break; 937423e3ce3SKalle Valo default: 938423e3ce3SKalle Valo B43legacy_WARN_ON(1); 939423e3ce3SKalle Valo } 940423e3ce3SKalle Valo *slot = (cookie & 0x0FFF); 941423e3ce3SKalle Valo B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); 942423e3ce3SKalle Valo 943423e3ce3SKalle Valo return ring; 944423e3ce3SKalle Valo } 945423e3ce3SKalle Valo 946423e3ce3SKalle Valo static int dma_tx_fragment(struct b43legacy_dmaring *ring, 947423e3ce3SKalle Valo struct sk_buff **in_skb) 948423e3ce3SKalle Valo { 949423e3ce3SKalle Valo struct sk_buff *skb = *in_skb; 950423e3ce3SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 951423e3ce3SKalle Valo u8 *header; 952423e3ce3SKalle Valo int slot, old_top_slot, old_used_slots; 953423e3ce3SKalle Valo int err; 954423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc; 955423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta; 956423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta_hdr; 957423e3ce3SKalle Valo struct sk_buff *bounce_skb; 958423e3ce3SKalle Valo 959423e3ce3SKalle Valo #define SLOTS_PER_PACKET 2 960423e3ce3SKalle Valo B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); 961423e3ce3SKalle Valo 962423e3ce3SKalle Valo old_top_slot = ring->current_slot; 963423e3ce3SKalle Valo old_used_slots = ring->used_slots; 964423e3ce3SKalle Valo 965423e3ce3SKalle Valo /* Get a slot for the header. */ 966423e3ce3SKalle Valo slot = request_slot(ring); 967423e3ce3SKalle Valo desc = op32_idx2desc(ring, slot, &meta_hdr); 968423e3ce3SKalle Valo memset(meta_hdr, 0, sizeof(*meta_hdr)); 969423e3ce3SKalle Valo 970423e3ce3SKalle Valo header = &(ring->txhdr_cache[slot * sizeof( 971423e3ce3SKalle Valo struct b43legacy_txhdr_fw3)]); 972423e3ce3SKalle Valo err = b43legacy_generate_txhdr(ring->dev, header, 973423e3ce3SKalle Valo skb->data, skb->len, info, 974423e3ce3SKalle Valo generate_cookie(ring, slot)); 975423e3ce3SKalle Valo if (unlikely(err)) { 976423e3ce3SKalle Valo ring->current_slot = old_top_slot; 977423e3ce3SKalle Valo ring->used_slots = old_used_slots; 978423e3ce3SKalle Valo return err; 979423e3ce3SKalle Valo } 980423e3ce3SKalle Valo 981423e3ce3SKalle Valo meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, 982423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1); 983423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, meta_hdr->dmaaddr, 984423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1)) { 985423e3ce3SKalle Valo ring->current_slot = old_top_slot; 986423e3ce3SKalle Valo ring->used_slots = old_used_slots; 987423e3ce3SKalle Valo return -EIO; 988423e3ce3SKalle Valo } 989423e3ce3SKalle Valo op32_fill_descriptor(ring, desc, meta_hdr->dmaaddr, 990423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); 991423e3ce3SKalle Valo 992423e3ce3SKalle Valo /* Get a slot for the payload. */ 993423e3ce3SKalle Valo slot = request_slot(ring); 994423e3ce3SKalle Valo desc = op32_idx2desc(ring, slot, &meta); 995423e3ce3SKalle Valo memset(meta, 0, sizeof(*meta)); 996423e3ce3SKalle Valo 997423e3ce3SKalle Valo meta->skb = skb; 998423e3ce3SKalle Valo meta->is_last_fragment = true; 999423e3ce3SKalle Valo 1000423e3ce3SKalle Valo meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); 1001423e3ce3SKalle Valo /* create a bounce buffer in zone_dma on mapping failure. */ 1002423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { 10036e1d8d14SJia-Ju Bai bounce_skb = alloc_skb(skb->len, GFP_KERNEL | GFP_DMA); 1004423e3ce3SKalle Valo if (!bounce_skb) { 1005423e3ce3SKalle Valo ring->current_slot = old_top_slot; 1006423e3ce3SKalle Valo ring->used_slots = old_used_slots; 1007423e3ce3SKalle Valo err = -ENOMEM; 1008423e3ce3SKalle Valo goto out_unmap_hdr; 1009423e3ce3SKalle Valo } 1010423e3ce3SKalle Valo 101159ae1d12SJohannes Berg skb_put_data(bounce_skb, skb->data, skb->len); 1012423e3ce3SKalle Valo memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); 1013423e3ce3SKalle Valo bounce_skb->dev = skb->dev; 1014423e3ce3SKalle Valo skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); 1015423e3ce3SKalle Valo info = IEEE80211_SKB_CB(bounce_skb); 1016423e3ce3SKalle Valo 1017423e3ce3SKalle Valo dev_kfree_skb_any(skb); 1018423e3ce3SKalle Valo skb = bounce_skb; 1019423e3ce3SKalle Valo *in_skb = bounce_skb; 1020423e3ce3SKalle Valo meta->skb = skb; 1021423e3ce3SKalle Valo meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); 1022423e3ce3SKalle Valo if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { 1023423e3ce3SKalle Valo ring->current_slot = old_top_slot; 1024423e3ce3SKalle Valo ring->used_slots = old_used_slots; 1025423e3ce3SKalle Valo err = -EIO; 1026423e3ce3SKalle Valo goto out_free_bounce; 1027423e3ce3SKalle Valo } 1028423e3ce3SKalle Valo } 1029423e3ce3SKalle Valo 1030423e3ce3SKalle Valo op32_fill_descriptor(ring, desc, meta->dmaaddr, 1031423e3ce3SKalle Valo skb->len, 0, 1, 1); 1032423e3ce3SKalle Valo 1033423e3ce3SKalle Valo wmb(); /* previous stuff MUST be done */ 1034423e3ce3SKalle Valo /* Now transfer the whole frame. */ 1035423e3ce3SKalle Valo op32_poke_tx(ring, next_slot(ring, slot)); 1036423e3ce3SKalle Valo return 0; 1037423e3ce3SKalle Valo 1038423e3ce3SKalle Valo out_free_bounce: 1039423e3ce3SKalle Valo dev_kfree_skb_any(skb); 1040423e3ce3SKalle Valo out_unmap_hdr: 1041423e3ce3SKalle Valo unmap_descbuffer(ring, meta_hdr->dmaaddr, 1042423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1); 1043423e3ce3SKalle Valo return err; 1044423e3ce3SKalle Valo } 1045423e3ce3SKalle Valo 1046423e3ce3SKalle Valo static inline 1047423e3ce3SKalle Valo int should_inject_overflow(struct b43legacy_dmaring *ring) 1048423e3ce3SKalle Valo { 1049423e3ce3SKalle Valo #ifdef CONFIG_B43LEGACY_DEBUG 1050423e3ce3SKalle Valo if (unlikely(b43legacy_debug(ring->dev, 1051423e3ce3SKalle Valo B43legacy_DBG_DMAOVERFLOW))) { 1052423e3ce3SKalle Valo /* Check if we should inject another ringbuffer overflow 1053423e3ce3SKalle Valo * to test handling of this situation in the stack. */ 1054423e3ce3SKalle Valo unsigned long next_overflow; 1055423e3ce3SKalle Valo 1056423e3ce3SKalle Valo next_overflow = ring->last_injected_overflow + HZ; 1057423e3ce3SKalle Valo if (time_after(jiffies, next_overflow)) { 1058423e3ce3SKalle Valo ring->last_injected_overflow = jiffies; 1059423e3ce3SKalle Valo b43legacydbg(ring->dev->wl, 1060423e3ce3SKalle Valo "Injecting TX ring overflow on " 1061423e3ce3SKalle Valo "DMA controller %d\n", ring->index); 1062423e3ce3SKalle Valo return 1; 1063423e3ce3SKalle Valo } 1064423e3ce3SKalle Valo } 1065423e3ce3SKalle Valo #endif /* CONFIG_B43LEGACY_DEBUG */ 1066423e3ce3SKalle Valo return 0; 1067423e3ce3SKalle Valo } 1068423e3ce3SKalle Valo 1069423e3ce3SKalle Valo int b43legacy_dma_tx(struct b43legacy_wldev *dev, 1070423e3ce3SKalle Valo struct sk_buff *skb) 1071423e3ce3SKalle Valo { 1072423e3ce3SKalle Valo struct b43legacy_dmaring *ring; 1073423e3ce3SKalle Valo int err = 0; 1074423e3ce3SKalle Valo 1075423e3ce3SKalle Valo ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); 1076423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 1077423e3ce3SKalle Valo 1078423e3ce3SKalle Valo if (unlikely(ring->stopped)) { 1079423e3ce3SKalle Valo /* We get here only because of a bug in mac80211. 1080423e3ce3SKalle Valo * Because of a race, one packet may be queued after 1081423e3ce3SKalle Valo * the queue is stopped, thus we got called when we shouldn't. 1082423e3ce3SKalle Valo * For now, just refuse the transmit. */ 1083423e3ce3SKalle Valo if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1084423e3ce3SKalle Valo b43legacyerr(dev->wl, "Packet after queue stopped\n"); 1085423e3ce3SKalle Valo return -ENOSPC; 1086423e3ce3SKalle Valo } 1087423e3ce3SKalle Valo 10887e41fb50SIgor Stoppa if (WARN_ON(free_slots(ring) < SLOTS_PER_PACKET)) { 1089423e3ce3SKalle Valo /* If we get here, we have a real error with the queue 1090423e3ce3SKalle Valo * full, but queues not stopped. */ 1091423e3ce3SKalle Valo b43legacyerr(dev->wl, "DMA queue overflow\n"); 1092423e3ce3SKalle Valo return -ENOSPC; 1093423e3ce3SKalle Valo } 1094423e3ce3SKalle Valo 1095423e3ce3SKalle Valo /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing 1096423e3ce3SKalle Valo * into the skb data or cb now. */ 1097423e3ce3SKalle Valo err = dma_tx_fragment(ring, &skb); 1098423e3ce3SKalle Valo if (unlikely(err == -ENOKEY)) { 1099423e3ce3SKalle Valo /* Drop this packet, as we don't have the encryption key 1100423e3ce3SKalle Valo * anymore and must not transmit it unencrypted. */ 1101423e3ce3SKalle Valo dev_kfree_skb_any(skb); 1102423e3ce3SKalle Valo return 0; 1103423e3ce3SKalle Valo } 1104423e3ce3SKalle Valo if (unlikely(err)) { 1105423e3ce3SKalle Valo b43legacyerr(dev->wl, "DMA tx mapping failure\n"); 1106423e3ce3SKalle Valo return err; 1107423e3ce3SKalle Valo } 1108423e3ce3SKalle Valo if ((free_slots(ring) < SLOTS_PER_PACKET) || 1109423e3ce3SKalle Valo should_inject_overflow(ring)) { 1110423e3ce3SKalle Valo /* This TX ring is full. */ 1111423e3ce3SKalle Valo unsigned int skb_mapping = skb_get_queue_mapping(skb); 1112423e3ce3SKalle Valo ieee80211_stop_queue(dev->wl->hw, skb_mapping); 1113423e3ce3SKalle Valo dev->wl->tx_queue_stopped[skb_mapping] = 1; 1114423e3ce3SKalle Valo ring->stopped = true; 1115423e3ce3SKalle Valo if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1116423e3ce3SKalle Valo b43legacydbg(dev->wl, "Stopped TX ring %d\n", 1117423e3ce3SKalle Valo ring->index); 1118423e3ce3SKalle Valo } 1119423e3ce3SKalle Valo return err; 1120423e3ce3SKalle Valo } 1121423e3ce3SKalle Valo 1122423e3ce3SKalle Valo void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, 1123423e3ce3SKalle Valo const struct b43legacy_txstatus *status) 1124423e3ce3SKalle Valo { 1125423e3ce3SKalle Valo struct b43legacy_dmaring *ring; 1126423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta; 1127423e3ce3SKalle Valo int retry_limit; 1128423e3ce3SKalle Valo int slot; 1129423e3ce3SKalle Valo int firstused; 1130423e3ce3SKalle Valo 1131423e3ce3SKalle Valo ring = parse_cookie(dev, status->cookie, &slot); 1132423e3ce3SKalle Valo if (unlikely(!ring)) 1133423e3ce3SKalle Valo return; 1134423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 1135423e3ce3SKalle Valo 1136423e3ce3SKalle Valo /* Sanity check: TX packets are processed in-order on one ring. 1137423e3ce3SKalle Valo * Check if the slot deduced from the cookie really is the first 1138423e3ce3SKalle Valo * used slot. */ 1139423e3ce3SKalle Valo firstused = ring->current_slot - ring->used_slots + 1; 1140423e3ce3SKalle Valo if (firstused < 0) 1141423e3ce3SKalle Valo firstused = ring->nr_slots + firstused; 1142423e3ce3SKalle Valo if (unlikely(slot != firstused)) { 1143423e3ce3SKalle Valo /* This possibly is a firmware bug and will result in 1144423e3ce3SKalle Valo * malfunction, memory leaks and/or stall of DMA functionality. 1145423e3ce3SKalle Valo */ 1146423e3ce3SKalle Valo b43legacydbg(dev->wl, "Out of order TX status report on DMA " 1147423e3ce3SKalle Valo "ring %d. Expected %d, but got %d\n", 1148423e3ce3SKalle Valo ring->index, firstused, slot); 1149423e3ce3SKalle Valo return; 1150423e3ce3SKalle Valo } 1151423e3ce3SKalle Valo 1152423e3ce3SKalle Valo while (1) { 1153423e3ce3SKalle Valo B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); 1154423e3ce3SKalle Valo op32_idx2desc(ring, slot, &meta); 1155423e3ce3SKalle Valo 1156423e3ce3SKalle Valo if (meta->skb) 1157423e3ce3SKalle Valo unmap_descbuffer(ring, meta->dmaaddr, 1158423e3ce3SKalle Valo meta->skb->len, 1); 1159423e3ce3SKalle Valo else 1160423e3ce3SKalle Valo unmap_descbuffer(ring, meta->dmaaddr, 1161423e3ce3SKalle Valo sizeof(struct b43legacy_txhdr_fw3), 1162423e3ce3SKalle Valo 1); 1163423e3ce3SKalle Valo 1164423e3ce3SKalle Valo if (meta->is_last_fragment) { 1165423e3ce3SKalle Valo struct ieee80211_tx_info *info; 1166423e3ce3SKalle Valo BUG_ON(!meta->skb); 1167423e3ce3SKalle Valo info = IEEE80211_SKB_CB(meta->skb); 1168423e3ce3SKalle Valo 1169423e3ce3SKalle Valo /* preserve the confiured retry limit before clearing the status 1170423e3ce3SKalle Valo * The xmit function has overwritten the rc's value with the actual 1171423e3ce3SKalle Valo * retry limit done by the hardware */ 1172423e3ce3SKalle Valo retry_limit = info->status.rates[0].count; 1173423e3ce3SKalle Valo ieee80211_tx_info_clear_status(info); 1174423e3ce3SKalle Valo 1175423e3ce3SKalle Valo if (status->acked) 1176423e3ce3SKalle Valo info->flags |= IEEE80211_TX_STAT_ACK; 1177423e3ce3SKalle Valo 1178423e3ce3SKalle Valo if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { 1179423e3ce3SKalle Valo /* 1180423e3ce3SKalle Valo * If the short retries (RTS, not data frame) have exceeded 1181423e3ce3SKalle Valo * the limit, the hw will not have tried the selected rate, 1182423e3ce3SKalle Valo * but will have used the fallback rate instead. 1183423e3ce3SKalle Valo * Don't let the rate control count attempts for the selected 1184423e3ce3SKalle Valo * rate in this case, otherwise the statistics will be off. 1185423e3ce3SKalle Valo */ 1186423e3ce3SKalle Valo info->status.rates[0].count = 0; 1187423e3ce3SKalle Valo info->status.rates[1].count = status->frame_count; 1188423e3ce3SKalle Valo } else { 1189423e3ce3SKalle Valo if (status->frame_count > retry_limit) { 1190423e3ce3SKalle Valo info->status.rates[0].count = retry_limit; 1191423e3ce3SKalle Valo info->status.rates[1].count = status->frame_count - 1192423e3ce3SKalle Valo retry_limit; 1193423e3ce3SKalle Valo 1194423e3ce3SKalle Valo } else { 1195423e3ce3SKalle Valo info->status.rates[0].count = status->frame_count; 1196423e3ce3SKalle Valo info->status.rates[1].idx = -1; 1197423e3ce3SKalle Valo } 1198423e3ce3SKalle Valo } 1199423e3ce3SKalle Valo 1200423e3ce3SKalle Valo /* Call back to inform the ieee80211 subsystem about the 1201423e3ce3SKalle Valo * status of the transmission. 1202423e3ce3SKalle Valo * Some fields of txstat are already filled in dma_tx(). 1203423e3ce3SKalle Valo */ 1204423e3ce3SKalle Valo ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); 1205423e3ce3SKalle Valo /* skb is freed by ieee80211_tx_status_irqsafe() */ 1206423e3ce3SKalle Valo meta->skb = NULL; 1207423e3ce3SKalle Valo } else { 1208423e3ce3SKalle Valo /* No need to call free_descriptor_buffer here, as 1209423e3ce3SKalle Valo * this is only the txhdr, which is not allocated. 1210423e3ce3SKalle Valo */ 1211423e3ce3SKalle Valo B43legacy_WARN_ON(meta->skb != NULL); 1212423e3ce3SKalle Valo } 1213423e3ce3SKalle Valo 1214423e3ce3SKalle Valo /* Everything unmapped and free'd. So it's not used anymore. */ 1215423e3ce3SKalle Valo ring->used_slots--; 1216423e3ce3SKalle Valo 1217423e3ce3SKalle Valo if (meta->is_last_fragment) 1218423e3ce3SKalle Valo break; 1219423e3ce3SKalle Valo slot = next_slot(ring, slot); 1220423e3ce3SKalle Valo } 1221423e3ce3SKalle Valo dev->stats.last_tx = jiffies; 1222423e3ce3SKalle Valo if (ring->stopped) { 1223423e3ce3SKalle Valo B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); 1224423e3ce3SKalle Valo ring->stopped = false; 1225423e3ce3SKalle Valo } 1226423e3ce3SKalle Valo 1227423e3ce3SKalle Valo if (dev->wl->tx_queue_stopped[ring->queue_prio]) { 1228423e3ce3SKalle Valo dev->wl->tx_queue_stopped[ring->queue_prio] = 0; 1229423e3ce3SKalle Valo } else { 1230423e3ce3SKalle Valo /* If the driver queue is running wake the corresponding 1231423e3ce3SKalle Valo * mac80211 queue. */ 1232423e3ce3SKalle Valo ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); 1233423e3ce3SKalle Valo if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1234423e3ce3SKalle Valo b43legacydbg(dev->wl, "Woke up TX ring %d\n", 1235423e3ce3SKalle Valo ring->index); 1236423e3ce3SKalle Valo } 1237423e3ce3SKalle Valo /* Add work to the queue. */ 1238423e3ce3SKalle Valo ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work); 1239423e3ce3SKalle Valo } 1240423e3ce3SKalle Valo 1241423e3ce3SKalle Valo static void dma_rx(struct b43legacy_dmaring *ring, 1242423e3ce3SKalle Valo int *slot) 1243423e3ce3SKalle Valo { 1244423e3ce3SKalle Valo struct b43legacy_dmadesc32 *desc; 1245423e3ce3SKalle Valo struct b43legacy_dmadesc_meta *meta; 1246423e3ce3SKalle Valo struct b43legacy_rxhdr_fw3 *rxhdr; 1247423e3ce3SKalle Valo struct sk_buff *skb; 1248423e3ce3SKalle Valo u16 len; 1249423e3ce3SKalle Valo int err; 1250423e3ce3SKalle Valo dma_addr_t dmaaddr; 1251423e3ce3SKalle Valo 1252423e3ce3SKalle Valo desc = op32_idx2desc(ring, *slot, &meta); 1253423e3ce3SKalle Valo 1254423e3ce3SKalle Valo sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); 1255423e3ce3SKalle Valo skb = meta->skb; 1256423e3ce3SKalle Valo 1257423e3ce3SKalle Valo if (ring->index == 3) { 1258423e3ce3SKalle Valo /* We received an xmit status. */ 1259423e3ce3SKalle Valo struct b43legacy_hwtxstatus *hw = 1260423e3ce3SKalle Valo (struct b43legacy_hwtxstatus *)skb->data; 1261423e3ce3SKalle Valo int i = 0; 1262423e3ce3SKalle Valo 1263423e3ce3SKalle Valo while (hw->cookie == 0) { 1264423e3ce3SKalle Valo if (i > 100) 1265423e3ce3SKalle Valo break; 1266423e3ce3SKalle Valo i++; 1267423e3ce3SKalle Valo udelay(2); 1268423e3ce3SKalle Valo barrier(); 1269423e3ce3SKalle Valo } 1270423e3ce3SKalle Valo b43legacy_handle_hwtxstatus(ring->dev, hw); 1271423e3ce3SKalle Valo /* recycle the descriptor buffer. */ 1272423e3ce3SKalle Valo sync_descbuffer_for_device(ring, meta->dmaaddr, 1273423e3ce3SKalle Valo ring->rx_buffersize); 1274423e3ce3SKalle Valo 1275423e3ce3SKalle Valo return; 1276423e3ce3SKalle Valo } 1277423e3ce3SKalle Valo rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data; 1278423e3ce3SKalle Valo len = le16_to_cpu(rxhdr->frame_len); 1279423e3ce3SKalle Valo if (len == 0) { 1280423e3ce3SKalle Valo int i = 0; 1281423e3ce3SKalle Valo 1282423e3ce3SKalle Valo do { 1283423e3ce3SKalle Valo udelay(2); 1284423e3ce3SKalle Valo barrier(); 1285423e3ce3SKalle Valo len = le16_to_cpu(rxhdr->frame_len); 1286423e3ce3SKalle Valo } while (len == 0 && i++ < 5); 1287423e3ce3SKalle Valo if (unlikely(len == 0)) { 1288423e3ce3SKalle Valo /* recycle the descriptor buffer. */ 1289423e3ce3SKalle Valo sync_descbuffer_for_device(ring, meta->dmaaddr, 1290423e3ce3SKalle Valo ring->rx_buffersize); 1291423e3ce3SKalle Valo goto drop; 1292423e3ce3SKalle Valo } 1293423e3ce3SKalle Valo } 1294423e3ce3SKalle Valo if (unlikely(len > ring->rx_buffersize)) { 1295423e3ce3SKalle Valo /* The data did not fit into one descriptor buffer 1296423e3ce3SKalle Valo * and is split over multiple buffers. 1297423e3ce3SKalle Valo * This should never happen, as we try to allocate buffers 1298423e3ce3SKalle Valo * big enough. So simply ignore this packet. 1299423e3ce3SKalle Valo */ 1300423e3ce3SKalle Valo int cnt = 0; 1301423e3ce3SKalle Valo s32 tmp = len; 1302423e3ce3SKalle Valo 1303423e3ce3SKalle Valo while (1) { 1304423e3ce3SKalle Valo desc = op32_idx2desc(ring, *slot, &meta); 1305423e3ce3SKalle Valo /* recycle the descriptor buffer. */ 1306423e3ce3SKalle Valo sync_descbuffer_for_device(ring, meta->dmaaddr, 1307423e3ce3SKalle Valo ring->rx_buffersize); 1308423e3ce3SKalle Valo *slot = next_slot(ring, *slot); 1309423e3ce3SKalle Valo cnt++; 1310423e3ce3SKalle Valo tmp -= ring->rx_buffersize; 1311423e3ce3SKalle Valo if (tmp <= 0) 1312423e3ce3SKalle Valo break; 1313423e3ce3SKalle Valo } 1314423e3ce3SKalle Valo b43legacyerr(ring->dev->wl, "DMA RX buffer too small " 1315423e3ce3SKalle Valo "(len: %u, buffer: %u, nr-dropped: %d)\n", 1316423e3ce3SKalle Valo len, ring->rx_buffersize, cnt); 1317423e3ce3SKalle Valo goto drop; 1318423e3ce3SKalle Valo } 1319423e3ce3SKalle Valo 1320423e3ce3SKalle Valo dmaaddr = meta->dmaaddr; 1321423e3ce3SKalle Valo err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); 1322423e3ce3SKalle Valo if (unlikely(err)) { 1323423e3ce3SKalle Valo b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()" 1324423e3ce3SKalle Valo " failed\n"); 1325423e3ce3SKalle Valo sync_descbuffer_for_device(ring, dmaaddr, 1326423e3ce3SKalle Valo ring->rx_buffersize); 1327423e3ce3SKalle Valo goto drop; 1328423e3ce3SKalle Valo } 1329423e3ce3SKalle Valo 1330423e3ce3SKalle Valo unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); 1331423e3ce3SKalle Valo skb_put(skb, len + ring->frameoffset); 1332423e3ce3SKalle Valo skb_pull(skb, ring->frameoffset); 1333423e3ce3SKalle Valo 1334423e3ce3SKalle Valo b43legacy_rx(ring->dev, skb, rxhdr); 1335423e3ce3SKalle Valo drop: 1336423e3ce3SKalle Valo return; 1337423e3ce3SKalle Valo } 1338423e3ce3SKalle Valo 1339423e3ce3SKalle Valo void b43legacy_dma_rx(struct b43legacy_dmaring *ring) 1340423e3ce3SKalle Valo { 1341423e3ce3SKalle Valo int slot; 1342423e3ce3SKalle Valo int current_slot; 1343423e3ce3SKalle Valo int used_slots = 0; 1344423e3ce3SKalle Valo 1345423e3ce3SKalle Valo B43legacy_WARN_ON(ring->tx); 1346423e3ce3SKalle Valo current_slot = op32_get_current_rxslot(ring); 1347423e3ce3SKalle Valo B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < 1348423e3ce3SKalle Valo ring->nr_slots)); 1349423e3ce3SKalle Valo 1350423e3ce3SKalle Valo slot = ring->current_slot; 1351423e3ce3SKalle Valo for (; slot != current_slot; slot = next_slot(ring, slot)) { 1352423e3ce3SKalle Valo dma_rx(ring, &slot); 1353423e3ce3SKalle Valo update_max_used_slots(ring, ++used_slots); 1354423e3ce3SKalle Valo } 1355423e3ce3SKalle Valo op32_set_current_rxslot(ring, slot); 1356423e3ce3SKalle Valo ring->current_slot = slot; 1357423e3ce3SKalle Valo } 1358423e3ce3SKalle Valo 1359423e3ce3SKalle Valo static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) 1360423e3ce3SKalle Valo { 1361423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 1362423e3ce3SKalle Valo op32_tx_suspend(ring); 1363423e3ce3SKalle Valo } 1364423e3ce3SKalle Valo 1365423e3ce3SKalle Valo static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) 1366423e3ce3SKalle Valo { 1367423e3ce3SKalle Valo B43legacy_WARN_ON(!ring->tx); 1368423e3ce3SKalle Valo op32_tx_resume(ring); 1369423e3ce3SKalle Valo } 1370423e3ce3SKalle Valo 1371423e3ce3SKalle Valo void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) 1372423e3ce3SKalle Valo { 1373423e3ce3SKalle Valo b43legacy_power_saving_ctl_bits(dev, -1, 1); 1374423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0); 1375423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1); 1376423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2); 1377423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3); 1378423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4); 1379423e3ce3SKalle Valo b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5); 1380423e3ce3SKalle Valo } 1381423e3ce3SKalle Valo 1382423e3ce3SKalle Valo void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev) 1383423e3ce3SKalle Valo { 1384423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5); 1385423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4); 1386423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3); 1387423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2); 1388423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1); 1389423e3ce3SKalle Valo b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0); 1390423e3ce3SKalle Valo b43legacy_power_saving_ctl_bits(dev, -1, -1); 1391423e3ce3SKalle Valo } 1392