pci_64.c

来自「linux 内核源代码」· C语言 代码 · 共 990 行 · 第 1/2 页

C
990
字号
			       "on PCI domain %04x\n", hose->global_number);	}	mode = PCI_PROBE_NORMAL;	if (node && ppc_md.pci_probe_mode)		mode = ppc_md.pci_probe_mode(bus);	DBG("    probe mode: %d\n", mode);	if (mode == PCI_PROBE_DEVTREE) {		bus->subordinate = hose->last_busno;		of_scan_bus(node, bus);	}	if (mode == PCI_PROBE_NORMAL)		hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);}static int __init pcibios_init(void){	struct pci_controller *hose, *tmp;	/* For now, override phys_mem_access_prot. If we need it,	 * later, we may move that initialization to each ppc_md	 */	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;	if (firmware_has_feature(FW_FEATURE_ISERIES))		iSeries_pcibios_init();	printk(KERN_DEBUG "PCI: Probing PCI hardware\n");	/* Scan all of the recorded PCI controllers.  */	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {		scan_phb(hose);		pci_bus_add_devices(hose->bus);	}	if (!firmware_has_feature(FW_FEATURE_ISERIES)) {		if (pci_probe_only)			pcibios_claim_of_setup();		else			/* FIXME: `else' will be removed when			   pci_assign_unassigned_resources() is able to work			   correctly with [partially] allocated PCI tree. */			pci_assign_unassigned_resources();	}	/* Call machine dependent final fixup */	if (ppc_md.pcibios_fixup)		ppc_md.pcibios_fixup();	printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");	return 0;}subsys_initcall(pcibios_init);int pcibios_enable_device(struct pci_dev *dev, int mask){	u16 cmd, oldcmd;	int i;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	oldcmd = cmd;	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		struct resource *res = &dev->resource[i];		/* Only set up the requested stuff */		if (!(mask & (1<<i)))			continue;		if (res->flags & IORESOURCE_IO)			cmd |= PCI_COMMAND_IO;		if (res->flags & IORESOURCE_MEM)			cmd |= PCI_COMMAND_MEMORY;	}	if (cmd != oldcmd) {		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",		       pci_name(dev), cmd);                /* Enable the appropriate bits in the PCI command register.  */		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	return 0;}/* Decide whether to display the domain number in /proc */int pci_proc_domain(struct pci_bus *bus){	if (firmware_has_feature(FW_FEATURE_ISERIES))		return 0;	else {		struct pci_controller *hose = pci_bus_to_host(bus);		return hose->buid != 0;	}}void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,					    struct device_node *dev, int prim){	const unsigned int *ranges;	unsigned int pci_space;	unsigned long size;	int rlen = 0;	int memno = 0;	struct resource *res;	int np, na = of_n_addr_cells(dev);	unsigned long pci_addr, cpu_phys_addr;	np = na + 5;	/* From "PCI Binding to 1275"	 * 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 = of_get_property(dev, "ranges", &rlen);	if (ranges == NULL)		return;	hose->io_base_phys = 0;	while ((rlen -= np * sizeof(unsigned int)) >= 0) {		res = NULL;		pci_space = ranges[0];		pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2];		cpu_phys_addr = of_translate_address(dev, &ranges[3]);		size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4];		ranges += np;		if (size == 0)			continue;		/* Now consume following elements while they are contiguous */		while (rlen >= np * sizeof(unsigned int)) {			unsigned long addr, phys;			if (ranges[0] != pci_space)				break;			addr = ((unsigned long)ranges[1] << 32) | ranges[2];			phys = ranges[3];			if (na >= 2)				phys = (phys << 32) | ranges[4];			if (addr != pci_addr + size ||			    phys != cpu_phys_addr + size)				break;			size += ((unsigned long)ranges[na+3] << 32)				| ranges[na+4];			ranges += np;			rlen -= np * sizeof(unsigned int);		}		switch ((pci_space >> 24) & 0x3) {		case 1:		/* I/O space */			hose->io_base_phys = cpu_phys_addr - pci_addr;			/* handle from 0 to top of I/O window */			hose->pci_io_size = pci_addr + size;			res = &hose->io_resource;			res->flags = IORESOURCE_IO;			res->start = pci_addr;			DBG("phb%d: IO 0x%lx -> 0x%lx\n", hose->global_number,				    res->start, res->start + size - 1);			break;		case 2:		/* memory space */			memno = 0;			while (memno < 3 && hose->mem_resources[memno].flags)				++memno;			if (memno == 0)				hose->pci_mem_offset = cpu_phys_addr - pci_addr;			if (memno < 3) {				res = &hose->mem_resources[memno];				res->flags = IORESOURCE_MEM;				res->start = cpu_phys_addr;				DBG("phb%d: MEM 0x%lx -> 0x%lx\n", hose->global_number,					    res->start, 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;		}	}}#ifdef CONFIG_HOTPLUGint pcibios_unmap_io_space(struct pci_bus *bus){	struct pci_controller *hose;	WARN_ON(bus == NULL);	/* If this is not a PHB, we only flush the hash table over	 * the area mapped by this bridge. We don't play with the PTE	 * mappings since we might have to deal with sub-page alignemnts	 * so flushing the hash table is the only sane way to make sure	 * that no hash entries are covering that removed bridge area	 * while still allowing other busses overlapping those pages	 */	if (bus->self) {		struct resource *res = bus->resource[0];		DBG("IO unmapping for PCI-PCI bridge %s\n",		    pci_name(bus->self));		__flush_hash_table_range(&init_mm, res->start + _IO_BASE,					 res->end - res->start + 1);		return 0;	}	/* Get the host bridge */	hose = pci_bus_to_host(bus);	/* Check if we have IOs allocated */	if (hose->io_base_alloc == 0)		return 0;	DBG("IO unmapping for PHB %s\n",	    ((struct device_node *)hose->arch_data)->full_name);	DBG("  alloc=0x%p\n", hose->io_base_alloc);	/* This is a PHB, we fully unmap the IO area */	vunmap(hose->io_base_alloc);	return 0;}EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);#endif /* CONFIG_HOTPLUG */int __devinit pcibios_map_io_space(struct pci_bus *bus){	struct vm_struct *area;	unsigned long phys_page;	unsigned long size_page;	unsigned long io_virt_offset;	struct pci_controller *hose;	WARN_ON(bus == NULL);	/* If this not a PHB, nothing to do, page tables still exist and	 * thus HPTEs will be faulted in when needed	 */	if (bus->self) {		DBG("IO mapping for PCI-PCI bridge %s\n",		    pci_name(bus->self));		DBG("  virt=0x%016lx...0x%016lx\n",		    bus->resource[0]->start + _IO_BASE,		    bus->resource[0]->end + _IO_BASE);		return 0;	}	/* Get the host bridge */	hose = pci_bus_to_host(bus);	phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);	size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);	/* Make sure IO area address is clear */	hose->io_base_alloc = NULL;	/* If there's no IO to map on that bus, get away too */	if (hose->pci_io_size == 0 || hose->io_base_phys == 0)		return 0;	/* Let's allocate some IO space for that guy. We don't pass	 * VM_IOREMAP because we don't care about alignment tricks that	 * the core does in that case. Maybe we should due to stupid card	 * with incomplete address decoding but I'd rather not deal with	 * those outside of the reserved 64K legacy region.	 */	area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END);	if (area == NULL)		return -ENOMEM;	hose->io_base_alloc = area->addr;	hose->io_base_virt = (void __iomem *)(area->addr +					      hose->io_base_phys - phys_page);	DBG("IO mapping for PHB %s\n",	    ((struct device_node *)hose->arch_data)->full_name);	DBG("  phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",	    hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);	DBG("  size=0x%016lx (alloc=0x%016lx)\n",	    hose->pci_io_size, size_page);	/* Establish the mapping */	if (__ioremap_at(phys_page, area->addr, size_page,			 _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)		return -ENOMEM;	/* Fixup hose IO resource */	io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;	hose->io_resource.start += io_virt_offset;	hose->io_resource.end += io_virt_offset;	DBG("  hose->io_resource=0x%016lx...0x%016lx\n",	    hose->io_resource.start, hose->io_resource.end);	return 0;}EXPORT_SYMBOL_GPL(pcibios_map_io_space);static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev){	struct pci_controller *hose = pci_bus_to_host(dev->bus);	unsigned long offset;	if (res->flags & IORESOURCE_IO) {		offset = (unsigned long)hose->io_base_virt - _IO_BASE;		res->start += offset;		res->end += offset;	} else if (res->flags & IORESOURCE_MEM) {		res->start += hose->pci_mem_offset;		res->end += hose->pci_mem_offset;	}}void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,					      struct pci_bus *bus){	/* Update device resources.  */	int i;	DBG("%s: Fixup resources:\n", pci_name(dev));	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		struct resource *res = &dev->resource[i];		if (!res->flags)			continue;		DBG("  0x%02x < %08lx:0x%016lx...0x%016lx\n",		    i, res->flags, res->start, res->end);		fixup_resource(res, dev);		DBG("       > %08lx:0x%016lx...0x%016lx\n",		    res->flags, res->start, res->end);	}}EXPORT_SYMBOL(pcibios_fixup_device_resources);void __devinit pcibios_setup_new_device(struct pci_dev *dev){	struct dev_archdata *sd = &dev->dev.archdata;	sd->of_node = pci_device_to_OF_node(dev);	DBG("PCI device %s OF node: %s\n", pci_name(dev),	    sd->of_node ? sd->of_node->full_name : "<none>");	sd->dma_ops = pci_dma_ops;#ifdef CONFIG_NUMA	sd->numa_node = pcibus_to_node(dev->bus);#else	sd->numa_node = -1;#endif	if (ppc_md.pci_dma_dev_setup)		ppc_md.pci_dma_dev_setup(dev);}EXPORT_SYMBOL(pcibios_setup_new_device);static void __devinit do_bus_setup(struct pci_bus *bus){	struct pci_dev *dev;	if (ppc_md.pci_dma_bus_setup)		ppc_md.pci_dma_bus_setup(bus);	list_for_each_entry(dev, &bus->devices, bus_list)		pcibios_setup_new_device(dev);	/* 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);	}}void __devinit pcibios_fixup_bus(struct pci_bus *bus){	struct pci_dev *dev = bus->self;	struct device_node *np;	np = pci_bus_to_OF_node(bus);	DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>");	if (dev && pci_probe_only &&	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {		/* This is a subordinate bridge */		pci_read_bridge_bases(bus);		pcibios_fixup_device_resources(dev, bus);	}	do_bus_setup(bus);	if (!pci_probe_only)		return;	list_for_each_entry(dev, &bus->devices, bus_list)		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)			pcibios_fixup_device_resources(dev, bus);}EXPORT_SYMBOL(pcibios_fixup_bus);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) {		if (address >= hose->io_base_phys &&		    address < (hose->io_base_phys + hose->pci_io_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_GPL(pci_address_to_pio);#define IOBASE_BRIDGE_NUMBER	0#define IOBASE_MEMORY		1#define IOBASE_IO		2#define IOBASE_ISA_IO		3#define IOBASE_ISA_MEM		4long sys_pciconfig_iobase(long which, unsigned long in_bus,			  unsigned long in_devfn){	struct pci_controller* hose;	struct list_head *ln;	struct pci_bus *bus = NULL;	struct device_node *hose_node;	/* 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.	 */	if (machine_is_compatible("MacRISC4"))		if (in_bus == 0)			in_bus = 0xf0;	/* That syscall isn't quite compatible with PCI domains, but it's	 * used on pre-domains setup. We return the first match	 */	for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {		bus = pci_bus_b(ln);		if (in_bus >= bus->number && in_bus <= bus->subordinate)			break;		bus = NULL;	}	if (bus == NULL || bus->sysdata == NULL)		return -ENODEV;	hose_node = (struct device_node *)bus->sysdata;	hose = PCI_DN(hose_node)->phb;	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 -EINVAL;	}	return -EOPNOTSUPP;}#ifdef CONFIG_NUMAint pcibus_to_node(struct pci_bus *bus){	struct pci_controller *phb = pci_bus_to_host(bus);	return phb->node;}EXPORT_SYMBOL(pcibus_to_node);#endif

⌨️ 快捷键说明

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