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

📄 pci_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Initialize bridges with base/limit values we have collected */static void __initdo_update_p2p_io_resource(struct pci_bus *bus, int enable_vga){	struct pci_dev *bridge = bus->self;	struct pci_controller* hose = (struct pci_controller *)bridge->sysdata;	u32 l;	u16 w;	struct resource res;	if (bus->resource[0] == NULL)		return; 	res = *(bus->resource[0]);	DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));	res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);	res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);	DBG("  IO window: %016llx-%016llx\n", res.start, res.end);	/* Set up the top and bottom of the PCI I/O segment for this bus. */	pci_read_config_dword(bridge, PCI_IO_BASE, &l);	l &= 0xffff000f;	l |= (res.start >> 8) & 0x00f0;	l |= res.end & 0xf000;	pci_write_config_dword(bridge, PCI_IO_BASE, l);	if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {		l = (res.start >> 16) | (res.end & 0xffff0000);		pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l);	}	pci_read_config_word(bridge, PCI_COMMAND, &w);	w |= PCI_COMMAND_IO;	pci_write_config_word(bridge, PCI_COMMAND, w);#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */	if (enable_vga) {		pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);		w |= PCI_BRIDGE_CTL_VGA;		pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);	}#endif}/* This function is pretty basic and actually quite broken for the * general case, it's enough for us right now though. It's supposed * to tell us if we need to open an IO range at all or not and what * size. */static int __initcheck_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga){	struct pci_dev *dev;	int	i;	int	rc = 0;#define push_end(res, mask) do {		\	BUG_ON((mask+1) & mask);		\	res->end = (res->end + mask) | mask;	\} while (0)	list_for_each_entry(dev, &bus->devices, bus_list) {		u16 class = dev->class >> 8;		if (class == PCI_CLASS_DISPLAY_VGA ||		    class == PCI_CLASS_NOT_DEFINED_VGA)			*found_vga = 1;		if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)			rc |= check_for_io_childs(dev->subordinate, res, found_vga);		if (class == PCI_CLASS_BRIDGE_CARDBUS)			push_end(res, 0xfff);		for (i=0; i<PCI_NUM_RESOURCES; i++) {			struct resource *r;			unsigned long r_size;			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI			    && i >= PCI_BRIDGE_RESOURCES)				continue;			r = &dev->resource[i];			r_size = r->end - r->start;			if (r_size < 0xfff)				r_size = 0xfff;			if (r->flags & IORESOURCE_IO && (r_size) != 0) {				rc = 1;				push_end(res, r_size);			}		}	}	return rc;}/* Here we scan all P2P bridges of a given level that have a closed * IO window. Note that the test for the presence of a VGA card should * be improved to take into account already configured P2P bridges, * currently, we don't see them and might end up configuring 2 bridges * with VGA pass through enabled */static void __initdo_fixup_p2p_level(struct pci_bus *bus){	struct pci_bus *b;	int i, parent_io;	int has_vga = 0;	for (parent_io=0; parent_io<4; parent_io++)		if (bus->resource[parent_io]		    && bus->resource[parent_io]->flags & IORESOURCE_IO)			break;	if (parent_io >= 4)		return;	list_for_each_entry(b, &bus->children, node) {		struct pci_dev *d = b->self;		struct pci_controller* hose = (struct pci_controller *)d->sysdata;		struct resource *res = b->resource[0];		struct resource tmp_res;		unsigned long max;		int found_vga = 0;		memset(&tmp_res, 0, sizeof(tmp_res));		tmp_res.start = bus->resource[parent_io]->start;		/* We don't let low addresses go through that closed P2P bridge, well,		 * that may not be necessary but I feel safer that way		 */		if (tmp_res.start == 0)			tmp_res.start = 0x1000;			if (!list_empty(&b->devices) && res && res->flags == 0 &&		    res != bus->resource[parent_io] &&		    (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&		    check_for_io_childs(b, &tmp_res, &found_vga)) {			u8 io_base_lo;			printk(KERN_INFO "Fixing up IO bus %s\n", b->name);			if (found_vga) {				if (has_vga) {					printk(KERN_WARNING "Skipping VGA, already active"					    " on bus segment\n");					found_vga = 0;				} else					has_vga = 1;			}			pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);			if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)				max = ((unsigned long) hose->io_base_virt					- isa_io_base) + 0xffffffff;			else				max = ((unsigned long) hose->io_base_virt					- isa_io_base) + 0xffff;			*res = tmp_res;			res->flags = IORESOURCE_IO;			res->name = b->name;					/* Find a resource in the parent where we can allocate */			for (i = 0 ; i < 4; i++) {				struct resource *r = bus->resource[i];				if (!r)					continue;				if ((r->flags & IORESOURCE_IO) == 0)					continue;				DBG("Trying to allocate from %016llx, size %016llx from parent"				    " res %d: %016llx -> %016llx\n",					res->start, res->end, i, r->start, r->end);							if (allocate_resource(r, res, res->end + 1, res->start, max,				    res->end + 1, NULL, NULL) < 0) {					DBG("Failed !\n");					continue;				}				do_update_p2p_io_resource(b, found_vga);				break;			}		}		do_fixup_p2p_level(b);	}}static voidpcibios_fixup_p2p_bridges(void){	struct pci_bus *b;	list_for_each_entry(b, &pci_root_buses, node)		do_fixup_p2p_level(b);}#endif /* CONFIG_PPC_PMAC */static int __initpcibios_init(void){	struct pci_controller *hose, *tmp;	struct pci_bus *bus;	int next_busno = 0;	printk(KERN_INFO "PCI: Probing PCI hardware\n");	/* Scan all of the recorded PCI controllers.  */	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {		if (pci_assign_all_buses)			hose->first_busno = next_busno;		hose->last_busno = 0xff;		bus = pci_scan_bus_parented(hose->parent, hose->first_busno,					    hose->ops, hose);		if (bus)			pci_bus_add_devices(bus);		hose->last_busno = bus->subordinate;		if (pci_assign_all_buses || next_busno <= hose->last_busno)			next_busno = hose->last_busno + pcibios_assign_bus_offset;	}	pci_bus_count = next_busno;	/* OpenFirmware based machines need a map of OF bus	 * numbers vs. kernel bus numbers since we may have to	 * remap them.	 */	if (pci_assign_all_buses && have_of)		pcibios_make_OF_bus_map();	/* Call machine dependent fixup */	if (ppc_md.pcibios_fixup)		ppc_md.pcibios_fixup();	/* Allocate and assign resources */	pcibios_allocate_bus_resources(&pci_root_buses);	pcibios_allocate_resources(0);	pcibios_allocate_resources(1);#ifdef CONFIG_PPC_PMAC	pcibios_fixup_p2p_bridges();#endif /* CONFIG_PPC_PMAC */	pcibios_assign_resources();	/* Call machine dependent post-init code */	if (ppc_md.pcibios_after_init)		ppc_md.pcibios_after_init();	return 0;}subsys_initcall(pcibios_init);void pcibios_fixup_bus(struct pci_bus *bus){	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;	unsigned long io_offset;	struct resource *res;	struct pci_dev *dev;	int i;	io_offset = (unsigned long)hose->io_base_virt - isa_io_base;	if (bus->parent == NULL) {		/* This is a host bridge - fill in its resources */		hose->bus = bus;		bus->resource[0] = res = &hose->io_resource;		if (!res->flags) {			if (io_offset)				printk(KERN_ERR "I/O resource not set for host"				       " bridge %d\n", hose->global_number);			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->global_number);				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 || bus->self->transparent)				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;			}		}	}	/* Platform specific bus fixups */	if (ppc_md.pcibios_fixup_bus)		ppc_md.pcibios_fixup_bus(bus);	/* Read default IRQs and fixup if necessary */	list_for_each_entry(dev, &bus->devices, bus_list) {		pci_read_irq_line(dev);		if (ppc_md.pci_irq_fixup)			ppc_md.pci_irq_fixup(dev);	}}/* 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, int mask){	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->flags & IORESOURCE_UNSET) {			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));			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",		       pci_name(dev), old_cmd, cmd);		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	return 0;}static struct pci_controller*pci_bus_to_hose(int bus){	struct pci_controller *hose, *tmp;	list_for_each_entry_safe(hose, tmp, &hose_list, list_node)		if (bus >= hose->first_busno && bus <= hose->last_busno)			return hose;	return NULL;}/* 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 */long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn){	struct pci_controller* hose;	long result = -EOPNOTSUPP;	/* Argh ! Please forgive me for that hack, but that's the	 * simplest way to get existing XFree to not lockup on some	 * G5 machines... So when something asks for bus 0 io base	 * (bus 0 is HT root), we return the AGP one instead.	 */#ifdef CONFIG_PPC_PMAC	if (machine_is(powermac) && machine_is_compatible("MacRISC4"))		if (bus == 0)			bus = 0xf0;#endif /* CONFIG_PPC_PMAC */	hose = pci_bus_to_hose(bus);	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;}unsigned long pci_address_to_pio(phys_addr_t address){	struct pci_controller *hose, *tmp;	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {		unsigned int size = hose->io_resource.end -			hose->io_resource.start + 1;		if (address >= hose->io_base_phys &&		    address < (hose->io_base_phys + size)) {			unsigned long base =				(unsigned long)hose->io_base_virt - _IO_BASE;			return base + (address - hose->io_base_phys);		}	}	return (unsigned int)-1;}EXPORT_SYMBOL(pci_address_to_pio);/* * 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;    				\}static intnull_read_config(struct pci_bus *bus, unsigned int devfn, int offset,		 int len, u32 *val){	return PCIBIOS_DEVICE_NOT_FOUND;}static intnull_write_config(struct pci_bus *bus, unsigned int devfn, int offset,		  int len, u32 val){	return PCIBIOS_DEVICE_NOT_FOUND;}static struct pci_ops null_pci_ops ={	.read = null_read_config,	.write = null_write_config,};/* * 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_bus *fake_pci_bus(struct pci_controller *hose, int busnr){	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);	}	bus.number = busnr;	bus.sysdata = hose;	bus.ops = hose? hose->ops: &null_pci_ops;	return &bus;}#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_bus_##rw##_config_##size(fake_pci_bus(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)extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);int early_find_capability(struct pci_controller *hose, int bus, int devfn,			  int cap){	return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);}

⌨️ 快捷键说明

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