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

📄 pci-irq.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
}static struct irq_router pirq_bios_router =	{ "BIOS", 0, 0, NULL, pirq_bios_set };#endifstatic struct irq_router pirq_routers[] = {	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,	  pirq_serverworks_get, pirq_serverworks_set },	{ "default", 0, 0, NULL, NULL }};static struct irq_router *pirq_router;static struct pci_dev *pirq_router_dev;static void __init pirq_find_router(void){	struct irq_routing_table *rt = pirq_table;	struct irq_router *r;#ifdef CONFIG_PCI_BIOS	if (!rt->signature) {		printk("PCI: Using BIOS for IRQ routing\n");		pirq_router = &pirq_bios_router;		return;	}#endif	/* fall back to default router if nothing else found */	pirq_router = pirq_routers + sizeof(pirq_routers) / sizeof(pirq_routers[0]) - 1;	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);	if (!pirq_router_dev) {		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);		return;	}	for(r=pirq_routers; r->vendor; r++) {		/* Exact match against router table entry? Use it! */		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {			pirq_router = r;			break;		}		/* Match against router device entry? Use it as a fallback */		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {			pirq_router = r;		}	}	printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n",		pirq_router->name,		pirq_router_dev->vendor,		pirq_router_dev->device,		pirq_router_dev->slot_name);}static struct irq_info *pirq_get_info(struct pci_dev *dev){	struct irq_routing_table *rt = pirq_table;	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);	struct irq_info *info;	for (info = rt->slots; entries--; info++)		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))			return info;	return NULL;}static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs){}static int pcibios_lookup_irq(struct pci_dev *dev, int assign){	u8 pin;	struct irq_info *info;	int i, pirq, newirq;	int irq = 0;	u32 mask;	struct irq_router *r = pirq_router;	struct pci_dev *dev2;	char *msg = NULL;	if (!pirq_table)		return 0;	/* Find IRQ routing entry */	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);	if (!pin) {		DBG(" -> no interrupt pin\n");		return 0;	}	pin = pin - 1;		DBG("IRQ for %s:%d", dev->slot_name, pin);	info = pirq_get_info(dev);	if (!info) {		DBG(" -> not found in routing table\n");		return 0;	}	pirq = info->irq[pin].link;	mask = info->irq[pin].bitmap;	if (!pirq) {		DBG(" -> not routed\n");		return 0;	}	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);	mask &= pcibios_irq_mask;	/*	 * Find the best IRQ to assign: use the one	 * reported by the device if possible.	 */	newirq = dev->irq;	if (!newirq && assign) {		for (i = 0; i < 16; i++) {			if (!(mask & (1 << i)))				continue;			if (pirq_penalty[i] < pirq_penalty[newirq] &&			    !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {				free_irq(i, dev);				newirq = i;			}		}	}	DBG(" -> newirq=%d", newirq);	/* Check if it is hardcoded */	if ((pirq & 0xf0) == 0xf0) {		irq = pirq & 0xf;		DBG(" -> hardcoded IRQ %d\n", irq);		msg = "Hardcoded";		if (dev->irq && dev->irq != irq) {			printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n");			return 0;		}	} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {		DBG(" -> got IRQ %d\n", irq);		msg = "Found";		/* We refuse to override the dev->irq information. Give a warning! */	    	if (dev->irq && dev->irq != irq) {	    		printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n");	    		return 0;	    	}	} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {		DBG(" -> assigning IRQ %d", newirq);		if (r->set(pirq_router_dev, dev, pirq, newirq)) {			eisa_set_level_irq(newirq);			DBG(" ... OK\n");			msg = "Assigned";			irq = newirq;		}	}	if (!irq) {		DBG(" ... failed\n");		if (newirq && mask == (1 << newirq)) {			msg = "Guessed";			irq = newirq;		} else			return 0;	}	printk("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);	/* Update IRQ for all devices with the same pirq value */	pci_for_each_dev(dev2) {		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);		if (!pin)			continue;		pin--;		info = pirq_get_info(dev2);		if (!info)			continue;		if (info->irq[pin].link == pirq) {			dev2->irq = irq;			pirq_penalty[irq]++;			if (dev != dev2)				printk("PCI: The same IRQ used for device %s\n", dev2->slot_name);		}	}	return 1;}void __init pcibios_irq_init(void){	DBG("PCI: IRQ init\n");	pirq_table = pirq_find_routing_table();#ifdef CONFIG_PCI_BIOS	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))		pirq_table = pcibios_get_irq_routing_table();#endif	if (pirq_table) {		pirq_peer_trick();		pirq_find_router();		if (pirq_table->exclusive_irqs) {			int i;			for (i=0; i<16; i++)				if (!(pirq_table->exclusive_irqs & (1 << i)))					pirq_penalty[i] += 100;		}		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */		if (io_apic_assign_pci_irqs)			pirq_table = NULL;	}}void __init pcibios_fixup_irqs(void){	struct pci_dev *dev;	u8 pin;	DBG("PCI: IRQ fixup\n");	pci_for_each_dev(dev) {		/*		 * If the BIOS has set an out of range IRQ number, just ignore it.		 * Also keep track of which IRQ's are already in use.		 */		if (dev->irq >= 16) {			DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);			dev->irq = 0;		}		/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */		if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)			pirq_penalty[dev->irq] = 0;		pirq_penalty[dev->irq]++;	}	pci_for_each_dev(dev) {		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);#ifdef CONFIG_X86_IO_APIC		/*		 * Recalculate IRQ numbers if we use the I/O APIC.		 */		if (io_apic_assign_pci_irqs)		{			int irq;			if (pin) {				pin--;		/* interrupt pins are numbered starting from 1 */				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);/* * Will be removed completely if things work out well with fuzzy parsing */#if 0				if (irq < 0 && dev->bus->parent) { /* go back to the bridge */					struct pci_dev * bridge = dev->bus->self;					pin = (pin + PCI_SLOT(dev->devfn)) % 4;					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 							PCI_SLOT(bridge->devfn), pin);					if (irq >= 0)						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);				}#endif				if (irq >= 0) {					printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);					dev->irq = irq;				}			}		}#endif		/*		 * Still no IRQ? Try to lookup one...		 */		if (pin && !dev->irq)			pcibios_lookup_irq(dev, 0);	}}void pcibios_penalize_isa_irq(int irq){	/*	 *  If any ISAPnP device reports an IRQ in its list of possible	 *  IRQ's, we try to avoid assigning it to PCI devices.	 */	pirq_penalty[irq] += 100;}void pcibios_enable_irq(struct pci_dev *dev){	u8 pin;	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {		char *msg;		if (io_apic_assign_pci_irqs)			msg = " Probably buggy MP table.";		else if (pci_probe & PCI_BIOS_IRQ_SCAN)			msg = "";		else			msg = " Please try using pci=biosirq.";		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",		       'A' + pin - 1, dev->slot_name, msg);	}}

⌨️ 快捷键说明

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