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

📄 pci.c

📁 LINUX 2.6.17.4的源码
💻 C
字号:
/* * arch/arm/mach-ixp23xx/pci.c * * PCI routines for IXP23XX based systems * * Copyright (c) 2005 MontaVista Software, Inc. * * based on original code: * * Author: Naeem Afzal <naeem.m.afzal@intel.com> * Copyright 2002-2005 Intel Corp. * * 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. */#include <linux/config.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/sizes.h>#include <asm/system.h>#include <asm/mach/pci.h>#include <asm/mach-types.h>#include <asm/hardware.h>extern int (*external_fault) (unsigned long, struct pt_regs *);static int pci_master_aborts = 0;#ifdef DEBUG#define DBG(x...)	printk(x)#else#define DBG(x...)#endifint clear_master_aborts(void);static u32*ixp23xx_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where){	u32 *paddress;	/*	 * Must be dword aligned	 */	where &= ~3;	/*	 * For top bus, generate type 0, else type 1	 */	if (!bus_nr) {		if (PCI_SLOT(devfn) >= 8)			return 0;		paddress = (u32 *) (IXP23XX_PCI_CFG0_VIRT				    | (1 << (PCI_SLOT(devfn) + 16))				    | (PCI_FUNC(devfn) << 8) | where);	} else {		paddress = (u32 *) (IXP23XX_PCI_CFG1_VIRT				    | (bus_nr << 16)				    | (PCI_SLOT(devfn) << 11)				    | (PCI_FUNC(devfn) << 8) | where);	}	return paddress;}/* * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes. * 0 and 3 are not valid indexes... */static u32 bytemask[] = {	/*0*/	0,	/*1*/	0xff,	/*2*/	0xffff,	/*3*/	0,	/*4*/	0xffffffff,};static int ixp23xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,				int where, int size, u32 *value){	u32 n;	u32 *addr;	n = where % 4;	DBG("In config_read(%d) %d from dev %d:%d:%d\n", size, where,		bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));	addr = ixp23xx_pci_config_addr(bus->number, devfn, where);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	pci_master_aborts = 0;	*value = (*addr >> (8*n)) & bytemask[size];	if (pci_master_aborts) {			pci_master_aborts = 0;			*value = 0xffffffff;			return PCIBIOS_DEVICE_NOT_FOUND;		}	return PCIBIOS_SUCCESSFUL;}/* * We don't do error checking on the address for writes. * It's assumed that the user checked for the device existing first * by doing a read first. */static int ixp23xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,					int where, int size, u32 value){	u32 mask;	u32 *addr;	u32 temp;	mask = ~(bytemask[size] << ((where % 0x4) * 8));	addr = ixp23xx_pci_config_addr(bus->number, devfn, where);	if (!addr)		return PCIBIOS_DEVICE_NOT_FOUND;	temp = (u32) (value) << ((where % 0x4) * 8);	*addr = (*addr & mask) | temp;	clear_master_aborts();	return PCIBIOS_SUCCESSFUL;}struct pci_ops ixp23xx_pci_ops = {	.read	= ixp23xx_pci_read_config,	.write	= ixp23xx_pci_write_config,};struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata){	return pci_scan_bus(sysdata->busnr, &ixp23xx_pci_ops, sysdata);}int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs){	volatile unsigned long temp;	unsigned long flags;	pci_master_aborts = 1;	local_irq_save(flags);	temp = *IXP23XX_PCI_CONTROL;	/*	 * master abort and cmd tgt err	 */	if (temp & ((1 << 8) | (1 << 5)))		*IXP23XX_PCI_CONTROL = temp;	temp = *IXP23XX_PCI_CMDSTAT;	if (temp & (1 << 29))		*IXP23XX_PCI_CMDSTAT = temp;	local_irq_restore(flags);	/*	 * If it was an imprecise abort, then we need to correct the	 * return address to be _after_ the instruction.	 */	if (fsr & (1 << 10))		regs->ARM_pc += 4;	return 0;}int clear_master_aborts(void){	volatile u32 temp;	temp = *IXP23XX_PCI_CONTROL;	/*	 * master abort and cmd tgt err	 */	if (temp & ((1 << 8) | (1 << 5)))		*IXP23XX_PCI_CONTROL = temp;	temp = *IXP23XX_PCI_CMDSTAT;	if (temp & (1 << 29))		*IXP23XX_PCI_CMDSTAT = temp;	return 0;}static void __init ixp23xx_pci_common_init(void){#ifdef __ARMEB__	*IXP23XX_PCI_CONTROL |= 0x20000;	/* set I/O swapping */#endif	/*	 * ADDR_31 needs to be clear for PCI memory access to CPP memory	 */	*IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_ADDR_31;	*IXP23XX_CPP2XSI_CURR_XFER_REG3 |= IXP23XX_CPP2XSI_PSH_OFF;	/*	 * Select correct memory for PCI inbound transactions	 */	if (ixp23xx_cpp_boot()) {		*IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1);	} else {		*IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1);		/*		 * Enable coherency on A2 silicon.		 */		if (arch_is_coherent())			*IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF;	}}void __init ixp23xx_pci_preinit(void){	ixp23xx_pci_common_init();	hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS,			"PCI config cycle to non-existent device");	*IXP23XX_PCI_ADDR_EXT = 0x0000e000;}/* * Prevent PCI layer from seeing the inbound host-bridge resources */static void __devinit pci_fixup_ixp23xx(struct pci_dev *dev){	int i;	dev->class &= 0xff;	dev->class |= PCI_CLASS_BRIDGE_HOST << 8;	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		dev->resource[i].start = 0;		dev->resource[i].end   = 0;		dev->resource[i].flags = 0;	}}DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9002, pci_fixup_ixp23xx);/* * IXP2300 systems often have large resource requirements, so we just * use our own resource space. */static struct resource ixp23xx_pci_mem_space = {	.start	= IXP23XX_PCI_MEM_START,	.end	= IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE - 1,	.flags	= IORESOURCE_MEM,	.name	= "PCI Mem Space"};static struct resource ixp23xx_pci_io_space = {	.start	= 0x00000100,	.end	= 0x01ffffff,	.flags	= IORESOURCE_IO,	.name	= "PCI I/O Space"};int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys){	if (nr >= 1)		return 0;	sys->resource[0] = &ixp23xx_pci_io_space;	sys->resource[1] = &ixp23xx_pci_mem_space;	sys->resource[2] = NULL;	return 1;}void ixp23xx_pci_slave_init(void){	ixp23xx_pci_common_init();}

⌨️ 快捷键说明

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