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

📄 pmac_pci.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
       	hose->first_busno = 0xf0;	hose->last_busno = 0xff;	has_uninorth = 1;	hose->ops = &macrisc_pci_ops;	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);	u3_agp = hose;}static void __init setup_u3_ht(struct pci_controller* hose){	struct device_node *np = (struct device_node *)hose->arch_data;	int i, cur;	hose->ops = &u3_ht_pci_ops;	/* We hard code the address because of the different size of	 * the reg address cell, we shall fix that by killing struct	 * reg_property and using some accessor functions instead	 */	hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);	/*	 * /ht node doesn't expose a "ranges" property, so we "remove" regions that	 * have been allocated to AGP. So far, this version of the code doesn't assign	 * any of the 0xfxxxxxxx "fine" memory regions to /ht.	 * We need to fix that sooner or later by either parsing all child "ranges"	 * properties or figuring out the U3 address space decoding logic and	 * then read it's configuration register (if any).	 */	hose->io_base_phys = 0xf4000000 + 0x00400000;	hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);	isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt;	hose->io_resource.name = np->full_name;	hose->io_resource.start = 0;	hose->io_resource.end = 0x003fffff;	hose->io_resource.flags = IORESOURCE_IO;	hose->pci_mem_offset = 0;	hose->first_busno = 0;	hose->last_busno = 0xef;	hose->mem_resources[0].name = np->full_name;	hose->mem_resources[0].start = 0x80000000;	hose->mem_resources[0].end = 0xefffffff;	hose->mem_resources[0].flags = IORESOURCE_MEM;	if (u3_agp == NULL) {		DBG("U3 has no AGP, using full resource range\n");		return;	}	/* We "remove" the AGP resources from the resources allocated to HT, that	 * is we create "holes". However, that code does assumptions that so far	 * happen to be true (cross fingers...), typically that resources in the	 * AGP node are properly ordered	 */	cur = 0;	for (i=0; i<3; i++) {		struct resource *res = &u3_agp->mem_resources[i];		if (res->flags != IORESOURCE_MEM)			continue;		/* We don't care about "fine" resources */		if (res->start >= 0xf0000000)			continue;		/* Check if it's just a matter of "shrinking" us in one direction */		if (hose->mem_resources[cur].start == res->start) {			DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",			    cur, hose->mem_resources[cur].start, res->end + 1);			hose->mem_resources[cur].start = res->end + 1;			continue;		}		if (hose->mem_resources[cur].end == res->end) {			DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",			    cur, hose->mem_resources[cur].end, res->start - 1);			hose->mem_resources[cur].end = res->start - 1;			continue;		}		/* No, it's not the case, we need a hole */		if (cur == 2) {			/* not enough resources for a hole, we drop part of the range */			printk(KERN_WARNING "Running out of resources for /ht host !\n");			hose->mem_resources[cur].end = res->start - 1;			continue;		}				cur++;       		DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",		    cur-1, res->start - 1, cur, res->end + 1);		hose->mem_resources[cur].name = np->full_name;		hose->mem_resources[cur].flags = IORESOURCE_MEM;		hose->mem_resources[cur].start = res->end + 1;		hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;		hose->mem_resources[cur-1].end = res->start - 1;	}}static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose,			   struct device_node *dev, int primary){	static unsigned int static_lc_ranges[2024];	unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;	unsigned int size;	int rlen = 0, orig_rlen;	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	 */	dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);	if (!dt_ranges)		return;	/*	lc_ranges = (unsigned int *) alloc_bootmem(rlen);*/	lc_ranges = static_lc_ranges;	if (!lc_ranges)		return; /* what can we do here ? */	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) {		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];			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 0				if (primary)					isa_mem_base = ranges[na+2];#endif				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 + size - 1;			res->parent = NULL;			res->sibling = NULL;			res->child = NULL;		}		ranges += np;	}}/* * We assume that if we have a G3 powermac, we have one bridge called * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */static int __init add_bridge(struct device_node *dev){	int len;	struct pci_controller *hose;	char* disp_name;	int *bus_range;	int primary = 1; 	struct property *of_prop;	DBG("Adding PCI host bridge %s\n", dev->full_name);       	bus_range = (int *) get_property(dev, "bus-range", &len);       	if (bus_range == NULL || len < 2 * sizeof(int)) {       		printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",       			       dev->full_name);       	}       	hose = pci_alloc_pci_controller(phb_type_apple);       	if (!hose)       		return -ENOMEM;       	hose->arch_data = dev;       	hose->first_busno = bus_range ? bus_range[0] : 0;       	hose->last_busno = bus_range ? bus_range[1] : 0xff;	of_prop = (struct property *)alloc_bootmem(sizeof(struct property) +			sizeof(hose->global_number));        	if (of_prop) {		memset(of_prop, 0, sizeof(struct property));		of_prop->name = "linux,pci-domain";		of_prop->length = sizeof(hose->global_number);		of_prop->value = (unsigned char *)&of_prop[1];		memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number));		prom_add_property(dev, of_prop);	}	disp_name = NULL;       	if (device_is_compatible(dev, "u3-agp")) {       		setup_u3_agp(hose);       		disp_name = "U3-AGP";       		primary = 0;       	} else if (device_is_compatible(dev, "u3-ht")) {       		setup_u3_ht(hose);       		disp_name = "U3-HT";       		primary = 1;       	}       	printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",       		disp_name, hose->first_busno, hose->last_busno);       	/* Interpret the "ranges" property */       	/* This also maps the I/O region and sets isa_io/mem_base */       	pmac_process_bridge_OF_ranges(hose, dev, primary);       	/* Fixup "bus-range" OF property */       	fixup_bus_range(dev);	return 0;}void __init pmac_pcibios_fixup(void){	struct pci_dev *dev = NULL;	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)		pci_read_irq_line(dev);	pci_fix_bus_sysdata();#ifdef CONFIG_PMAC_DART	iommu_setup_pmac();#endif /* CONFIG_PMAC_DART */}static void __init pmac_fixup_phb_resources(void){	struct pci_controller *hose;		for (hose = hose_head; hose; hose = hose->next) {		unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;		hose->io_resource.start += offset;		hose->io_resource.end += offset;		printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",		       hose->global_number,		       hose->io_resource.start, hose->io_resource.end);	}}void __init pmac_pci_init(void){	struct device_node *np, *root;	struct device_node *ht = NULL;	/* Probe root PCI hosts, that is on U3 the AGP host and the	 * HyperTransport host. That one is actually "kept" around	 * and actually added last as it's resource management relies	 * on the AGP resources to have been setup first	 */	root = of_find_node_by_path("/");	if (root == NULL) {		printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");		return;	}	for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {		if (np->name == NULL)			continue;		if (strcmp(np->name, "pci") == 0) {			if (add_bridge(np) == 0)				of_node_get(np);		}		if (strcmp(np->name, "ht") == 0) {			of_node_get(np);			ht = np;		}	}	of_node_put(root);	/* Now setup the HyperTransport host if we found any	 */	if (ht && add_bridge(ht) != 0)		of_node_put(ht);	/* Fixup the IO resources on our host bridges as the common code	 * does it only for childs of the host bridges	 */	pmac_fixup_phb_resources();	/* Setup the linkage between OF nodes and PHBs */ 	pci_devs_phb_init();	/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We	 * assume there is no P2P bridge on the AGP bus, which should be a	 * safe assumptions hopefully.	 */	if (u3_agp) {		struct device_node *np = u3_agp->arch_data;		np->busno = 0xf0;		for (np = np->child; np; np = np->sibling)			np->busno = 0xf0;	}	pmac_check_ht_link();	/* Tell pci.c to use the common resource allocation mecanism */	pci_probe_only = 0;		/* HT don't do more than 64 bytes transfers. FIXME: Deal with	 * the exception of U3/AGP (hook into pci_set_mwi)	 */	pci_cache_line_size = 16; /* 64 bytes */}/* * Disable second function on K2-SATA, it's broken * and disable IO BARs on first one */void fixup_k2_sata(struct pci_dev* dev){	int i;	u16 cmd;	if (PCI_FUNC(dev->devfn) > 0) {		pci_read_config_word(dev, PCI_COMMAND, &cmd);		cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);		pci_write_config_word(dev, PCI_COMMAND, cmd);		for (i = 0; i < 6; i++) {			dev->resource[i].start = dev->resource[i].end = 0;			dev->resource[i].flags = 0;			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);		}	} else {		pci_read_config_word(dev, PCI_COMMAND, &cmd);		cmd &= ~PCI_COMMAND_IO;		pci_write_config_word(dev, PCI_COMMAND, cmd);		for (i = 0; i < 5; i++) {			dev->resource[i].start = dev->resource[i].end = 0;			dev->resource[i].flags = 0;			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);		}	}}

⌨️ 快捷键说明

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