processor.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,497 行 · 第 1/5 页
C
2,497 行
end: return 0;}static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_processor_limit_seq_show, PDE(inode)->data);}static ssize_tacpi_processor_write_limit ( struct file *file, const char __user *buffer, size_t count, loff_t *data){ int result = 0; struct seq_file *m = (struct seq_file *)file->private_data; struct acpi_processor *pr = (struct acpi_processor *)m->private; char limit_string[25] = {'\0'}; int px = 0; int tx = 0; ACPI_FUNCTION_TRACE("acpi_processor_write_limit"); if (!pr || (count > sizeof(limit_string) - 1)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n")); return_VALUE(-EINVAL); } if (copy_from_user(limit_string, buffer, count)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n")); return_VALUE(-EFAULT); } limit_string[count] = '\0'; if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); return_VALUE(-EINVAL); } if (pr->flags.throttling) { if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n")); return_VALUE(-EINVAL); } pr->limit.user.tx = tx; } result = acpi_processor_apply_limit(pr); return_VALUE(count);}static intacpi_processor_add_fs ( struct acpi_device *device){ struct proc_dir_entry *entry = NULL; ACPI_FUNCTION_TRACE("acpi_processor_add_fs"); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_processor_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); } acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, S_IRUGO, acpi_device_dir(device)); if (!entry) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create '%s' fs entry\n", ACPI_PROCESSOR_FILE_INFO)); else { entry->proc_fops = &acpi_processor_info_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'power' [R] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, S_IRUGO, acpi_device_dir(device)); if (!entry) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create '%s' fs entry\n", ACPI_PROCESSOR_FILE_POWER)); else { entry->proc_fops = &acpi_processor_power_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'throttling' [R/W] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); if (!entry) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create '%s' fs entry\n", ACPI_PROCESSOR_FILE_THROTTLING)); else { entry->proc_fops = &acpi_processor_throttling_fops; entry->proc_fops->write = acpi_processor_write_throttling; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'limit' [R/W] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); if (!entry) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create '%s' fs entry\n", ACPI_PROCESSOR_FILE_LIMIT)); else { entry->proc_fops = &acpi_processor_limit_fops; entry->proc_fops->write = acpi_processor_write_limit; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } return_VALUE(0);}static intacpi_processor_remove_fs ( struct acpi_device *device){ ACPI_FUNCTION_TRACE("acpi_processor_remove_fs"); if (acpi_device_dir(device)) { remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,acpi_device_dir(device)); remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,acpi_device_dir(device)); remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, acpi_device_dir(device)); remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); acpi_device_dir(device) = NULL; } return_VALUE(0);}/* Use the acpiid in MADT to map cpus in case of SMP */#ifndef CONFIG_SMP#define convert_acpiid_to_cpu(acpi_id) (0xff)#else#ifdef CONFIG_IA64#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid#define arch_cpu_to_apicid ia64_cpu_to_sapicid#define ARCH_BAD_APICID (0xffff)#else#define arch_acpiid_to_apicid x86_acpiid_to_apicid#define arch_cpu_to_apicid x86_cpu_to_apicid#define ARCH_BAD_APICID (0xff)#endifstatic u8 convert_acpiid_to_cpu(u8 acpi_id){ u16 apic_id; int i; apic_id = arch_acpiid_to_apicid[acpi_id]; if (apic_id == ARCH_BAD_APICID) return -1; for (i = 0; i < NR_CPUS; i++) { if (arch_cpu_to_apicid[i] == apic_id) return i; } return -1;}#endif/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */static intacpi_processor_get_info ( struct acpi_processor *pr){ acpi_status status = 0; union acpi_object object = {0}; struct acpi_buffer buffer = {sizeof(union acpi_object), &object}; u8 cpu_index; static int cpu0_initialized; ACPI_FUNCTION_TRACE("acpi_processor_get_info"); if (!pr) return_VALUE(-EINVAL); if (num_online_cpus() > 1) errata.smp = TRUE; acpi_processor_errata(pr); /* * Check to see if we have bus mastering arbitration control. This * is required for proper C3 usage (to maintain cache coherency). */ if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) { pr->flags.bm_control = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Bus mastering arbitration control present\n")); } else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No bus mastering arbitration control\n")); /* * Evalute the processor object. Note that it is common on SMP to * have the first (boot) processor with a valid PBLK address while * all others have a NULL address. */ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating processor object\n")); return_VALUE(-ENODEV); } /* * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c */ pr->acpi_id = object.processor.proc_id; cpu_index = convert_acpiid_to_cpu(pr->acpi_id); if ( !cpu0_initialized && (cpu_index == 0xff)) { /* Handle UP system running SMP kernel, with no LAPIC in MADT */ cpu_index = 0; } else if (cpu_index > num_online_cpus()) { /* * Extra Processor objects may be enumerated on MP systems with * less than the max # of CPUs. They should be ignored. */ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error getting cpuindex for acpiid 0x%x\n", pr->acpi_id)); return_VALUE(-ENODEV); } cpu0_initialized = 1; pr->id = cpu_index; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, pr->acpi_id)); if (!object.processor.pblk_address) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); else if (object.processor.pblk_length != 6) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n", object.processor.pblk_length)); else { pr->throttling.address = object.processor.pblk_address; pr->throttling.duty_offset = acpi_fadt.duty_offset; pr->throttling.duty_width = acpi_fadt.duty_width; pr->power.states[ACPI_STATE_C2].address = object.processor.pblk_address + 4; pr->power.states[ACPI_STATE_C3].address = object.processor.pblk_address + 5; /* * We don't care about error returns - we just try to mark * these reserved so that nobody else is confused into thinking * that this region might be unused.. * * (In particular, allocating the IO range for Cardbus) */ request_region(pr->throttling.address, 6, "ACPI CPU throttle"); } acpi_processor_get_power_info(pr);#ifdef CONFIG_CPU_FREQ acpi_processor_ppc_has_changed(pr);#endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); return_VALUE(0);}static voidacpi_processor_notify ( acpi_handle handle, u32 event, void *data){ struct acpi_processor *pr = (struct acpi_processor *) data; struct acpi_device *device = NULL; ACPI_FUNCTION_TRACE("acpi_processor_notify"); if (!pr) return_VOID; if (acpi_bus_get_device(pr->handle, &device)) return_VOID; switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: acpi_processor_ppc_has_changed(pr); acpi_bus_generate_event(device, event, pr->performance_platform_limit); break; case ACPI_PROCESSOR_NOTIFY_POWER: /* TBD */ acpi_bus_generate_event(device, event, 0); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return_VOID;}static intacpi_processor_add ( struct acpi_device *device){ int result = 0; acpi_status status = AE_OK; struct acpi_processor *pr = NULL; u32 i = 0; ACPI_FUNCTION_TRACE("acpi_processor_add"); if (!device) return_VALUE(-EINVAL); pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return_VALUE(-ENOMEM); memset(pr, 0, sizeof(struct acpi_processor)); pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); acpi_driver_data(device) = pr; result = acpi_processor_get_info(pr); if (result) goto end; result = acpi_processor_add_fs(device); if (result) goto end; status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify, pr); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing notify handler\n")); result = -ENODEV; goto end; } processors[pr->id] = pr; /* * Install the idle handler if processor power management is supported. * Note that the default idle handler (default_idle) will be used on * platforms that only support C1. */ if ((pr->id == 0) && (pr->flags.power)) { pm_idle_save = pm_idle; pm_idle = acpi_processor_idle; } printk(KERN_INFO PREFIX "%s [%s] (supports", acpi_device_name(device), acpi_device_bid(device)); for (i=1; i<ACPI_C_STATE_COUNT; i++) if (pr->power.states[i].valid) printk(" C%d", i); if (pr->flags.throttling) printk(", %d throttling states", pr->throttling.state_count); printk(")\n");end: if (result) { acpi_processor_remove_fs(device); kfree(pr); } return_VALUE(result);}static intacpi_processor_remove ( struct acpi_device *device, int type){ acpi_status status = AE_OK; struct acpi_processor *pr = NULL; ACPI_FUNCTION_TRACE("acpi_processor_remove"); if (!device || !acpi_driver_data(device)) return_VALUE(-EINVAL); pr = (struct acpi_processor *) acpi_driver_data(device); /* Unregister the idle handler when processor #0 is removed. */ if (pr->id == 0) { pm_idle = pm_idle_save; /* * We are about to unload the current idle thread pm callback * (pm_idle), Wait for all processors to update cached/local * copies of pm_idle before proceeding. */ synchronize_kernel(); } status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error removing notify handler\n")); } acpi_processor_remove_fs(device); processors[pr->id] = NULL; kfree(pr); return_VALUE(0);}static int __initacpi_processor_init (void){ int result = 0; ACPI_FUNCTION_TRACE("acpi_processor_init"); memset(&processors, 0, sizeof(processors)); memset(&errata, 0, sizeof(errata)); acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) return_VALUE(-ENODEV); acpi_processor_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) { remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); return_VALUE(-ENODEV); } acpi_thermal_cpufreq_init(); acpi_processor_ppc_init(); return_VALUE(0);}static void __exitacpi_processor_exit (void){ ACPI_FUNCTION_TRACE("acpi_processor_exit"); acpi_processor_ppc_exit(); acpi_thermal_cpufreq_exit(); acpi_bus_unregister_driver(&acpi_processor_driver); remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); return_VOID;}module_init(acpi_processor_init);module_exit(acpi_processor_exit);EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?