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

📄 ebus.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: ebus.c,v 1.64 2001/11/08 04:41:33 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be) * Copyright (C) 1999  David S. Miller (davem@redhat.com) */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <asm/system.h>#include <asm/page.h>#include <asm/pbm.h>#include <asm/ebus.h>#include <asm/oplib.h>#include <asm/bpp.h>#include <asm/irq.h>/* EBUS dma library. */#define EBDMA_CSR	0x00UL	/* Control/Status */#define EBDMA_ADDR	0x04UL	/* DMA Address */#define EBDMA_COUNT	0x08UL	/* DMA Count */#define EBDMA_CSR_INT_PEND	0x00000001#define EBDMA_CSR_ERR_PEND	0x00000002#define EBDMA_CSR_DRAIN		0x00000004#define EBDMA_CSR_INT_EN	0x00000010#define EBDMA_CSR_RESET		0x00000080#define EBDMA_CSR_WRITE		0x00000100#define EBDMA_CSR_EN_DMA	0x00000200#define EBDMA_CSR_CYC_PEND	0x00000400#define EBDMA_CSR_DIAG_RD_DONE	0x00000800#define EBDMA_CSR_DIAG_WR_DONE	0x00001000#define EBDMA_CSR_EN_CNT	0x00002000#define EBDMA_CSR_TC		0x00004000#define EBDMA_CSR_DIS_CSR_DRN	0x00010000#define EBDMA_CSR_BURST_SZ_MASK	0x000c0000#define EBDMA_CSR_BURST_SZ_1	0x00080000#define EBDMA_CSR_BURST_SZ_4	0x00000000#define EBDMA_CSR_BURST_SZ_8	0x00040000#define EBDMA_CSR_BURST_SZ_16	0x000c0000#define EBDMA_CSR_DIAG_EN	0x00100000#define EBDMA_CSR_DIS_ERR_PEND	0x00400000#define EBDMA_CSR_TCI_DIS	0x00800000#define EBDMA_CSR_EN_NEXT	0x01000000#define EBDMA_CSR_DMA_ON	0x02000000#define EBDMA_CSR_A_LOADED	0x04000000#define EBDMA_CSR_NA_LOADED	0x08000000#define EBDMA_CSR_DEV_ID_MASK	0xf0000000#define EBUS_DMA_RESET_TIMEOUT	10000static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain){	int i;	u32 val = 0;	writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);	udelay(1);	if (no_drain)		return;	for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {		val = readl(p->regs + EBDMA_CSR);		if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))			break;		udelay(10);	}}static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs){	struct ebus_dma_info *p = dev_id;	unsigned long flags;	u32 csr = 0;	spin_lock_irqsave(&p->lock, flags);	csr = readl(p->regs + EBDMA_CSR);	writel(csr, p->regs + EBDMA_CSR);	spin_unlock_irqrestore(&p->lock, flags);	if (csr & EBDMA_CSR_ERR_PEND) {		printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);		p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);		return IRQ_HANDLED;	} else if (csr & EBDMA_CSR_INT_PEND) {		p->callback(p,			    (csr & EBDMA_CSR_TC) ?			    EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,			    p->client_cookie);		return IRQ_HANDLED;	}	return IRQ_NONE;}int ebus_dma_register(struct ebus_dma_info *p){	u32 csr;	if (!p->regs)		return -EINVAL;	if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |			 EBUS_DMA_FLAG_TCI_DISABLE))		return -EINVAL;	if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)		return -EINVAL;	if (!strlen(p->name))		return -EINVAL;	__ebus_dma_reset(p, 1);	csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;	if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)		csr |= EBDMA_CSR_TCI_DIS;	writel(csr, p->regs + EBDMA_CSR);	return 0;}EXPORT_SYMBOL(ebus_dma_register);int ebus_dma_irq_enable(struct ebus_dma_info *p, int on){	unsigned long flags;	u32 csr;	if (on) {		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {			if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p))				return -EBUSY;		}		spin_lock_irqsave(&p->lock, flags);		csr = readl(p->regs + EBDMA_CSR);		csr |= EBDMA_CSR_INT_EN;		writel(csr, p->regs + EBDMA_CSR);		spin_unlock_irqrestore(&p->lock, flags);	} else {		spin_lock_irqsave(&p->lock, flags);		csr = readl(p->regs + EBDMA_CSR);		csr &= ~EBDMA_CSR_INT_EN;		writel(csr, p->regs + EBDMA_CSR);		spin_unlock_irqrestore(&p->lock, flags);		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {			free_irq(p->irq, p);		}	}	return 0;}EXPORT_SYMBOL(ebus_dma_irq_enable);void ebus_dma_unregister(struct ebus_dma_info *p){	unsigned long flags;	u32 csr;	int irq_on = 0;	spin_lock_irqsave(&p->lock, flags);	csr = readl(p->regs + EBDMA_CSR);	if (csr & EBDMA_CSR_INT_EN) {		csr &= ~EBDMA_CSR_INT_EN;		writel(csr, p->regs + EBDMA_CSR);		irq_on = 1;	}	spin_unlock_irqrestore(&p->lock, flags);	if (irq_on)		free_irq(p->irq, p);}EXPORT_SYMBOL(ebus_dma_unregister);int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len){	unsigned long flags;	u32 csr;	int err;	if (len >= (1 << 24))		return -EINVAL;	spin_lock_irqsave(&p->lock, flags);	csr = readl(p->regs + EBDMA_CSR);	err = -EINVAL;	if (!(csr & EBDMA_CSR_EN_DMA))		goto out;	err = -EBUSY;	if (csr & EBDMA_CSR_NA_LOADED)		goto out;	writel(len,      p->regs + EBDMA_COUNT);	writel(bus_addr, p->regs + EBDMA_ADDR);	err = 0;out:	spin_unlock_irqrestore(&p->lock, flags);	return err;}EXPORT_SYMBOL(ebus_dma_request);void ebus_dma_prepare(struct ebus_dma_info *p, int write){	unsigned long flags;	u32 csr;	spin_lock_irqsave(&p->lock, flags);	__ebus_dma_reset(p, 0);	csr = (EBDMA_CSR_INT_EN |	       EBDMA_CSR_EN_CNT |	       EBDMA_CSR_BURST_SZ_16 |	       EBDMA_CSR_EN_NEXT);	if (write)		csr |= EBDMA_CSR_WRITE;	if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)		csr |= EBDMA_CSR_TCI_DIS;	writel(csr, p->regs + EBDMA_CSR);	spin_unlock_irqrestore(&p->lock, flags);}EXPORT_SYMBOL(ebus_dma_prepare);unsigned int ebus_dma_residue(struct ebus_dma_info *p){	return readl(p->regs + EBDMA_COUNT);}EXPORT_SYMBOL(ebus_dma_residue);unsigned int ebus_dma_addr(struct ebus_dma_info *p){	return readl(p->regs + EBDMA_ADDR);}EXPORT_SYMBOL(ebus_dma_addr);void ebus_dma_enable(struct ebus_dma_info *p, int on){	unsigned long flags;	u32 orig_csr, csr;	spin_lock_irqsave(&p->lock, flags);	orig_csr = csr = readl(p->regs + EBDMA_CSR);	if (on)		csr |= EBDMA_CSR_EN_DMA;	else		csr &= ~EBDMA_CSR_EN_DMA;	if ((orig_csr & EBDMA_CSR_EN_DMA) !=	    (csr & EBDMA_CSR_EN_DMA))		writel(csr, p->regs + EBDMA_CSR);	spin_unlock_irqrestore(&p->lock, flags);}EXPORT_SYMBOL(ebus_dma_enable);struct linux_ebus *ebus_chain = NULL;#ifdef CONFIG_SUN_AUXIOextern void auxio_probe(void);#endifstatic inline void *ebus_alloc(size_t size){	void *mem;	mem = kmalloc(size, GFP_ATOMIC);	if (!mem)		panic("ebus_alloc: out of memory");	memset((char *)mem, 0, size);	return mem;}static void __init ebus_ranges_init(struct linux_ebus *ebus){	int success;	ebus->num_ebus_ranges = 0;	success = prom_getproperty(ebus->prom_node, "ranges",				   (char *)ebus->ebus_ranges,				   sizeof(ebus->ebus_ranges));	if (success != -1)		ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));}static void __init ebus_intmap_init(struct linux_ebus *ebus){	int success;	ebus->num_ebus_intmap = 0;	success = prom_getproperty(ebus->prom_node, "interrupt-map",				   (char *)ebus->ebus_intmap,				   sizeof(ebus->ebus_intmap));	if (success == -1)		return;	ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));	success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",				   (char *)&ebus->ebus_intmask,				   sizeof(ebus->ebus_intmask));	if (success == -1) {		prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);		prom_halt();	}}int __init ebus_intmap_match(struct linux_ebus *ebus,			     struct linux_prom_registers *reg,			     int *interrupt)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -