pci_link.c
来自「linux 内核源代码」· C语言 代码 · 共 956 行 · 第 1/2 页
C
956 行
int __init acpi_irq_penalty_init(void){ struct list_head *node = NULL; struct acpi_pci_link *link = NULL; int i = 0; /* * Update penalties to facilitate IRQ balancing. */ list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { printk(KERN_ERR PREFIX "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_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING; return 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; if (link->irq.initialized) { if (link->refcnt == 0) /* This means the link is disabled but initialized */ acpi_pci_link_set(link, link->irq.active); return 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(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. " "Try pci=noacpi or acpi=off\n", acpi_device_name(link->device), acpi_device_bid(link->device)); return -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 0;}/* * acpi_pci_link_allocate_irq * success: return IRQ >= 0 * failure: return -1 */intacpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, int *polarity, char **name){ int result = 0; struct acpi_device *device = NULL; struct acpi_pci_link *link = NULL; result = acpi_bus_get_device(handle, &device); if (result) { printk(KERN_ERR PREFIX "Invalid link device\n"); return -1; } link = acpi_driver_data(device); if (!link) { printk(KERN_ERR PREFIX "Invalid link context\n"); return -1; } /* TBD: Support multiple index (IRQ) entries per Link Device */ if (index) { printk(KERN_ERR PREFIX "Invalid index %d\n", index); return -1; } mutex_lock(&acpi_link_lock); if (acpi_pci_link_allocate(link)) { mutex_unlock(&acpi_link_lock); return -1; } if (!link->irq.active) { mutex_unlock(&acpi_link_lock); printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); return -1; } link->refcnt++; mutex_unlock(&acpi_link_lock); if (triggering) *triggering = link->irq.triggering; if (polarity) *polarity = link->irq.polarity; if (name) *name = acpi_device_bid(link->device); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link %s is referenced\n", acpi_device_bid(link->device))); return (link->irq.active);}/* * We don't change link's irq information here. After it is reenabled, we * continue use the info */int acpi_pci_link_free_irq(acpi_handle handle){ struct acpi_device *device = NULL; struct acpi_pci_link *link = NULL; acpi_status result; result = acpi_bus_get_device(handle, &device); if (result) { printk(KERN_ERR PREFIX "Invalid link device\n"); return -1; } link = acpi_driver_data(device); if (!link) { printk(KERN_ERR PREFIX "Invalid link context\n"); return -1; } mutex_lock(&acpi_link_lock); if (!link->irq.initialized) { mutex_unlock(&acpi_link_lock); printk(KERN_ERR PREFIX "Link isn't initialized\n"); return -1; }#ifdef FUTURE_USE /* * The Link reference count allows us to _DISable an unused link * and suspend time, and set it again on resume. * However, 2.6.12 still has irq_router.resume * which blindly restores the link state. * So we disable the reference count method * to prevent duplicate acpi_pci_link_set() * which would harm some systems */ link->refcnt--;#endif ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link %s is dereferenced\n", acpi_device_bid(link->device))); if (link->refcnt == 0) { acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL); } mutex_unlock(&acpi_link_lock); return (link->irq.active);}/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */static int acpi_pci_link_add(struct acpi_device *device){ int result = 0; struct acpi_pci_link *link = NULL; int i = 0; int found = 0; if (!device) return -EINVAL; link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL); if (!link) return -ENOMEM; link->device = device; strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); acpi_driver_data(device) = link; mutex_lock(&acpi_link_lock); result = acpi_pci_link_get_possible(link); if (result) goto end; /* query and set link->irq.active */ acpi_pci_link_get_current(link); printk(KERN_INFO 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(device->handle, "_DIS", 0, NULL); mutex_unlock(&acpi_link_lock); if (result) kfree(link); return result;}static int acpi_pci_link_resume(struct acpi_pci_link *link){ if (link->refcnt && link->irq.active && link->irq.initialized) return (acpi_pci_link_set(link, link->irq.active)); else return 0;}static int irqrouter_resume(struct sys_device *dev){ struct list_head *node = NULL; struct acpi_pci_link *link = NULL; /* Make sure SCI is enabled again (Apple firmware bug?) */ acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { printk(KERN_ERR PREFIX "Invalid link context\n"); continue; } acpi_pci_link_resume(link); } return 0;}static int acpi_pci_link_remove(struct acpi_device *device, int type){ struct acpi_pci_link *link = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; link = acpi_driver_data(device); mutex_lock(&acpi_link_lock); list_del(&link->node); mutex_unlock(&acpi_link_lock); kfree(link); return 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;}/* * We'd like PNP to call this routine for the * single ISA_USED value for each legacy device. * But instead it calls us with each POSSIBLE setting. * There is no ISA_POSSIBLE weight, so we simply use * the (small) PCI_USING penalty. */void acpi_penalize_isa_irq(int irq, int active){ if (active) acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; else acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;}/* * 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);/* FIXME: we will remove this interface after all drivers call pci_disable_device */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; if (acpi_disabled || acpi_noirq) return 0; error = sysdev_class_register(&irqrouter_sysdev_class); if (!error) error = sysdev_register(&device_irqrouter); return error;}device_initcall(irqrouter_init_sysfs);static int __init acpi_pci_link_init(void){ if (acpi_noirq) return 0; acpi_link.count = 0; INIT_LIST_HEAD(&acpi_link.entries); if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0) return -ENODEV; return 0;}subsys_initcall(acpi_pci_link_init);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?