therm_pm72.c

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

C
2,259
字号
		start = jiffies;		down(&driver_lock);		/* Tickle the FCU just in case */		if (--fcu_tickle_ticks < 0) {			fcu_tickle_ticks = FCU_TICKLE_TICKS;			tickle_fcu();		}		/* First, we always calculate the new DIMMs state on an Xserve */		if (rackmac)			do_monitor_dimms(&dimms_state);		/* Then, the CPUs */		if (cpu_pid_type == CPU_PID_TYPE_COMBINED)			do_monitor_cpu_combined();		else if (cpu_pid_type == CPU_PID_TYPE_RACKMAC) {			do_monitor_cpu_rack(&cpu_state[0]);			if (cpu_state[1].monitor != NULL)				do_monitor_cpu_rack(&cpu_state[1]);			// better deal with UP		} else {			do_monitor_cpu_split(&cpu_state[0]);			if (cpu_state[1].monitor != NULL)				do_monitor_cpu_split(&cpu_state[1]);			// better deal with UP		}		/* Then, the rest */		do_monitor_backside(&backside_state);		if (rackmac)			do_monitor_slots(&slots_state);		else			do_monitor_drives(&drives_state);		up(&driver_lock);		if (critical_state == 1) {			printk(KERN_WARNING "Temperature control detected a critical condition\n");			printk(KERN_WARNING "Attempting to shut down...\n");			if (call_critical_overtemp()) {				printk(KERN_WARNING "Can't call %s, power off now!\n",				       critical_overtemp_path);				machine_power_off();			}		}		if (critical_state > 0)			critical_state++;		if (critical_state > MAX_CRITICAL_STATE) {			printk(KERN_WARNING "Shutdown timed out, power off now !\n");			machine_power_off();		}		// FIXME: Deal with signals		elapsed = jiffies - start;		if (elapsed < HZ)			schedule_timeout_interruptible(HZ - elapsed);	} out:	DBG("main_control_loop ended\n");	ctrl_task = 0;	complete_and_exit(&ctrl_complete, 0);}/* * Dispose the control loops when tearing down */static void dispose_control_loops(void){	dispose_cpu_state(&cpu_state[0]);	dispose_cpu_state(&cpu_state[1]);	dispose_backside_state(&backside_state);	dispose_drives_state(&drives_state);	dispose_slots_state(&slots_state);	dispose_dimms_state(&dimms_state);}/* * Create the control loops. U3-0 i2c bus is up, so we can now * get to the various sensors */static int create_control_loops(void){	struct device_node *np;	/* Count CPUs from the device-tree, we don't care how many are	 * actually used by Linux	 */	cpu_count = 0;	for (np = NULL; NULL != (np = of_find_node_by_type(np, "cpu"));)		cpu_count++;	DBG("counted %d CPUs in the device-tree\n", cpu_count);	/* Decide the type of PID algorithm to use based on the presence of	 * the pumps, though that may not be the best way, that is good enough	 * for now	 */	if (rackmac)		cpu_pid_type = CPU_PID_TYPE_RACKMAC;	else if (machine_is_compatible("PowerMac7,3")	    && (cpu_count > 1)	    && fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID	    && fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) {		printk(KERN_INFO "Liquid cooling pumps detected, using new algorithm !\n");		cpu_pid_type = CPU_PID_TYPE_COMBINED;	} else		cpu_pid_type = CPU_PID_TYPE_SPLIT;	/* Create control loops for everything. If any fail, everything	 * fails	 */	if (init_cpu_state(&cpu_state[0], 0))		goto fail;	if (cpu_pid_type == CPU_PID_TYPE_COMBINED)		fetch_cpu_pumps_minmax();	if (cpu_count > 1 && init_cpu_state(&cpu_state[1], 1))		goto fail;	if (init_backside_state(&backside_state))		goto fail;	if (rackmac && init_dimms_state(&dimms_state))		goto fail;	if (rackmac && init_slots_state(&slots_state))		goto fail;	if (!rackmac && init_drives_state(&drives_state))		goto fail;	DBG("all control loops up !\n");	return 0;	 fail:	DBG("failure creating control loops, disposing\n");	dispose_control_loops();	return -ENODEV;}/* * Start the control loops after everything is up, that is create * the thread that will make them run */static void start_control_loops(void){	init_completion(&ctrl_complete);	ctrl_task = kernel_thread(main_control_loop, NULL, SIGCHLD | CLONE_KERNEL);}/* * Stop the control loops when tearing down */static void stop_control_loops(void){	if (ctrl_task != 0)		wait_for_completion(&ctrl_complete);}/* * Attach to the i2c FCU after detecting U3-1 bus */static int attach_fcu(void){	fcu = attach_i2c_chip(FAN_CTRLER_ID, "fcu");	if (fcu == NULL)		return -ENODEV;	DBG("FCU attached\n");	return 0;}/* * Detach from the i2c FCU when tearing down */static void detach_fcu(void){	if (fcu)		detach_i2c_chip(fcu);	fcu = NULL;}/* * Attach to the i2c controller. We probe the various chips based * on the device-tree nodes and build everything for the driver to * run, we then kick the driver monitoring thread */static int therm_pm72_attach(struct i2c_adapter *adapter){	down(&driver_lock);	/* Check state */	if (state == state_detached)		state = state_attaching;	if (state != state_attaching) {		up(&driver_lock);		return 0;	}	/* Check if we are looking for one of these */	if (u3_0 == NULL && !strcmp(adapter->name, "u3 0")) {		u3_0 = adapter;		DBG("found U3-0\n");		if (k2 || !rackmac)			if (create_control_loops())				u3_0 = NULL;	} else if (u3_1 == NULL && !strcmp(adapter->name, "u3 1")) {		u3_1 = adapter;		DBG("found U3-1, attaching FCU\n");		if (attach_fcu())			u3_1 = NULL;	} else if (k2 == NULL && !strcmp(adapter->name, "mac-io 0")) {		k2 = adapter;		DBG("Found K2\n");		if (u3_0 && rackmac)			if (create_control_loops())				k2 = NULL;	}	/* We got all we need, start control loops */	if (u3_0 != NULL && u3_1 != NULL && (k2 || !rackmac)) {		DBG("everything up, starting control loops\n");		state = state_attached;		start_control_loops();	}	up(&driver_lock);	return 0;}/* * Called on every adapter when the driver or the i2c controller * is going away. */static int therm_pm72_detach(struct i2c_adapter *adapter){	down(&driver_lock);	if (state != state_detached)		state = state_detaching;	/* Stop control loops if any */	DBG("stopping control loops\n");	up(&driver_lock);	stop_control_loops();	down(&driver_lock);	if (u3_0 != NULL && !strcmp(adapter->name, "u3 0")) {		DBG("lost U3-0, disposing control loops\n");		dispose_control_loops();		u3_0 = NULL;	}		if (u3_1 != NULL && !strcmp(adapter->name, "u3 1")) {		DBG("lost U3-1, detaching FCU\n");		detach_fcu();		u3_1 = NULL;	}	if (u3_0 == NULL && u3_1 == NULL)		state = state_detached;	up(&driver_lock);	return 0;}static int fan_check_loc_match(const char *loc, int fan){	char	tmp[64];	char	*c, *e;	strlcpy(tmp, fcu_fans[fan].loc, 64);	c = tmp;	for (;;) {		e = strchr(c, ',');		if (e)			*e = 0;		if (strcmp(loc, c) == 0)			return 1;		if (e == NULL)			break;		c = e + 1;	}	return 0;}static void fcu_lookup_fans(struct device_node *fcu_node){	struct device_node *np = NULL;	int i;	/* The table is filled by default with values that are suitable	 * for the old machines without device-tree informations. We scan	 * the device-tree and override those values with whatever is	 * there	 */	DBG("Looking up FCU controls in device-tree...\n");	while ((np = of_get_next_child(fcu_node, np)) != NULL) {		int type = -1;		const char *loc;		const u32 *reg;		DBG(" control: %s, type: %s\n", np->name, np->type);		/* Detect control type */		if (!strcmp(np->type, "fan-rpm-control") ||		    !strcmp(np->type, "fan-rpm"))			type = FCU_FAN_RPM;		if (!strcmp(np->type, "fan-pwm-control") ||		    !strcmp(np->type, "fan-pwm"))			type = FCU_FAN_PWM;		/* Only care about fans for now */		if (type == -1)			continue;		/* Lookup for a matching location */		loc = of_get_property(np, "location", NULL);		reg = of_get_property(np, "reg", NULL);		if (loc == NULL || reg == NULL)			continue;		DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);		for (i = 0; i < FCU_FAN_COUNT; i++) {			int fan_id;			if (!fan_check_loc_match(loc, i))				continue;			DBG(" location match, index: %d\n", i);			fcu_fans[i].id = FCU_FAN_ABSENT_ID;			if (type != fcu_fans[i].type) {				printk(KERN_WARNING "therm_pm72: Fan type mismatch "				       "in device-tree for %s\n", np->full_name);				break;			}			if (type == FCU_FAN_RPM)				fan_id = ((*reg) - 0x10) / 2;			else				fan_id = ((*reg) - 0x30) / 2;			if (fan_id > 7) {				printk(KERN_WARNING "therm_pm72: Can't parse "				       "fan ID in device-tree for %s\n", np->full_name);				break;			}			DBG(" fan id -> %d, type -> %d\n", fan_id, type);			fcu_fans[i].id = fan_id;		}	}	/* Now dump the array */	printk(KERN_INFO "Detected fan controls:\n");	for (i = 0; i < FCU_FAN_COUNT; i++) {		if (fcu_fans[i].id == FCU_FAN_ABSENT_ID)			continue;		printk(KERN_INFO "  %d: %s fan, id %d, location: %s\n", i,		       fcu_fans[i].type == FCU_FAN_RPM ? "RPM" : "PWM",		       fcu_fans[i].id, fcu_fans[i].loc);	}}static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match){	state = state_detached;	/* Lookup the fans in the device tree */	fcu_lookup_fans(dev->node);	/* Add the driver */	return i2c_add_driver(&therm_pm72_driver);}static int fcu_of_remove(struct of_device* dev){	i2c_del_driver(&therm_pm72_driver);	return 0;}static struct of_device_id fcu_match[] = {	{	.type		= "fcu",	},	{},};static struct of_platform_driver fcu_of_platform_driver = {	.name 		= "temperature",	.match_table	= fcu_match,	.probe		= fcu_of_probe,	.remove		= fcu_of_remove};/* * Check machine type, attach to i2c controller */static int __init therm_pm72_init(void){	struct device_node *np;	rackmac = machine_is_compatible("RackMac3,1");	if (!machine_is_compatible("PowerMac7,2") &&	    !machine_is_compatible("PowerMac7,3") &&	    !rackmac)	    	return -ENODEV;	printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION);	np = of_find_node_by_type(NULL, "fcu");	if (np == NULL) {		/* Some machines have strangely broken device-tree */		np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e");		if (np == NULL) {			    printk(KERN_ERR "Can't find FCU in device-tree !\n");			    return -ENODEV;		}	}	of_dev = of_platform_device_create(np, "temperature", NULL);	if (of_dev == NULL) {		printk(KERN_ERR "Can't register FCU platform device !\n");		return -ENODEV;	}	of_register_platform_driver(&fcu_of_platform_driver);		return 0;}static void __exit therm_pm72_exit(void){	of_unregister_platform_driver(&fcu_of_platform_driver);	if (of_dev)		of_device_unregister(of_dev);}module_init(therm_pm72_init);module_exit(therm_pm72_exit);MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");MODULE_DESCRIPTION("Driver for Apple's PowerMac G5 thermal control");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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