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

📄 pci_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",	    pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags);	pr = pci_find_parent_resource(dev, r);	if (!pr || request_resource(pr, r) < 0) {		printk(KERN_ERR "PCI: Cannot allocate resource region %d"		       " of device %s\n", idx, pci_name(dev));		if (pr)			DBG("PCI:  parent is %p: %016llx-%016llx (f=%lx)\n",			    pr, (u64)pr->start, (u64)pr->end, pr->flags);		/* We'll assign a new address later */		r->flags |= IORESOURCE_UNSET;		r->end -= r->start;		r->start = 0;	}}static void __initpcibios_allocate_resources(int pass){	struct pci_dev *dev = NULL;	int idx, disabled;	u16 command;	struct resource *r;	for_each_pci_dev(dev) {		pci_read_config_word(dev, PCI_COMMAND, &command);		for (idx = 0; idx < 6; idx++) {			r = &dev->resource[idx];			if (r->parent)		/* Already allocated */				continue;			if (!r->flags || (r->flags & IORESOURCE_UNSET))				continue;	/* Not assigned at all */			if (r->flags & IORESOURCE_IO)				disabled = !(command & PCI_COMMAND_IO);			else				disabled = !(command & PCI_COMMAND_MEMORY);			if (pass == disabled)				alloc_resource(dev, idx);		}		if (pass)			continue;		r = &dev->resource[PCI_ROM_RESOURCE];		if (r->flags & IORESOURCE_ROM_ENABLE) {			/* Turn the ROM off, leave the resource region, but keep it unregistered. */			u32 reg;			DBG("PCI: Switching off ROM of %s\n", pci_name(dev));			r->flags &= ~IORESOURCE_ROM_ENABLE;			pci_read_config_dword(dev, dev->rom_base_reg, &reg);			pci_write_config_dword(dev, dev->rom_base_reg,					       reg & ~PCI_ROM_ADDRESS_ENABLE);		}	}}static void __initpcibios_assign_resources(void){	struct pci_dev *dev = NULL;	int idx;	struct resource *r;	for_each_pci_dev(dev) {		int class = dev->class >> 8;		/* Don't touch classless devices and host bridges */		if (!class || class == PCI_CLASS_BRIDGE_HOST)			continue;		for (idx = 0; idx < 6; idx++) {			r = &dev->resource[idx];			/*			 * We shall assign a new address to this resource,			 * either because the BIOS (sic) forgot to do so			 * or because we have decided the old address was			 * unusable for some reason.			 */			if ((r->flags & IORESOURCE_UNSET) && r->end &&			    (!ppc_md.pcibios_enable_device_hook ||			     !ppc_md.pcibios_enable_device_hook(dev, 1))) {				int rc;				r->flags &= ~IORESOURCE_UNSET;				rc = pci_assign_resource(dev, idx);				BUG_ON(rc);			}		}#if 0 /* don't assign ROMs */		r = &dev->resource[PCI_ROM_RESOURCE];		r->end -= r->start;		r->start = 0;		if (r->end)			pci_assign_resource(dev, PCI_ROM_RESOURCE);#endif	}}#ifdef CONFIG_PPC_OF/* * Functions below are used on OpenFirmware machines. */static voidmake_one_node_map(struct device_node* node, u8 pci_bus){	const int *bus_range;	int len;	if (pci_bus >= pci_bus_count)		return;	bus_range = of_get_property(node, "bus-range", &len);	if (bus_range == NULL || len < 2 * sizeof(int)) {		printk(KERN_WARNING "Can't get bus-range for %s, "		       "assuming it starts at 0\n", node->full_name);		pci_to_OF_bus_map[pci_bus] = 0;	} else		pci_to_OF_bus_map[pci_bus] = bus_range[0];	for (node=node->child; node != 0;node = node->sibling) {		struct pci_dev* dev;		const unsigned int *class_code, *reg;			class_code = of_get_property(node, "class-code", NULL);		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))			continue;		reg = of_get_property(node, "reg", NULL);		if (!reg)			continue;		dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));		if (!dev || !dev->subordinate) {			pci_dev_put(dev);			continue;		}		make_one_node_map(node, dev->subordinate->number);		pci_dev_put(dev);	}}	voidpcibios_make_OF_bus_map(void){	int i;	struct pci_controller *hose, *tmp;	struct property *map_prop;	struct device_node *dn;	pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);	if (!pci_to_OF_bus_map) {		printk(KERN_ERR "Can't allocate OF bus map !\n");		return;	}	/* We fill the bus map with invalid values, that helps	 * debugging.	 */	for (i=0; i<pci_bus_count; i++)		pci_to_OF_bus_map[i] = 0xff;	/* For each hose, we begin searching bridges */	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {		struct device_node* node;			node = (struct device_node *)hose->arch_data;		if (!node)			continue;		make_one_node_map(node, hose->first_busno);	}	dn = of_find_node_by_path("/");	map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);	if (map_prop) {		BUG_ON(pci_bus_count > map_prop->length);		memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);	}	of_node_put(dn);#ifdef DEBUG	printk("PCI->OF bus map:\n");	for (i=0; i<pci_bus_count; i++) {		if (pci_to_OF_bus_map[i] == 0xff)			continue;		printk("%d -> %d\n", i, pci_to_OF_bus_map[i]);	}#endif}typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);static struct device_node*scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data){	struct device_node* sub_node;	for (; node != 0;node = node->sibling) {		const unsigned int *class_code;			if (filter(node, data))			return node;		/* For PCI<->PCI bridges or CardBus bridges, we go down		 * Note: some OFs create a parent node "multifunc-device" as		 * a fake root for all functions of a multi-function device,		 * we go down them as well.		 */		class_code = of_get_property(node, "class-code", NULL);		if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&			strcmp(node->name, "multifunc-device"))			continue;		sub_node = scan_OF_pci_childs(node->child, filter, data);		if (sub_node)			return sub_node;	}	return NULL;}static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,					       unsigned int devfn){	struct device_node *np = NULL;	const u32 *reg;	unsigned int psize;	while ((np = of_get_next_child(parent, np)) != NULL) {		reg = of_get_property(np, "reg", &psize);		if (reg == NULL || psize < 4)			continue;		if (((reg[0] >> 8) & 0xff) == devfn)			return np;	}	return NULL;}static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus){	struct device_node *parent, *np;	/* Are we a root bus ? */	if (bus->self == NULL || bus->parent == NULL) {		struct pci_controller *hose = pci_bus_to_host(bus);		if (hose == NULL)			return NULL;		return of_node_get(hose->arch_data);	}	/* not a root bus, we need to get our parent */	parent = scan_OF_for_pci_bus(bus->parent);	if (parent == NULL)		return NULL;	/* now iterate for children for a match */	np = scan_OF_for_pci_dev(parent, bus->self->devfn);	of_node_put(parent);	return np;}/* * Scans the OF tree for a device node matching a PCI device */struct device_node *pci_busdev_to_OF_node(struct pci_bus *bus, int devfn){	struct device_node *parent, *np;	if (!have_of)		return NULL;	DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);	parent = scan_OF_for_pci_bus(bus);	if (parent == NULL)		return NULL;	DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");	np = scan_OF_for_pci_dev(parent, devfn);	of_node_put(parent);	DBG(" result is %s\n", np ? np->full_name : "<NULL>");	/* XXX most callers don't release the returned node	 * mostly because ppc64 doesn't increase the refcount,	 * we need to fix that.	 */	return np;}EXPORT_SYMBOL(pci_busdev_to_OF_node);struct device_node*pci_device_to_OF_node(struct pci_dev *dev){	return pci_busdev_to_OF_node(dev->bus, dev->devfn);}EXPORT_SYMBOL(pci_device_to_OF_node);static intfind_OF_pci_device_filter(struct device_node* node, void* data){	return ((void *)node == data);}/* * Returns the PCI device matching a given OF node */intpci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn){	const unsigned int *reg;	struct pci_controller* hose;	struct pci_dev* dev = NULL;		if (!have_of)		return -ENODEV;	/* Make sure it's really a PCI device */	hose = pci_find_hose_for_OF_device(node);	if (!hose || !hose->arch_data)		return -ENODEV;	if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,			find_OF_pci_device_filter, (void *)node))		return -ENODEV;	reg = of_get_property(node, "reg", NULL);	if (!reg)		return -ENODEV;	*bus = (reg[0] >> 16) & 0xff;	*devfn = ((reg[0] >> 8) & 0xff);	/* Ok, here we need some tweak. If we have already renumbered	 * all busses, we can't rely on the OF bus number any more.	 * the pci_to_OF_bus_map is not enough as several PCI busses	 * may match the same OF bus number.	 */	if (!pci_to_OF_bus_map)		return 0;	for_each_pci_dev(dev)		if (pci_to_OF_bus_map[dev->bus->number] == *bus &&				dev->devfn == *devfn) {			*bus = dev->bus->number;			pci_dev_put(dev);			return 0;		}	return -ENODEV;}EXPORT_SYMBOL(pci_device_from_OF_node);void __initpci_process_bridge_OF_ranges(struct pci_controller *hose,			   struct device_node *dev, int primary){	static unsigned int static_lc_ranges[256] __initdata;	const unsigned int *dt_ranges;	unsigned int *lc_ranges, *ranges, *prev, size;	int rlen = 0, orig_rlen;	int memno = 0;	struct resource *res;	int np, na = of_n_addr_cells(dev);	np = na + 5;	/* First we try to merge ranges to fix a problem with some pmacs	 * that can have more than 3 ranges, fortunately using contiguous	 * addresses -- BenH	 */	dt_ranges = of_get_property(dev, "ranges", &rlen);	if (!dt_ranges)		return;	/* Sanity check, though hopefully that never happens */	if (rlen > sizeof(static_lc_ranges)) {		printk(KERN_WARNING "OF ranges property too large !\n");		rlen = sizeof(static_lc_ranges);	}	lc_ranges = static_lc_ranges;	memcpy(lc_ranges, dt_ranges, rlen);	orig_rlen = rlen;	/* Let's work on a copy of the "ranges" property instead of damaging	 * the device-tree image in memory	 */	ranges = lc_ranges;	prev = NULL;	while ((rlen -= np * sizeof(unsigned int)) >= 0) {		if (prev) {			if (prev[0] == ranges[0] && prev[1] == ranges[1] &&				(prev[2] + prev[na+4]) == ranges[2] &&				(prev[na+2] + prev[na+4]) == ranges[na+2]) {				prev[na+4] += ranges[na+4];				ranges[0] = 0;				ranges += np;				continue;			}		}		prev = ranges;		ranges += np;	}	/*	 * The ranges property is laid out as an array of elements,	 * each of which comprises:	 *   cells 0 - 2:	a PCI address	 *   cells 3 or 3+4:	a CPU physical address	 *			(size depending on dev->n_addr_cells)	 *   cells 4+5 or 5+6:	the size of the range	 */	ranges = lc_ranges;	rlen = orig_rlen;	while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {		res = NULL;		size = ranges[na+4];		switch ((ranges[0] >> 24) & 0x3) {		case 1:		/* I/O space */			if (ranges[2] != 0)				break;			hose->io_base_phys = ranges[na+2];			/* limit I/O space to 16MB */			if (size > 0x01000000)				size = 0x01000000;			hose->io_base_virt = ioremap(ranges[na+2], size);			if (primary)				isa_io_base = (unsigned long) hose->io_base_virt;			res = &hose->io_resource;			res->flags = IORESOURCE_IO;			res->start = ranges[2];			DBG("PCI: IO 0x%llx -> 0x%llx\n",			    (u64)res->start, (u64)res->start + size - 1);			break;		case 2:		/* memory space */			memno = 0;			if (ranges[1] == 0 && ranges[2] == 0			    && ranges[na+4] <= (16 << 20)) {				/* 1st 16MB, i.e. ISA memory area */				if (primary)					isa_mem_base = ranges[na+2];				memno = 1;			}			while (memno < 3 && hose->mem_resources[memno].flags)				++memno;			if (memno == 0)				hose->pci_mem_offset = ranges[na+2] - ranges[2];			if (memno < 3) {				res = &hose->mem_resources[memno];				res->flags = IORESOURCE_MEM;				if(ranges[0] & 0x40000000)					res->flags |= IORESOURCE_PREFETCH;				res->start = ranges[na+2];				DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno,				    (u64)res->start, (u64)res->start + size - 1);			}			break;		}		if (res != NULL) {			res->name = dev->full_name;			res->end = res->start + size - 1;			res->parent = NULL;			res->sibling = NULL;			res->child = NULL;		}		ranges += np;	}}/* We create the "pci-OF-bus-map" property now so it appears in the * /proc device tree */void __initpci_create_OF_bus_map(void){	struct property* of_prop;	struct device_node *dn;	of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);	if (!of_prop)		return;	dn = of_find_node_by_path("/");	if (dn) {		memset(of_prop, -1, sizeof(struct property) + 256);		of_prop->name = "pci-OF-bus-map";		of_prop->length = 256;		of_prop->value = &of_prop[1];		prom_add_property(dn, of_prop);		of_node_put(dn);	}}#else /* CONFIG_PPC_OF */void pcibios_make_OF_bus_map(void){}#endif /* CONFIG_PPC_OF */#ifdef CONFIG_PPC_PMAC/* * This set of routines checks for PCI<->PCI bridges that have closed * IO resources and have child devices. It tries to re-open an IO * window on them. * * This is a _temporary_ fix to workaround a problem with Apple's OF * closing IO windows on P2P bridges when the OF drivers of cards * below this bridge don't claim any IO range (typically ATI or * Adaptec). * * A more complete fix would be to use drivers/pci/setup-bus.c, which * involves a working pcibios_fixup_pbus_ranges(), some more care about * ordering when creating the host bus resources, and maybe a few more * minor tweaks */

⌨️ 快捷键说明

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