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 + -
显示快捷键?