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