pseries_pci.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 800 行 · 第 1/2 页

C
800
字号
	struct reg_property64 reg_struct;	int *bus_range;	char *model;	enum phb_types phb_type; 	struct property *of_prop;	model = (char *)get_property(dev, "model", NULL);	if (!model) {		printk(KERN_ERR "alloc_phb: phb has no model property\n");		model = "<empty>";	}	/* Found a PHB, now figure out where his registers are mapped. */	ui_ptr = (unsigned int *) get_property(dev, "reg", &len);	if (ui_ptr == NULL) {		PPCDBG(PPCDBG_PHBINIT, "\tget reg failed.\n"); 		return NULL;	}	if (addr_size_words == 1) {		reg_struct.address = ((struct reg_property32 *)ui_ptr)->address;		reg_struct.size    = ((struct reg_property32 *)ui_ptr)->size;	} else {		reg_struct = *((struct reg_property64 *)ui_ptr);	}	if (strstr(model, "Python")) {		phb_type = phb_type_python;	} else if (strstr(model, "Speedwagon")) {		phb_type = phb_type_speedwagon;	} else if (strstr(model, "Winnipeg")) {		phb_type = phb_type_winnipeg;	} else {		printk(KERN_ERR "alloc_phb: unknown PHB %s\n", model);		phb_type = phb_type_unknown;	}	phb = pci_alloc_pci_controller(phb_type);	if (phb == NULL)		return NULL;	if (phb_type == phb_type_python)		python_countermeasures(reg_struct.address);	bus_range = (int *) get_property(dev, "bus-range", &len);	if (bus_range == NULL || len < 2 * sizeof(int)) {		kfree(phb);		return NULL;	}	of_prop = (struct property *)alloc_bootmem(sizeof(struct property) +			sizeof(phb->global_number));        	if (!of_prop) {		kfree(phb);		return NULL;	}	memset(of_prop, 0, sizeof(struct property));	of_prop->name = "linux,pci-domain";	of_prop->length = sizeof(phb->global_number);	of_prop->value = (unsigned char *)&of_prop[1];	memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number));	prom_add_property(dev, of_prop);	phb->first_busno =  bus_range[0];	phb->last_busno  =  bus_range[1];	phb->arch_data   = dev;	phb->ops = &rtas_pci_ops;	phb->buid = get_phb_buid(dev);	return phb;}unsigned long __init find_and_init_phbs(void){	struct device_node *node;	struct pci_controller *phb;	unsigned int root_size_cells = 0;	unsigned int index;	unsigned int *opprop;	struct device_node *root = of_find_node_by_path("/");	if (naca->interrupt_controller == IC_OPEN_PIC) {		opprop = (unsigned int *)get_property(root,				"platform-open-pic", NULL);	}	root_size_cells = prom_n_size_cells(root);	index = 0;	for (node = of_get_next_child(root, NULL);	     node != NULL;	     node = of_get_next_child(root, node)) {		if (node->type == NULL || strcmp(node->type, "pci") != 0)			continue;		phb = alloc_phb(node, root_size_cells);		if (!phb)			continue;		pci_process_bridge_OF_ranges(phb, node, index == 0);		if (naca->interrupt_controller == IC_OPEN_PIC) {			int addr = root_size_cells * (index + 2) - 1;			openpic_setup_ISU(index, opprop[addr]); 		}		index++;	}	of_node_put(root);	pci_devs_phb_init();	return 0;}void pcibios_name_device(struct pci_dev *dev){#if 0	struct device_node *dn;	/*	 * Add IBM loc code (slot) as a prefix to the device names for service	 */	dn = pci_device_to_OF_node(dev);	if (dn) {		char *loc_code = get_property(dn, "ibm,loc-code", 0);		if (loc_code) {			int loc_len = strlen(loc_code);			if (loc_len < sizeof(dev->dev.name)) {				memmove(dev->dev.name+loc_len+1, dev->dev.name,					sizeof(dev->dev.name)-loc_len-1);				memcpy(dev->dev.name, loc_code, loc_len);				dev->dev.name[loc_len] = ' ';				dev->dev.name[sizeof(dev->dev.name)-1] = '\0';			}		}	}#endif}   void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,					   struct pci_bus *bus){	/* Update device resources.  */	struct pci_controller *hose = PCI_GET_PHB_PTR(bus);	int i;	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		if (dev->resource[i].flags & IORESOURCE_IO) {			unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;                        unsigned long start, end, mask;                        start = dev->resource[i].start += offset;                        end = dev->resource[i].end += offset;                        /* Need to allow IO access to pages that are in the                           ISA range */                        if (start < MAX_ISA_PORT) {                                if (end > MAX_ISA_PORT)                                        end = MAX_ISA_PORT;                                start >>= PAGE_SHIFT;                                end >>= PAGE_SHIFT;                                /* get the range of pages for the map */                                mask = ((1 << (end+1))-1) ^ ((1 << start)-1);                                io_page_mask |= mask;                        }		}                else if (dev->resource[i].flags & IORESOURCE_MEM) {			dev->resource[i].start += hose->pci_mem_offset;			dev->resource[i].end += hose->pci_mem_offset;		}        }}EXPORT_SYMBOL(pcibios_fixup_device_resources);void __devinit pcibios_fixup_bus(struct pci_bus *bus){	struct pci_controller *hose = PCI_GET_PHB_PTR(bus);	struct list_head *ln;	/* XXX or bus->parent? */	struct pci_dev *dev = bus->self;	struct resource *res;	int i;	if (!dev) {		/* Root bus. */		hose->bus = bus;		bus->resource[0] = res = &hose->io_resource;		if (!res->flags)			BUG();	/* No I/O resource for this PHB? */		if (request_resource(&ioport_resource, res))			printk(KERN_ERR "Failed to request IO on "					"PCI domain %d\n", pci_domain_nr(bus));		for (i = 0; i < 3; ++i) {			res = &hose->mem_resources[i];			if (!res->flags && i == 0)				BUG();	/* No memory resource for this PHB? */			bus->resource[i+1] = res;			if (res->flags && request_resource(&iomem_resource, res))				printk(KERN_ERR "Failed to request MEM on "						"PCI domain %d\n",						pci_domain_nr(bus));		}	} else if (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);	}	/* XXX Need to check why Alpha doesnt do this - Anton */	if (!pci_probe_only)		return;	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {		struct pci_dev *dev = pci_dev_b(ln);		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)			pcibios_fixup_device_resources(dev, bus);	}}EXPORT_SYMBOL(pcibios_fixup_bus);static void check_s7a(void){	struct device_node *root;	char *model;	root = of_find_node_by_path("/");	if (root) {		model = get_property(root, "model", NULL);		if (model && !strcmp(model, "IBM,7013-S7A"))			s7a_workaround = 1;		of_node_put(root);	}}static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,				unsigned long *start_virt, unsigned long *size){	struct pci_controller *hose = PCI_GET_PHB_PTR(bus);	struct pci_bus_region region;	struct resource *res;	if (bus->self) {		res = bus->resource[0];		pcibios_resource_to_bus(bus->self, &region, res);		*start_phys = hose->io_base_phys + region.start;		*start_virt = (unsigned long) hose->io_base_virt + 				region.start;		if (region.end > region.start) 			*size = region.end - region.start + 1;		else {			printk("%s(): unexpected region 0x%lx->0x%lx\n", 					__FUNCTION__, region.start, region.end);			return 1;		}			} else {		/* Root Bus */		res = &hose->io_resource;		*start_phys = hose->io_base_phys;		*start_virt = (unsigned long) hose->io_base_virt;		if (res->end > res->start)			*size = res->end - res->start + 1;		else {			printk("%s(): unexpected region 0x%lx->0x%lx\n", 					__FUNCTION__, res->start, res->end);			return 1;		}	}	return 0;}int unmap_bus_range(struct pci_bus *bus){	unsigned long start_phys;	unsigned long start_virt;	unsigned long size;	if (!bus) {		printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);		return 1;	}		if (get_bus_io_range(bus, &start_phys, &start_virt, &size))		return 1;	if (iounmap_explicit((void *) start_virt, size))		return 1;	return 0;}EXPORT_SYMBOL(unmap_bus_range);int remap_bus_range(struct pci_bus *bus){	unsigned long start_phys;	unsigned long start_virt;	unsigned long size;	if (!bus) {		printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);		return 1;	}		if (get_bus_io_range(bus, &start_phys, &start_virt, &size))		return 1;	if (__ioremap_explicit(start_phys, start_virt, size, _PAGE_NO_CACHE))		return 1;	return 0;}EXPORT_SYMBOL(remap_bus_range);static void phbs_fixup_io(void){	struct pci_controller *hose;	for (hose=hose_head;hose;hose=hose->next) 		remap_bus_range(hose->bus);}extern void chrp_request_regions(void);void __init pSeries_final_fixup(void){	struct pci_dev *dev = NULL;	check_s7a();	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)		pci_read_irq_line(dev);	phbs_fixup_io();	chrp_request_regions();	pci_fix_bus_sysdata();	if (!ppc64_iommu_off)		iommu_setup_pSeries();}/***********************************************************************  * pci_find_hose_for_OF_device * * This function finds the PHB that matching device_node in the  * OpenFirmware by scanning all the pci_controllers. *  ***********************************************************************/struct pci_controller*pci_find_hose_for_OF_device(struct device_node *node){	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;}/* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. */intpcibios_scan_all_fns(struct pci_bus *bus, int devfn){       struct device_node *busdn, *dn;       if (bus->self)               busdn = pci_device_to_OF_node(bus->self);       else               busdn = bus->sysdata;   /* must be a phb */       /*        * Check to see if there is any of the 8 functions are in the        * device tree.  If they are then we need to scan all the        * functions of this slot.        */       for (dn = busdn->child; dn; dn = dn->sibling)               if ((dn->devfn >> 3) == (devfn >> 3))                       return 1;       return 0;}

⌨️ 快捷键说明

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