📄 dma.c
字号:
/* Broadcom B43legacy wireless driver DMA ringbuffer and descriptor allocation/management Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Some code in this file is derived from the b44.c driver Copyright (C) 2002 David S. Miller Copyright (C) Pekka Pietikainen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.*/#include "b43legacy.h"#include "dma.h"#include "main.h"#include "debugfs.h"#include "xmit.h"#include <linux/dma-mapping.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/skbuff.h>#include <net/dst.h>/* 32bit DMA ops. */staticstruct b43legacy_dmadesc_generic *op32_idx2desc( struct b43legacy_dmaring *ring, int slot, struct b43legacy_dmadesc_meta **meta){ struct b43legacy_dmadesc32 *desc; *meta = &(ring->meta[slot]); desc = ring->descbase; desc = &(desc[slot]); return (struct b43legacy_dmadesc_generic *)desc;}static void op32_fill_descriptor(struct b43legacy_dmaring *ring, struct b43legacy_dmadesc_generic *desc, dma_addr_t dmaaddr, u16 bufsize, int start, int end, int irq){ struct b43legacy_dmadesc32 *descbase = ring->descbase; int slot; u32 ctl; u32 addr; u32 addrext; slot = (int)(&(desc->dma32) - descbase); B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK) >> SSB_DMA_TRANSLATION_SHIFT; addr |= ssb_dma_translation(ring->dev->dev); ctl = (bufsize - ring->frameoffset) & B43legacy_DMA32_DCTL_BYTECNT; if (slot == ring->nr_slots - 1) ctl |= B43legacy_DMA32_DCTL_DTABLEEND; if (start) ctl |= B43legacy_DMA32_DCTL_FRAMESTART; if (end) ctl |= B43legacy_DMA32_DCTL_FRAMEEND; if (irq) ctl |= B43legacy_DMA32_DCTL_IRQ; ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) & B43legacy_DMA32_DCTL_ADDREXT_MASK; desc->dma32.control = cpu_to_le32(ctl); desc->dma32.address = cpu_to_le32(addr);}static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot){ b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX, (u32)(slot * sizeof(struct b43legacy_dmadesc32)));}static void op32_tx_suspend(struct b43legacy_dmaring *ring){ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) | B43legacy_DMA32_TXSUSPEND);}static void op32_tx_resume(struct b43legacy_dmaring *ring){ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) & ~B43legacy_DMA32_TXSUSPEND);}static int op32_get_current_rxslot(struct b43legacy_dmaring *ring){ u32 val; val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS); val &= B43legacy_DMA32_RXDPTR; return (val / sizeof(struct b43legacy_dmadesc32));}static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, int slot){ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, (u32)(slot * sizeof(struct b43legacy_dmadesc32)));}static const struct b43legacy_dma_ops dma32_ops = { .idx2desc = op32_idx2desc, .fill_descriptor = op32_fill_descriptor, .poke_tx = op32_poke_tx, .tx_suspend = op32_tx_suspend, .tx_resume = op32_tx_resume, .get_current_rxslot = op32_get_current_rxslot, .set_current_rxslot = op32_set_current_rxslot,};/* 64bit DMA ops. */staticstruct b43legacy_dmadesc_generic *op64_idx2desc( struct b43legacy_dmaring *ring, int slot, struct b43legacy_dmadesc_meta **meta){ struct b43legacy_dmadesc64 *desc; *meta = &(ring->meta[slot]); desc = ring->descbase; desc = &(desc[slot]); return (struct b43legacy_dmadesc_generic *)desc;}static void op64_fill_descriptor(struct b43legacy_dmaring *ring, struct b43legacy_dmadesc_generic *desc, dma_addr_t dmaaddr, u16 bufsize, int start, int end, int irq){ struct b43legacy_dmadesc64 *descbase = ring->descbase; int slot; u32 ctl0 = 0; u32 ctl1 = 0; u32 addrlo; u32 addrhi; u32 addrext; slot = (int)(&(desc->dma64) - descbase); B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); addrlo = (u32)(dmaaddr & 0xFFFFFFFF); addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) >> SSB_DMA_TRANSLATION_SHIFT; addrhi |= ssb_dma_translation(ring->dev->dev); if (slot == ring->nr_slots - 1) ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND; if (start) ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART; if (end) ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND; if (irq) ctl0 |= B43legacy_DMA64_DCTL0_IRQ; ctl1 |= (bufsize - ring->frameoffset) & B43legacy_DMA64_DCTL1_BYTECNT; ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT) & B43legacy_DMA64_DCTL1_ADDREXT_MASK; desc->dma64.control0 = cpu_to_le32(ctl0); desc->dma64.control1 = cpu_to_le32(ctl1); desc->dma64.address_low = cpu_to_le32(addrlo); desc->dma64.address_high = cpu_to_le32(addrhi);}static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot){ b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX, (u32)(slot * sizeof(struct b43legacy_dmadesc64)));}static void op64_tx_suspend(struct b43legacy_dmaring *ring){ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) | B43legacy_DMA64_TXSUSPEND);}static void op64_tx_resume(struct b43legacy_dmaring *ring){ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) & ~B43legacy_DMA64_TXSUSPEND);}static int op64_get_current_rxslot(struct b43legacy_dmaring *ring){ u32 val; val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS); val &= B43legacy_DMA64_RXSTATDPTR; return (val / sizeof(struct b43legacy_dmadesc64));}static void op64_set_current_rxslot(struct b43legacy_dmaring *ring, int slot){ b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, (u32)(slot * sizeof(struct b43legacy_dmadesc64)));}static const struct b43legacy_dma_ops dma64_ops = { .idx2desc = op64_idx2desc, .fill_descriptor = op64_fill_descriptor, .poke_tx = op64_poke_tx, .tx_suspend = op64_tx_suspend, .tx_resume = op64_tx_resume, .get_current_rxslot = op64_get_current_rxslot, .set_current_rxslot = op64_set_current_rxslot,};static inline int free_slots(struct b43legacy_dmaring *ring){ return (ring->nr_slots - ring->used_slots);}static inline int next_slot(struct b43legacy_dmaring *ring, int slot){ B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); if (slot == ring->nr_slots - 1) return 0; return slot + 1;}static inline int prev_slot(struct b43legacy_dmaring *ring, int slot){ B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); if (slot == 0) return ring->nr_slots - 1; return slot - 1;}#ifdef CONFIG_B43LEGACY_DEBUGstatic void update_max_used_slots(struct b43legacy_dmaring *ring, int current_used_slots){ if (current_used_slots <= ring->max_used_slots) return; ring->max_used_slots = current_used_slots; if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE)) b43legacydbg(ring->dev->wl, "max_used_slots increased to %d on %s ring %d\n", ring->max_used_slots, ring->tx ? "TX" : "RX", ring->index);}#elsestatic inlinevoid update_max_used_slots(struct b43legacy_dmaring *ring, int current_used_slots){ }#endif /* DEBUG *//* Request a slot for usage. */static inlineint request_slot(struct b43legacy_dmaring *ring){ int slot; B43legacy_WARN_ON(!ring->tx); B43legacy_WARN_ON(ring->stopped); B43legacy_WARN_ON(free_slots(ring) == 0); slot = next_slot(ring, ring->current_slot); ring->current_slot = slot; ring->used_slots++; update_max_used_slots(ring, ring->used_slots); return slot;}/* Mac80211-queue to b43legacy-ring mapping */static struct b43legacy_dmaring *priority_to_txring( struct b43legacy_wldev *dev, int queue_priority){ struct b43legacy_dmaring *ring;/*FIXME: For now we always run on TX-ring-1 */return dev->dma.tx_ring1; /* 0 = highest priority */ switch (queue_priority) { default: B43legacy_WARN_ON(1); /* fallthrough */ case 0: ring = dev->dma.tx_ring3; break; case 1: ring = dev->dma.tx_ring2; break; case 2: ring = dev->dma.tx_ring1; break; case 3: ring = dev->dma.tx_ring0; break; case 4: ring = dev->dma.tx_ring4; break; case 5: ring = dev->dma.tx_ring5; break; } return ring;}/* Bcm4301-ring to mac80211-queue mapping */static inline int txring_to_priority(struct b43legacy_dmaring *ring){ static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };/*FIXME: have only one queue, for now */return 0; return idx_to_prio[ring->index];}u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx){ static const u16 map64[] = { B43legacy_MMIO_DMA64_BASE0, B43legacy_MMIO_DMA64_BASE1, B43legacy_MMIO_DMA64_BASE2, B43legacy_MMIO_DMA64_BASE3, B43legacy_MMIO_DMA64_BASE4, B43legacy_MMIO_DMA64_BASE5, }; static const u16 map32[] = { B43legacy_MMIO_DMA32_BASE0, B43legacy_MMIO_DMA32_BASE1, B43legacy_MMIO_DMA32_BASE2, B43legacy_MMIO_DMA32_BASE3, B43legacy_MMIO_DMA32_BASE4, B43legacy_MMIO_DMA32_BASE5, }; if (dma64bit) { B43legacy_WARN_ON(!(controller_idx >= 0 && controller_idx < ARRAY_SIZE(map64))); return map64[controller_idx]; } B43legacy_WARN_ON(!(controller_idx >= 0 && controller_idx < ARRAY_SIZE(map32))); return map32[controller_idx];}static inlinedma_addr_t map_descbuffer(struct b43legacy_dmaring *ring, unsigned char *buf, size_t len, int tx){ dma_addr_t dmaaddr; if (tx) dmaaddr = dma_map_single(ring->dev->dev->dev, buf, len, DMA_TO_DEVICE); else dmaaddr = dma_map_single(ring->dev->dev->dev, buf, len, DMA_FROM_DEVICE); return dmaaddr;}static inlinevoid unmap_descbuffer(struct b43legacy_dmaring *ring, dma_addr_t addr, size_t len, int tx){ if (tx) dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE); else dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_FROM_DEVICE);}static inlinevoid sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring, dma_addr_t addr, size_t len){ B43legacy_WARN_ON(ring->tx); dma_sync_single_for_cpu(ring->dev->dev->dev, addr, len, DMA_FROM_DEVICE);}static inlinevoid sync_descbuffer_for_device(struct b43legacy_dmaring *ring, dma_addr_t addr, size_t len){ B43legacy_WARN_ON(ring->tx); dma_sync_single_for_device(ring->dev->dev->dev, addr, len, DMA_FROM_DEVICE);}static inlinevoid 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; }}static int alloc_ringmemory(struct b43legacy_dmaring *ring){ struct device *dev = ring->dev->dev->dev; ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE, &(ring->dmabase), GFP_KERNEL); if (!ring->descbase) { b43legacyerr(ring->dev->wl, "DMA ringmemory allocation" " failed\n"); return -ENOMEM; } memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE); return 0;}static void free_ringmemory(struct b43legacy_dmaring *ring){ struct device *dev = ring->dev->dev->dev; dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE, ring->descbase, ring->dmabase);}/* Reset the RX DMA channel */int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, u16 mmio_base, int dma64){ int i; u32 value; u16 offset; might_sleep(); offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; b43legacy_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { offset = dma64 ? B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); if (dma64) { value &= B43legacy_DMA64_RXSTAT; if (value == B43legacy_DMA64_RXSTAT_DISABLED) { i = -1; break; } } else { value &= B43legacy_DMA32_RXSTATE; if (value == B43legacy_DMA32_RXSTAT_DISABLED) { i = -1; break; } } msleep(1); } if (i != -1) { b43legacyerr(dev->wl, "DMA RX reset timed out\n"); return -ENODEV; } return 0;}/* Reset the RX DMA channel */int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, u16 mmio_base, int dma64){ int i; u32 value; u16 offset; might_sleep();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -