⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dma.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  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 + -