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

📄 pci.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
			res->start = 0;			res->end = IO_SPACE_LIMIT;			res->flags = IORESOURCE_IO;		}		res->start += io_offset;		res->end += io_offset;		for (i = 0; i < 3; ++i) {			res = &hose->mem_resources[i];			if (!res->flags) {				if (i > 0)					continue;				printk(KERN_ERR "Memory resource not set for "				       "host bridge %d\n", hose->index);				res->start = hose->pci_mem_offset;				res->end = ~0U;				res->flags = IORESOURCE_MEM;			}			bus->resource[i+1] = res;		}	} else {		/* This is a subordinate bridge */		pci_read_bridge_bases(bus);		for (i = 0; i < 4; ++i) {			if ((res = bus->resource[i]) == NULL)				continue;			if (!res->flags)				continue;			if (io_offset && (res->flags & IORESOURCE_IO)) {				res->start += io_offset;				res->end += io_offset;			} else if (hose->pci_mem_offset				   && (res->flags & IORESOURCE_MEM)) {				res->start += hose->pci_mem_offset;				res->end += hose->pci_mem_offset;			}		}	}	if (ppc_md.pcibios_fixup_bus)		ppc_md.pcibios_fixup_bus(bus);}char __init *pcibios_setup(char *str){	return str;}/* the next one is stolen from the alpha port... */void __initpcibios_update_irq(struct pci_dev *dev, int irq){	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);	/* XXX FIXME - update OF device tree node interrupt property */}int pcibios_enable_device(struct pci_dev *dev){	u16 cmd, old_cmd;	int idx;	struct resource *r;	if (ppc_md.pcibios_enable_device_hook)		if (ppc_md.pcibios_enable_device_hook(dev, 0))			return -EINVAL;				pci_read_config_word(dev, PCI_COMMAND, &cmd);	old_cmd = cmd;	for (idx=0; idx<6; idx++) {		r = &dev->resource[idx];		if (!r->start && r->end) {			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);			return -EINVAL;		}		if (r->flags & IORESOURCE_IO)			cmd |= PCI_COMMAND_IO;		if (r->flags & IORESOURCE_MEM)			cmd |= PCI_COMMAND_MEMORY;	}	if (cmd != old_cmd) {		printk("PCI: Enabling device %s (%04x -> %04x)\n",		       dev->slot_name, old_cmd, cmd);		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	return 0;}struct pci_controller*pci_bus_to_hose(int bus){	struct pci_controller* hose = hose_head;	for (; hose; hose = hose->next)		if (bus >= hose->first_busno && bus <= hose->last_busno)			return hose;	return NULL;}void*pci_bus_io_base(unsigned int bus){	struct pci_controller *hose;	hose = pci_bus_to_hose(bus);	if (!hose)		return NULL;	return hose->io_base_virt;}unsigned longpci_bus_io_base_phys(unsigned int bus){	struct pci_controller *hose;	hose = pci_bus_to_hose(bus);	if (!hose)		return 0;	return hose->io_base_phys;}unsigned longpci_bus_mem_base_phys(unsigned int bus){	struct pci_controller *hose;	hose = pci_bus_to_hose(bus);	if (!hose)		return 0;	return hose->pci_mem_offset;}unsigned longpci_resource_to_bus(struct pci_dev *pdev, struct resource *res){	/* Hack alert again ! See comments in chrp_pci.c	 */	struct pci_controller* hose =		(struct pci_controller *)pdev->sysdata;	if (hose && res->flags & IORESOURCE_MEM)		return res->start - hose->pci_mem_offset;	/* We may want to do something with IOs here... */	return res->start;}/* * Return the index of the PCI controller for device pdev. */int pci_controller_num(struct pci_dev *dev){	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;	return hose->index;}/* * Platform support for /proc/bus/pci/X/Y mmap()s, * modelled on the sparc64 implementation by Dave Miller. *  -- paulus. *//* * Adjust vm_pgoff of VMA such that it is the physical page offset * corresponding to the 32-bit pci bus offset for DEV requested by the user. * * Basically, the user finds the base address for his device which he wishes * to mmap.  They read the 32-bit value from the config space base register, * add whatever PAGE_SIZE multiple offset they wish, and feed this into the * offset parameter of mmap on /proc/bus/pci/XXX for that device. * * Returns negative error code on failure, zero on success. */static __inline__ int__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,		       enum pci_mmap_state mmap_state){	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;	unsigned long io_offset = 0;	int i, res_bit;	if (hose == 0)		return -EINVAL;		/* should never happen */	/* If memory, add on the PCI bridge address offset */	if (mmap_state == pci_mmap_mem) {		offset += hose->pci_mem_offset;		res_bit = IORESOURCE_MEM;	} else {		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;		offset += io_offset;		res_bit = IORESOURCE_IO;	}	/*	 * Check that the offset requested corresponds to one of the	 * resources of the device.	 */	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {		struct resource *rp = &dev->resource[i];		int flags = rp->flags;		/* treat ROM as memory (should be already) */		if (i == PCI_ROM_RESOURCE)			flags |= IORESOURCE_MEM;		/* Active and same type? */		if ((flags & res_bit) == 0)			continue;		/* In the range of this resource? */		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)			continue;		/* found it! construct the final physical address */		if (mmap_state == pci_mmap_io)			offset += hose->io_base_phys - io_offset;		vma->vm_pgoff = offset >> PAGE_SHIFT;		return 0;	}	return -EINVAL;}/* * Set vm_flags of VMA, as appropriate for this architecture, for a pci device * mapping. */static __inline__ void__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,		     enum pci_mmap_state mmap_state){	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;}/* * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci * device mapping. */static __inline__ void__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,		      enum pci_mmap_state mmap_state, int write_combine){	int prot = pgprot_val(vma->vm_page_prot);	/* XXX would be nice to have a way to ask for write-through */	prot |= _PAGE_NO_CACHE;	if (!write_combine)		prot |= _PAGE_GUARDED;	vma->vm_page_prot = __pgprot(prot);}/* * Perform the actual remap of the pages for a PCI device mapping, as * appropriate for this architecture.  The region in the process to map * is described by vm_start and vm_end members of VMA, the base physical * address is found in vm_pgoff. * The pci device structure is provided so that architectures may make mapping * decisions on a per-device or per-bus basis. * * Returns a negative error code on failure, zero on success. */int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,			enum pci_mmap_state mmap_state,			int write_combine){	int ret;	ret = __pci_mmap_make_offset(dev, vma, mmap_state);	if (ret < 0)		return ret;	__pci_mmap_set_flags(dev, vma, mmap_state);	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);	ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,			       vma->vm_end - vma->vm_start, vma->vm_page_prot);	return ret;}/* Obsolete functions. Should be removed once the symbios driver * is fixed */unsigned longphys_to_bus(unsigned long pa){	struct pci_controller *hose;	int i;	for (hose = hose_head; hose; hose = hose->next) {		for (i = 0; i < 3; ++i) {			if (pa >= hose->mem_resources[i].start			    && pa <= hose->mem_resources[i].end) {				/*				 * XXX the hose->pci_mem_offset really				 * only applies to mem_resources[0].				 * We need a way to store an offset for				 * the others.  -- paulus				 */				if (i == 0)					pa -= hose->pci_mem_offset;				return pa;			}		}	}	/* hmmm, didn't find it */	return 0;}unsigned longpci_phys_to_bus(unsigned long pa, int busnr){	struct pci_controller* hose = pci_bus_to_hose(busnr);	if (!hose)		return pa;	return pa - hose->pci_mem_offset;}unsigned longpci_bus_to_phys(unsigned int ba, int busnr){	struct pci_controller* hose = pci_bus_to_hose(busnr);	if (!hose)		return ba;	return ba + hose->pci_mem_offset;}/* Provide information on locations of various I/O regions in physical * memory.  Do this on a per-card basis so that we choose the right * root bridge. * Note that the returned IO or memory base is a physical address */longsys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn){	struct pci_controller* hose = pci_bus_to_hose(bus);	long result = -EOPNOTSUPP;	if (!hose)		return -ENODEV;		switch (which) {	case IOBASE_BRIDGE_NUMBER:		return (long)hose->first_busno;	case IOBASE_MEMORY:		return (long)hose->pci_mem_offset;	case IOBASE_IO:		return (long)hose->io_base_phys;	case IOBASE_ISA_IO:		return (long)isa_io_base;	case IOBASE_ISA_MEM:		return (long)isa_mem_base;	}	return result;}/* * Null PCI config access functions, for the case when we can't * find a hose. */#define NULL_PCI_OP(rw, size, type)					\static int								\null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\{									\	return PCIBIOS_DEVICE_NOT_FOUND;    				\}NULL_PCI_OP(read, byte, u8 *)NULL_PCI_OP(read, word, u16 *)NULL_PCI_OP(read, dword, u32 *)NULL_PCI_OP(write, byte, u8)NULL_PCI_OP(write, word, u16)NULL_PCI_OP(write, dword, u32)static struct pci_ops null_pci_ops ={	null_read_config_byte,	null_read_config_word,	null_read_config_dword,	null_write_config_byte,	null_write_config_word,	null_write_config_dword};/* * These functions are used early on before PCI scanning is done * and all of the pci_dev and pci_bus structures have been created. */static struct pci_dev *fake_pci_dev(struct pci_controller *hose, int busnr, int devfn){	static struct pci_dev dev;	static struct pci_bus bus;	if (hose == 0) {		hose = pci_bus_to_hose(busnr);		if (hose == 0)			printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);	}	dev.bus = &bus;	dev.sysdata = hose;	dev.devfn = devfn;	bus.number = busnr;	bus.ops = hose? hose->ops: &null_pci_ops;	return &dev;}#define EARLY_PCI_OP(rw, size, type)					\int early_##rw##_config_##size(struct pci_controller *hose, int bus,	\			       int devfn, int offset, type value)	\{									\	return pci_##rw##_config_##size(fake_pci_dev(hose, bus, devfn),	\					offset, value);			\}EARLY_PCI_OP(read, byte, u8 *)EARLY_PCI_OP(read, word, u16 *)EARLY_PCI_OP(read, dword, u32 *)EARLY_PCI_OP(write, byte, u8)EARLY_PCI_OP(write, word, u16)EARLY_PCI_OP(write, dword, u32)

⌨️ 快捷键说明

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