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

📄 pci.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	return 0;}static int next_controller_index;struct pci_controller * __initpcibios_alloc_controller(void){	struct pci_controller *hose;	hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose));	memset(hose, 0, sizeof(struct pci_controller));		*hose_tail = hose;	hose_tail = &hose->next;	hose->index = next_controller_index++;	return hose;}#ifdef CONFIG_ALL_PPC/* * Functions below are used on OpenFirmware machines. */static void __openfirmwaremake_one_node_map(struct device_node* node, u8 pci_bus){	int *bus_range;	int len;		if (pci_bus >= pci_bus_count)		return;	bus_range = (int *) get_property(node, "bus-range", &len);	if (bus_range == NULL || len < 2 * sizeof(int)) {		printk(KERN_WARNING "Can't get bus-range for %s\n",			       node->full_name);		return;	}	pci_to_OF_bus_map[pci_bus] = bus_range[0];		for (node=node->child; node != 0;node = node->sibling) {		struct pci_dev* dev;		unsigned int *class_code, *reg;				class_code = (unsigned int *) get_property(node, "class-code", 0);		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))			continue;		reg = (unsigned int *)get_property(node, "reg", 0);		if (!reg)			continue;		dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));		if (!dev || !dev->subordinate)			continue;		make_one_node_map(node, dev->subordinate->number);	}}		void __openfirmwarepcibios_make_OF_bus_map(void){	int i;	struct pci_controller* hose;	u8* of_prop_map;		pci_to_OF_bus_map = (u8*)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 */	for(hose=hose_head; hose; hose=hose->next) {		struct device_node* node;				node = (struct device_node *)hose->arch_data;		if (!node)			continue;		make_one_node_map(node, hose->first_busno);	}	of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", 0);	if (of_prop_map)		memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);#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* __openfirmwarescan_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) {		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 = (unsigned int *) get_property(node, "class-code", 0);		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 intscan_OF_pci_childs_iterator(struct device_node* node, void* data){	unsigned int *reg;	u8* fdata = (u8*)data;			reg = (unsigned int *) get_property(node, "reg", 0);	if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]		&& ((reg[0] >> 16) & 0xff) == fdata[0])		return 1;	return 0;}static struct device_node* __openfirmwarescan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn){	u8 filter_data[2] = {bus, dev_fn};	return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);}/*  * Scans the OF tree for a device node matching a PCI device */struct device_node*pci_device_to_OF_node(struct pci_dev *dev){	struct pci_controller *hose;	struct device_node *node;	int bus;		if (!have_of)		return NULL;			/* Lookup the hose */	bus = dev->bus->number;	hose = pci_bus_to_hose(bus);	if (!hose)		return NULL;	/* Check it has an OF node associated */	node = (struct device_node *) hose->arch_data;	if (!node)		return NULL;	/* Fixup bus number according to what OF think it is. */	if (pci_to_OF_bus_map)		bus = pci_to_OF_bus_map[bus];	if (bus == 0xff)		return NULL;			/* Now, lookup childs of the hose */	return scan_OF_childs_for_device(node->child, bus, dev->devfn);}/* This routine is meant to be used early during boot, when the * PCI bus numbers have not yet been assigned, and you need to * issue PCI config cycles to an OF device. * It could also be used to "fix" RTAS config cycles if you want * to set pci_assign_all_busses to 1 and still use RTAS for PCI * config cycles. */struct pci_controller*pci_find_hose_for_OF_device(struct device_node* node){	if (!have_of)		return NULL;	while(node) {		struct pci_controller* hose;		for (hose=hose_head;hose;hose=hose->next)			if (hose->arch_data == node)				return hose;		node=node->parent;	}	return NULL;}static int __openfirmwarefind_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){	unsigned int *reg;	struct pci_controller* hose;	struct pci_dev* dev;			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 = (unsigned int *) get_property(node, "reg", 0);	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;	pci_for_each_dev(dev) {		if (pci_to_OF_bus_map[dev->bus->number] != *bus)			continue;		if (dev->devfn != *devfn)			continue;		*bus = dev->bus->number;		return 0;	}	return -ENODEV;}void __initpci_process_bridge_OF_ranges(struct pci_controller *hose,			   struct device_node *dev, int primary){	unsigned int *ranges, *prev;	int rlen = 0;	int memno = 0;	struct resource *res;	int np, na = prom_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	 */	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);	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	 */	rlen = 0;	hose->io_base_phys = 0;	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);	while ((rlen -= np * sizeof(unsigned int)) >= 0) {		res = NULL;		switch (ranges[0] >> 24) {		case 1:		/* I/O space */			if (ranges[2] != 0)				break;			hose->io_base_phys = ranges[na+2];			hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]);			if (primary)				isa_io_base = (unsigned long) hose->io_base_virt;			res = &hose->io_resource;			res->flags = IORESOURCE_IO;			res->start = ranges[2];			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;				res->start = ranges[na+2];			}			break;		}		if (res != NULL) {			res->name = dev->full_name;			res->end = res->start + ranges[na+4] - 1;			res->parent = NULL;			res->sibling = NULL;			res->child = NULL;		}		ranges += np;	}}#endif /* CONFIG_ALL_PPC */void __initpcibios_init(void){	struct pci_controller *hose;	struct pci_bus *bus;	int next_busno;	printk(KERN_INFO "PCI: Probing PCI hardware\n");	/* Scan all of the recorded PCI controllers.  */	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {		if (pci_assign_all_busses)			hose->first_busno = next_busno;		hose->last_busno = 0xff;		bus = pci_scan_bus(hose->first_busno, hose->ops, hose);		hose->last_busno = bus->subordinate;		if (pci_assign_all_busses || next_busno <= hose->last_busno)			next_busno = hose->last_busno+1;	}	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_busses && have_of)		pcibios_make_OF_bus_map();	/* Call machine dependant 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);	pcibios_assign_resources();	/* Call machine dependent post-init code */	if (ppc_md.pcibios_after_init)		ppc_md.pcibios_after_init();}int __initpcibios_assign_all_busses(void){	return pci_assign_all_busses;}void __initpcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges){	ranges->io_start -= bus->resource[0]->start;	ranges->io_end -= bus->resource[0]->start;	ranges->mem_start -= bus->resource[1]->start;	ranges->mem_end -= bus->resource[1]->start;}unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,			     unsigned long start, unsigned long size){	return start;}void __init pcibios_fixup_bus(struct pci_bus *bus){	struct pci_controller *hose = (struct pci_controller *) bus->sysdata;	unsigned long io_offset;	struct resource *res;	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->index);

⌨️ 快捷键说明

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