processor_core.c

来自「linux 内核源代码」· C语言 代码 · 共 1,098 行 · 第 1/2 页

C
1,098
字号
		* 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)) {			printk(KERN_ERR PREFIX "Evaluating processor object\n");			return -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 = get_cpu_id(pr->handle, pr->acpi_id);	/* Handle UP system running SMP kernel, with no LAPIC in MADT */	if (!cpu0_initialized && (cpu_index == -1) &&	    (num_online_cpus() == 1)) {		cpu_index = 0;	}	cpu0_initialized = 1;	pr->id = cpu_index;	/*	 *  Extra Processor objects may be enumerated on MP systems with	 *  less than the max # of CPUs. They should be ignored _iff	 *  they are physically not present.	 */	if (pr->id == -1) {		if (ACPI_FAILURE		    (acpi_processor_hotadd_init(pr->handle, &pr->id))) {			return -ENODEV;		}	}	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)		printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",			    object.processor.pblk_length);	else {		pr->throttling.address = object.processor.pblk_address;		pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;		pr->throttling.duty_width = acpi_gbl_FADT.duty_width;		pr->pblk = object.processor.pblk_address;		/*		 * 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");	}	return 0;}static void *processor_device_array[NR_CPUS];static int __cpuinit acpi_processor_start(struct acpi_device *device){	int result = 0;	acpi_status status = AE_OK;	struct acpi_processor *pr;	pr = acpi_driver_data(device);	result = acpi_processor_get_info(pr, device->flags.unique_id);	if (result) {		/* Processor is physically not present */		return 0;	}	BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));	/*	 * Buggy BIOS check	 * ACPI id of processors can be reported wrongly by the BIOS.	 * Don't trust it blindly	 */	if (processor_device_array[pr->id] != NULL &&	    processor_device_array[pr->id] != device) {		printk(KERN_WARNING "BIOS reported wrong ACPI id "			"for the processor\n");		return -ENODEV;	}	processor_device_array[pr->id] = device;	processors[pr->id] = pr;	result = acpi_processor_add_fs(device);	if (result)		goto end;	status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,					     acpi_processor_notify, pr);	/* _PDC call should be done before doing anything else (if reqd.). */	arch_acpi_processor_init_pdc(pr);	acpi_processor_set_pdc(pr);#ifdef CONFIG_CPU_FREQ	acpi_processor_ppc_has_changed(pr);#endif	acpi_processor_get_throttling_info(pr);	acpi_processor_get_limit_info(pr);	acpi_processor_power_init(pr, device);	if (pr->flags.throttling) {		printk(KERN_INFO PREFIX "%s [%s] (supports",		       acpi_device_name(device), acpi_device_bid(device));		printk(" %d throttling states", pr->throttling.state_count);		printk(")\n");	}      end:	return result;}static void acpi_processor_notify(acpi_handle handle, u32 event, void *data){	struct acpi_processor *pr = data;	struct acpi_device *device = NULL;	int saved;	if (!pr)		return;	if (acpi_bus_get_device(pr->handle, &device))		return;	switch (event) {	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:		saved = pr->performance_platform_limit;		acpi_processor_ppc_has_changed(pr);		if (saved == pr->performance_platform_limit)			break;		acpi_bus_generate_proc_event(device, event,					pr->performance_platform_limit);		acpi_bus_generate_netlink_event(device->pnp.device_class,						  device->dev.bus_id, event,						  pr->performance_platform_limit);		break;	case ACPI_PROCESSOR_NOTIFY_POWER:		acpi_processor_cst_has_changed(pr);		acpi_bus_generate_proc_event(device, event, 0);		acpi_bus_generate_netlink_event(device->pnp.device_class,						  device->dev.bus_id, event, 0);		break;	case ACPI_PROCESSOR_NOTIFY_THROTTLING:		acpi_processor_tstate_has_changed(pr);		acpi_bus_generate_proc_event(device, event, 0);		acpi_bus_generate_netlink_event(device->pnp.device_class,						  device->dev.bus_id, event, 0);	default:		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "Unsupported event [0x%x]\n", event));		break;	}	return;}static int acpi_cpu_soft_notify(struct notifier_block *nfb,		unsigned long action, void *hcpu){	unsigned int cpu = (unsigned long)hcpu;	struct acpi_processor *pr = processors[cpu];	if (action == CPU_ONLINE && pr) {		acpi_processor_ppc_has_changed(pr);		acpi_processor_cst_has_changed(pr);		acpi_processor_tstate_has_changed(pr);	}	return NOTIFY_OK;}static struct notifier_block acpi_cpu_notifier ={	    .notifier_call = acpi_cpu_soft_notify,};static int acpi_processor_add(struct acpi_device *device){	struct acpi_processor *pr = NULL;	if (!device)		return -EINVAL;	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);	if (!pr)		return -ENOMEM;	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;	return 0;}static int acpi_processor_remove(struct acpi_device *device, int type){	acpi_status status = AE_OK;	struct acpi_processor *pr = NULL;	if (!device || !acpi_driver_data(device))		return -EINVAL;	pr = acpi_driver_data(device);	if (pr->id >= nr_cpu_ids) {		kfree(pr);		return 0;	}	if (type == ACPI_BUS_REMOVAL_EJECT) {		if (acpi_processor_handle_eject(pr))			return -EINVAL;	}	acpi_processor_power_exit(pr, device);	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,					    acpi_processor_notify);	acpi_processor_remove_fs(device);	processors[pr->id] = NULL;	kfree(pr);	return 0;}#ifdef CONFIG_ACPI_HOTPLUG_CPU/**************************************************************************** * 	Acpi processor hotplug support 				       	    * ****************************************************************************/static int is_processor_present(acpi_handle handle);static int is_processor_present(acpi_handle handle){	acpi_status status;	unsigned long sta = 0;	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {		ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));		return 0;	}	return 1;}staticint acpi_processor_device_add(acpi_handle handle, struct acpi_device **device){	acpi_handle phandle;	struct acpi_device *pdev;	struct acpi_processor *pr;	if (acpi_get_parent(handle, &phandle)) {		return -ENODEV;	}	if (acpi_bus_get_device(phandle, &pdev)) {		return -ENODEV;	}	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {		return -ENODEV;	}	acpi_bus_start(*device);	pr = acpi_driver_data(*device);	if (!pr)		return -ENODEV;	if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {		kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);	}	return 0;}static voidacpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data){	struct acpi_processor *pr;	struct acpi_device *device = NULL;	int result;	switch (event) {	case ACPI_NOTIFY_BUS_CHECK:	case ACPI_NOTIFY_DEVICE_CHECK:		printk("Processor driver received %s event\n",		       (event == ACPI_NOTIFY_BUS_CHECK) ?		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");		if (!is_processor_present(handle))			break;		if (acpi_bus_get_device(handle, &device)) {			result = acpi_processor_device_add(handle, &device);			if (result)				printk(KERN_ERR PREFIX					    "Unable to add the device\n");			break;		}		pr = acpi_driver_data(device);		if (!pr) {			printk(KERN_ERR PREFIX "Driver data is NULL\n");			break;		}		if (pr->id >= 0 && (pr->id < nr_cpu_ids)) {			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);			break;		}		result = acpi_processor_start(device);		if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) {			kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);		} else {			printk(KERN_ERR PREFIX "Device [%s] failed to start\n",				    acpi_device_bid(device));		}		break;	case ACPI_NOTIFY_EJECT_REQUEST:		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "received ACPI_NOTIFY_EJECT_REQUEST\n"));		if (acpi_bus_get_device(handle, &device)) {			printk(KERN_ERR PREFIX				    "Device don't exist, dropping EJECT\n");			break;		}		pr = acpi_driver_data(device);		if (!pr) {			printk(KERN_ERR PREFIX				    "Driver data is NULL, dropping EJECT\n");			return;		}		if ((pr->id < nr_cpu_ids) && (cpu_present(pr->id)))			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);		break;	default:		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "Unsupported event [0x%x]\n", event));		break;	}	return;}static acpi_statusprocessor_walk_namespace_cb(acpi_handle handle,			    u32 lvl, void *context, void **rv){	acpi_status status;	int *action = context;	acpi_object_type type = 0;	status = acpi_get_type(handle, &type);	if (ACPI_FAILURE(status))		return (AE_OK);	if (type != ACPI_TYPE_PROCESSOR)		return (AE_OK);	switch (*action) {	case INSTALL_NOTIFY_HANDLER:		acpi_install_notify_handler(handle,					    ACPI_SYSTEM_NOTIFY,					    acpi_processor_hotplug_notify,					    NULL);		break;	case UNINSTALL_NOTIFY_HANDLER:		acpi_remove_notify_handler(handle,					   ACPI_SYSTEM_NOTIFY,					   acpi_processor_hotplug_notify);		break;	default:		break;	}	return (AE_OK);}static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu){	if (!is_processor_present(handle)) {		return AE_ERROR;	}	if (acpi_map_lsapic(handle, p_cpu))		return AE_ERROR;	if (arch_register_cpu(*p_cpu)) {		acpi_unmap_lsapic(*p_cpu);		return AE_ERROR;	}	return AE_OK;}static int acpi_processor_handle_eject(struct acpi_processor *pr){	if (cpu_online(pr->id)) {		return (-EINVAL);	}	arch_unregister_cpu(pr->id);	acpi_unmap_lsapic(pr->id);	return (0);}#elsestatic acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu){	return AE_ERROR;}static int acpi_processor_handle_eject(struct acpi_processor *pr){	return (-EINVAL);}#endifstaticvoid acpi_processor_install_hotplug_notify(void){#ifdef CONFIG_ACPI_HOTPLUG_CPU	int action = INSTALL_NOTIFY_HANDLER;	acpi_walk_namespace(ACPI_TYPE_PROCESSOR,			    ACPI_ROOT_OBJECT,			    ACPI_UINT32_MAX,			    processor_walk_namespace_cb, &action, NULL);#endif	register_hotcpu_notifier(&acpi_cpu_notifier);}staticvoid acpi_processor_uninstall_hotplug_notify(void){#ifdef CONFIG_ACPI_HOTPLUG_CPU	int action = UNINSTALL_NOTIFY_HANDLER;	acpi_walk_namespace(ACPI_TYPE_PROCESSOR,			    ACPI_ROOT_OBJECT,			    ACPI_UINT32_MAX,			    processor_walk_namespace_cb, &action, NULL);#endif	unregister_hotcpu_notifier(&acpi_cpu_notifier);}/* * We keep the driver loaded even when ACPI is not running. * This is needed for the powernow-k8 driver, that works even without * ACPI, but needs symbols from this driver */static int __init acpi_processor_init(void){	int result = 0;	memset(&processors, 0, sizeof(processors));	memset(&errata, 0, sizeof(errata));#ifdef CONFIG_SMP	if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,				(struct acpi_table_header **)&madt)))		madt = NULL;#endif	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);	if (!acpi_processor_dir)		return -ENOMEM;	acpi_processor_dir->owner = THIS_MODULE;	result = cpuidle_register_driver(&acpi_idle_driver);	if (result < 0)		goto out_proc;	result = acpi_bus_register_driver(&acpi_processor_driver);	if (result < 0)		goto out_cpuidle;	acpi_processor_install_hotplug_notify();	acpi_thermal_cpufreq_init();	acpi_processor_ppc_init();	return 0;out_cpuidle:	cpuidle_unregister_driver(&acpi_idle_driver);out_proc:	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);	return result;}static void __exit acpi_processor_exit(void){	acpi_processor_ppc_exit();	acpi_thermal_cpufreq_exit();	acpi_processor_uninstall_hotplug_notify();	acpi_bus_unregister_driver(&acpi_processor_driver);	cpuidle_unregister_driver(&acpi_idle_driver);	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);	return;}module_init(acpi_processor_init);module_exit(acpi_processor_exit);EXPORT_SYMBOL(acpi_processor_set_thermal_limit);MODULE_ALIAS("processor");

⌨️ 快捷键说明

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