pci_link.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 874 行 · 第 1/2 页

C
874
字号
 * enabled system. */#define ACPI_MAX_IRQS		256#define ACPI_MAX_ISA_IRQ	16#define PIRQ_PENALTY_PCI_AVAILABLE	(0)#define PIRQ_PENALTY_PCI_POSSIBLE	(16*16)#define PIRQ_PENALTY_PCI_USING		(16*16*16)#define PIRQ_PENALTY_ISA_TYPICAL	(16*16*16*16)#define PIRQ_PENALTY_ISA_USED		(16*16*16*16*16)#define PIRQ_PENALTY_ISA_ALWAYS		(16*16*16*16*16*16)static int acpi_irq_penalty[ACPI_MAX_IRQS] = {	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ3	serial */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ4	serial */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ5 sometimes SoundBlaster */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ6 */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ7 parallel, spurious */	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ8 rtc, sometimes */	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ9  PCI, often acpi */	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ10 PCI */	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ11 PCI */	PIRQ_PENALTY_ISA_USED,	/* IRQ12 mouse */	PIRQ_PENALTY_ISA_USED,	/* IRQ13 fpe, sometimes */	PIRQ_PENALTY_ISA_USED,	/* IRQ14 ide0 */	PIRQ_PENALTY_ISA_USED,	/* IRQ15 ide1 */			/* >IRQ15 */};int __initacpi_irq_penalty_init(void){	struct list_head	*node = NULL;	struct acpi_pci_link    *link = NULL;	int			i = 0;	ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");	/*	 * Update penalties to facilitate IRQ balancing.	 */	list_for_each(node, &acpi_link.entries) {		link = list_entry(node, struct acpi_pci_link, node);		if (!link) {			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));			continue;		}		/*		 * reflect the possible and active irqs in the penalty table --		 * useful for breaking ties.		 */		if (link->irq.possible_count) {			int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count;			for (i = 0; i < link->irq.possible_count; i++) {				if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)					acpi_irq_penalty[link->irq.possible[i]] += penalty;			}		} else if (link->irq.active) {			acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE;		}	}	/* Add a penalty for the SCI */	acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;	return_VALUE(0);}static int acpi_irq_balance;	/* 0: static, 1: balance */static int acpi_pci_link_allocate(struct acpi_pci_link* link) {	int irq;	int i;	ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");	if (link->irq.initialized)		return_VALUE(0);	/*	 * search for active IRQ in list of possible IRQs.	 */	for (i = 0; i < link->irq.possible_count; ++i) {		if (link->irq.active == link->irq.possible[i])			break;	}	/*	 * forget active IRQ that is not in possible list	 */	if (i == link->irq.possible_count) {		if (acpi_strict)			printk(KERN_WARNING PREFIX "_CRS %d not found"				" in _PRS\n", link->irq.active);		link->irq.active = 0;	}	/*	 * if active found, use it; else pick entry from end of possible list.	 */	if (link->irq.active) {		irq = link->irq.active;	} else {		irq = link->irq.possible[link->irq.possible_count - 1];	}	if (acpi_irq_balance || !link->irq.active) {		/*		 * Select the best IRQ.  This is done in reverse to promote		 * the use of IRQs 9, 10, 11, and >15.		 */		for (i = (link->irq.possible_count - 1); i >= 0; i--) {			if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]])				irq = link->irq.possible[i];		}	}	/* Attempt to enable the link device at this IRQ. */	if (acpi_pci_link_set(link, irq)) {		printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"				"Try pci=noacpi or acpi=off\n",			acpi_device_name(link->device),			acpi_device_bid(link->device));		return_VALUE(-ENODEV);	} else {		acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;		printk(PREFIX "%s [%s] enabled at IRQ %d\n", 			acpi_device_name(link->device),			acpi_device_bid(link->device), link->irq.active);	}	link->irq.initialized = 1;	return_VALUE(0);}intacpi_pci_link_get_irq (	acpi_handle		handle,	int			index,	int*			edge_level,	int*			active_high_low){	int                     result = 0;	struct acpi_device	*device = NULL;	struct acpi_pci_link	*link = NULL;	ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq");	result = acpi_bus_get_device(handle, &device);	if (result) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));		return_VALUE(0);	}	link = (struct acpi_pci_link *) acpi_driver_data(device);	if (!link) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));		return_VALUE(0);	}	/* TBD: Support multiple index (IRQ) entries per Link Device */	if (index) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index));		return_VALUE(0);	}	if (acpi_pci_link_allocate(link))		return_VALUE(0);	   	if (!link->irq.active) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));		return_VALUE(0);	}	if (edge_level) *edge_level = link->irq.edge_level;	if (active_high_low) *active_high_low = link->irq.active_high_low;	return_VALUE(link->irq.active);}/* --------------------------------------------------------------------------                                 Driver Interface   -------------------------------------------------------------------------- */static intacpi_pci_link_add (	struct acpi_device *device){	int			result = 0;	struct acpi_pci_link	*link = NULL;	int			i = 0;	int			found = 0;	ACPI_FUNCTION_TRACE("acpi_pci_link_add");	if (!device)		return_VALUE(-EINVAL);	link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);	if (!link)		return_VALUE(-ENOMEM);	memset(link, 0, sizeof(struct acpi_pci_link));	link->device = device;	link->handle = device->handle;	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);	acpi_driver_data(device) = link;	result = acpi_pci_link_get_possible(link);	if (result)		goto end;	/* query and set link->irq.active */	acpi_pci_link_get_current(link);	printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),		acpi_device_bid(device));	for (i = 0; i < link->irq.possible_count; i++) {		if (link->irq.active == link->irq.possible[i]) {			printk(" *%d", link->irq.possible[i]);			found = 1;		}		else			printk(" %d", link->irq.possible[i]);	}	printk(")");	if (!found)		printk(" *%d", link->irq.active);	if(!link->device->status.enabled)		printk(", disabled.");	printk("\n");	/* TBD: Acquire/release lock */	list_add_tail(&link->node, &acpi_link.entries);	acpi_link.count++;end:	/* disable all links -- to be activated on use */	acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);	if (result)		kfree(link);	return_VALUE(result);}static intacpi_pci_link_resume (	struct acpi_pci_link	*link){	ACPI_FUNCTION_TRACE("acpi_pci_link_resume");		if (link->irq.active && link->irq.initialized)		return_VALUE(acpi_pci_link_set(link, link->irq.active));	else		return_VALUE(0);}static intirqrouter_resume(	struct sys_device *dev){	struct list_head        *node = NULL;	struct acpi_pci_link    *link = NULL;	ACPI_FUNCTION_TRACE("irqrouter_resume");	list_for_each(node, &acpi_link.entries) {		link = list_entry(node, struct acpi_pci_link, node);		if (!link) {			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));			continue;		}		acpi_pci_link_resume(link);	}	return_VALUE(0);}static intacpi_pci_link_remove (	struct acpi_device	*device,	int			type){	struct acpi_pci_link *link = NULL;	ACPI_FUNCTION_TRACE("acpi_pci_link_remove");	if (!device || !acpi_driver_data(device))		return_VALUE(-EINVAL);	link = (struct acpi_pci_link *) acpi_driver_data(device);	/* TBD: Acquire/release lock */	list_del(&link->node);	kfree(link);	return_VALUE(0);}/* * modify acpi_irq_penalty[] from cmdline */static int __init acpi_irq_penalty_update(char *str, int used){	int i;	for (i = 0; i < 16; i++) {		int retval;		int irq;		retval = get_option(&str,&irq);		if (!retval)			break;	/* no number found */		if (irq < 0)			continue;				if (irq >= ACPI_MAX_IRQS)			continue;		if (used)			acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;		else			acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;		if (retval != 2)	/* no next number */			break;	}	return 1;}/* * Over-ride default table to reserve additional IRQs for use by ISA * e.g. acpi_irq_isa=5 * Useful for telling ACPI how not to interfere with your ISA sound card. */static int __init acpi_irq_isa(char *str){	return(acpi_irq_penalty_update(str, 1));}__setup("acpi_irq_isa=", acpi_irq_isa);/* * Over-ride default table to free additional IRQs for use by PCI * e.g. acpi_irq_pci=7,15 * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing. */static int __init acpi_irq_pci(char *str){	return(acpi_irq_penalty_update(str, 0));}__setup("acpi_irq_pci=", acpi_irq_pci);static int __init acpi_irq_nobalance_set(char *str){	acpi_irq_balance = 0;	return(1);}__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);int __init acpi_irq_balance_set(char *str){	acpi_irq_balance = 1;	return(1);}__setup("acpi_irq_balance", acpi_irq_balance_set);static struct sysdev_class irqrouter_sysdev_class = {        set_kset_name("irqrouter"),        .resume = irqrouter_resume,};static struct sys_device device_irqrouter = {	.id     = 0,	.cls    = &irqrouter_sysdev_class,};static int __init irqrouter_init_sysfs(void){	int error;	ACPI_FUNCTION_TRACE("irqrouter_init_sysfs");	if (acpi_disabled || acpi_noirq)		return_VALUE(0);	error = sysdev_class_register(&irqrouter_sysdev_class);	if (!error)		error = sysdev_register(&device_irqrouter);	return_VALUE(error);}                                        device_initcall(irqrouter_init_sysfs);static int __init acpi_pci_link_init (void){	ACPI_FUNCTION_TRACE("acpi_pci_link_init");	if (acpi_noirq)		return_VALUE(0);	acpi_link.count = 0;	INIT_LIST_HEAD(&acpi_link.entries);	if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)		return_VALUE(-ENODEV);	return_VALUE(0);}subsys_initcall(acpi_pci_link_init);

⌨️ 快捷键说明

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