Reduced number of syscalls
This commit is contained in:
		
							parent
							
								
									afdddabc0c
								
							
						
					
					
						commit
						34bbcf7883
					
				| @ -62,7 +62,8 @@ int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus) | ||||
| 				/* Matched all PCI IDs, check for good firmware read */ | ||||
| 				strcpy(dev_file, "/dev/"); | ||||
| 				strcat(dev_file, ent->d_name); | ||||
| 				if (check_for_icx3(dev_file)) { | ||||
| 				infos[num_gpus].i2c_dev_path = dev_file; | ||||
| 				if (icx3_init(&infos[num_gpus]) > 0) { | ||||
| 					/* Write our card info into the provided struct array */ | ||||
| 					infos[num_gpus].card_name = evga_pci_ids[i].card_name; | ||||
| 					infos[num_gpus].pci_id = pci_addr; | ||||
|  | ||||
| @ -1,3 +1,6 @@ | ||||
| #ifndef EVGA_CARD_H | ||||
| #define EVGA_CARD_H | ||||
| 
 | ||||
| #define NVIDIA_VEN                                      0x10DE | ||||
| 
 | ||||
| #define NVIDIA_RTX3060_DEV                              0x2503 | ||||
| @ -85,6 +88,7 @@ struct card_info { | ||||
| 	char *pci_id; | ||||
| 	char *i2c_dev_path; | ||||
| 	int i2c_fd; | ||||
| 	int product_id; | ||||
| }; | ||||
| 
 | ||||
| struct gpu_pci_info { | ||||
| @ -159,3 +163,5 @@ static struct gpu_pci_info evga_pci_ids[] = | ||||
| int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus); | ||||
| unsigned short read_pci_id(char *device_path, char *field); | ||||
| char *read_nvidia_pci_address(char *device_path); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										14
									
								
								evga-icx.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								evga-icx.c
									
									
									
									
									
								
							| @ -105,15 +105,13 @@ int main (int argc, char **argv) | ||||
| 		for (int i = 0; i < gpu_count; i++){ | ||||
| 			for (int j = 0; j < ICX3_MAX_FANS; j++) { | ||||
| 				if (fan_speed[j] != NULL) | ||||
| 					set_fan(j, fan_speed[j], gpus[i].i2c_dev_path); | ||||
| 					/* printf("gpu %d fan %d : %s\n", i, j, fan_speed[j]); */ | ||||
| 					set_fan(j, fan_speed[j], &gpus[i]); | ||||
| 			} | ||||
| 		} | ||||
| 	} else if (gpu_num <= gpu_count - 1) { | ||||
| 		for (int j = 0; j < ICX3_MAX_FANS; j++) { | ||||
| 			if (fan_speed[j] != NULL) | ||||
| 				set_fan(gpu_num, fan_speed[j], gpus[gpu_num].i2c_dev_path); | ||||
| 				/* printf("gpu %d fan %d : %s\n", gpu_num, j, fan_speed[j]);*/ | ||||
| 				set_fan(gpu_num, fan_speed[j], &gpus[gpu_num]); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| @ -133,13 +131,13 @@ int main (int argc, char **argv) | ||||
| void print_gpu_info(int gpu_num, struct card_info gpus[], int compact) { | ||||
| 	if (compact) { | ||||
| 		printf("#%d ", gpu_num); | ||||
| 		print_icx3_fans_oneline(gpus[gpu_num].i2c_dev_path); | ||||
| 		print_icx3_temps_oneline(gpus[gpu_num].i2c_dev_path); | ||||
| 		print_icx3_fans_oneline(&gpus[gpu_num]); | ||||
| 		print_icx3_temps_oneline(&gpus[gpu_num]); | ||||
| 		printf("\n"); | ||||
| 	} else { | ||||
| 		printf("#%d: %s (%s) @ %s\n", gpu_num, gpus[gpu_num].card_name, gpus[gpu_num].i2c_dev_path, gpus[gpu_num].pci_id); | ||||
| 		print_icx3_fans(gpus[gpu_num].i2c_dev_path); | ||||
| 		print_icx3_temps(gpus[gpu_num].i2c_dev_path); | ||||
| 		print_icx3_fans(&gpus[gpu_num]); | ||||
| 		print_icx3_temps(&gpus[gpu_num]); | ||||
| 		printf("\n"); | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
							
								
								
									
										126
									
								
								icx3.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								icx3.c
									
									
									
									
									
								
							| @ -9,32 +9,42 @@ | ||||
| 
 | ||||
| #include "icx3.h" | ||||
| 
 | ||||
| /* Check an I2C device file for an ICX3 controller, returns the product id, or ICX3_PRODUCT_NONE on bad read. */ | ||||
| enum icx3_product_id check_for_icx3(char *i2c_dev_path) | ||||
| int icx3_init(struct card_info *card) | ||||
| { | ||||
| 	char data[I2C_SMBUS_BLOCK_MAX] = {}; | ||||
| 	int fd, read_result; | ||||
| 	int read_result; | ||||
| 	struct icx3_info *temp_info; | ||||
| 	 | ||||
| 	fd = open_i2c_dev(i2c_dev_path); | ||||
| 	if (fd == -1) | ||||
| 		return ICX3_PRODUCT_NONE; | ||||
| 	int fd = open(card->i2c_dev_path, O_RDONLY); | ||||
| 	 | ||||
| 	read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, data); | ||||
| 	if (fd == -1) | ||||
| 		return -1; | ||||
| 	 | ||||
| 	if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) { | ||||
| 		close(fd); | ||||
| 	if (read_result == ICX3_READINFORMATION_SIZE) { | ||||
| 		temp_info = (struct icx3_info*)&data; | ||||
| 		if (temp_info->slave_address == ICX3_I2C_ADDR) | ||||
| 			return temp_info->product_id; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	return ICX3_PRODUCT_NONE; | ||||
| 	read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, data); | ||||
| 	if (read_result == ICX3_READINFORMATION_SIZE) { | ||||
| 		temp_info = (struct icx3_info*)&data; | ||||
| 		if (temp_info->slave_address == ICX3_I2C_ADDR) { | ||||
| 			card->product_id = temp_info->product_id; | ||||
| 			card->i2c_fd = fd; | ||||
| 			return fd; | ||||
| 		} else { | ||||
| 			close(fd); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| void print_icx3_fans(char *i2c_dev_path) | ||||
| void print_icx3_fans(struct card_info *card) | ||||
| { | ||||
| 	struct icx3_fan_control fans[ICX3_MAX_FANS];  | ||||
| 	get_fan_status(fans, i2c_dev_path); | ||||
| 	get_fan_status(fans, card); | ||||
| 	 | ||||
| 	for (int i=0; i < ICX3_MAX_FANS; i++) {		 | ||||
| 		printf("%s: %d RPM (%d/%d%%, %s)\n", | ||||
| @ -47,10 +57,10 @@ void print_icx3_fans(char *i2c_dev_path) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void print_icx3_fans_oneline(char *i2c_dev_path) | ||||
| void print_icx3_fans_oneline(struct card_info *card) | ||||
| { | ||||
| 	struct icx3_fan_control fans[ICX3_MAX_FANS];  | ||||
| 	get_fan_status(fans, i2c_dev_path); | ||||
| 	get_fan_status(fans, card); | ||||
| 	 | ||||
| 	printf("FAN"); | ||||
| 	for (int i=0; i < ICX3_MAX_FANS; i++) {		 | ||||
| @ -59,11 +69,11 @@ void print_icx3_fans_oneline(char *i2c_dev_path) | ||||
| 	printf("%%"); | ||||
| } | ||||
| 
 | ||||
| void print_icx3_temps(char *i2c_dev_path) | ||||
| void print_icx3_temps(struct card_info *card) | ||||
| { | ||||
| 	float temps[ICX3_NUM_TEMP_SENSORS]; | ||||
| 	 | ||||
| 	get_temp_sensors(temps, i2c_dev_path); | ||||
| 	get_temp_sensors(temps, card); | ||||
| 	 | ||||
| 	for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) { | ||||
| 		printf("%s: %+.1f°C\n", | ||||
| @ -72,11 +82,11 @@ void print_icx3_temps(char *i2c_dev_path) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void print_icx3_temps_oneline(char *i2c_dev_path) | ||||
| void print_icx3_temps_oneline(struct card_info *card) | ||||
| { | ||||
| 	float temps[ICX3_NUM_TEMP_SENSORS]; | ||||
| 	 | ||||
| 	get_temp_sensors(temps, i2c_dev_path); | ||||
| 	get_temp_sensors(temps, card); | ||||
| 	 | ||||
| 	for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) { | ||||
| 		if (i == 0 || strncmp(icx3_temp_sensor_names[i], icx3_temp_sensor_names[i-1], 3)) | ||||
| @ -86,9 +96,9 @@ void print_icx3_temps_oneline(char *i2c_dev_path) | ||||
| 	printf("°C"); | ||||
| } | ||||
| 
 | ||||
| void get_available_fans(char *i2c_dev_path, char *fans_avail) | ||||
| void get_available_fans(char *fans_avail, struct card_info *card) | ||||
| { | ||||
| 	int product_id = check_for_icx3(i2c_dev_path); | ||||
| 	int product_id = card->product_id; | ||||
| 	 | ||||
| 	/* From ICX3TotalFanCtrl.cs */ | ||||
| 	switch(product_id) { | ||||
| @ -142,47 +152,34 @@ void get_available_fans(char *i2c_dev_path, char *fans_avail) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void get_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path) | ||||
| void get_fan_status(struct icx3_fan_control *fans, struct card_info *card) | ||||
| { | ||||
| 	char data[I2C_SMBUS_BLOCK_MAX] = {}; | ||||
| 	int fd, read_result; | ||||
| 	int read_result; | ||||
| 	 | ||||
| 	/* First thing is to check for the product ID to figure out how many fans we have */ | ||||
| 	char fans_avail[ICX3_MAX_FANS] = {0}; | ||||
| 	get_available_fans(i2c_dev_path, fans_avail); | ||||
| 	 | ||||
| 	fd = open_i2c_dev(i2c_dev_path); | ||||
| 	if (fd == -1) | ||||
| 		return; | ||||
| 	get_available_fans(fans_avail, card); | ||||
| 		 | ||||
| 	for (int i=0; i < ICX3_MAX_FANS; i++) { | ||||
| 		if (!fans_avail[i]) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		 | ||||
| 		read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data); | ||||
| 		read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data); | ||||
| 		if (read_result != ICX3_FANCONTROL_SIZE) { | ||||
| 			close(fd); | ||||
| 			return; | ||||
| 		} | ||||
| 		memcpy(&fans[i], &data, sizeof(struct icx3_fan_control)); | ||||
| 	} | ||||
| 	 | ||||
| 	close(fd); | ||||
| } | ||||
| 
 | ||||
| void get_temp_sensors(float *temps, char *i2c_dev_path) | ||||
| void get_temp_sensors(float *temps, struct card_info *card) | ||||
| { | ||||
| 	char data[I2C_SMBUS_BLOCK_MAX] = {}; | ||||
| 	int fd, read_result; | ||||
| 	int read_result; | ||||
| 	struct icx3_temp_sensors *temp_sensors; | ||||
| 		 | ||||
| 	fd = open_i2c_dev(i2c_dev_path); | ||||
| 	if (fd == -1) | ||||
| 		return; | ||||
| 	 | ||||
| 	read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data); | ||||
| 	close(fd); | ||||
| 	read_result = i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data); | ||||
| 	if (read_result != ICX3_TEMPSENSOR_SIZE) | ||||
| 		return; | ||||
| 	temp_sensors = (struct icx3_temp_sensors*) &data; | ||||
| @ -198,54 +195,34 @@ void get_temp_sensors(float *temps, char *i2c_dev_path) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int open_i2c_dev(char *i2c_dev_path) | ||||
| void enable_write(int enable, struct card_info *card) | ||||
| {	 | ||||
| 	int fd = open(i2c_dev_path, O_RDONLY); | ||||
| 	 | ||||
| 	/* Error silently here because we should have already checked we can read the i2c in check_for_icx3() */ | ||||
| 	if (fd == -1) | ||||
| 		return -1; | ||||
| 	 | ||||
| 	if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) { | ||||
| 		close(fd); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return fd; | ||||
| } | ||||
| 
 | ||||
| void enable_write(int enable, char *i2c_dev_path) | ||||
| { | ||||
| 	int fd = open_i2c_dev(i2c_dev_path); | ||||
| 	if (fd == -1) | ||||
| 		return; | ||||
| 	 | ||||
| 	unsigned char *data; | ||||
| 	if (enable) | ||||
| 		data = icx3_write_enable; | ||||
| 	else | ||||
| 		data = icx3_write_disable; | ||||
| 	/* Enable or disable write */ | ||||
|     i2c_smbus_write_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data); | ||||
|     i2c_smbus_write_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, data); | ||||
| 	 | ||||
| 	/* Read back the result to verify */ | ||||
| 	unsigned char read_result[ICX3_ENABLEWRITE_SIZE]; | ||||
| 	int write_ok = 0; | ||||
| 	i2c_smbus_read_i2c_block_data(fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result); | ||||
| 	i2c_smbus_read_i2c_block_data(card->i2c_fd, ICX3_REG_ENABLEWRITE, ICX3_ENABLEWRITE_SIZE, read_result); | ||||
| 	if (enable) | ||||
| 		write_ok = (read_result[1] == 0xFC); | ||||
| 	else | ||||
| 		write_ok = (read_result[1] == 0xFE); | ||||
| 	 | ||||
| 	if (!write_ok) | ||||
| 		printf("Unable to enable/disable write on %s\n", i2c_dev_path); | ||||
| 
 | ||||
| 		printf("Unable to enable/disable write on %s\n", card->i2c_dev_path); | ||||
| } | ||||
| 
 | ||||
| /* Sets a given fan on the GPU according to a string setting
 | ||||
| 'auto' resets the fan to default (fans 1-2 go to GPU control, 3-4 to +0 RPM offset from GPU control) | ||||
| A number without a sign (e.g. 50) manually sets the fan to a given % duty cycle | ||||
| A number with a sign (e.g. +500) sets the fan to run at an RPM offset from GPU control */ | ||||
| void set_fan(int fan, char *setting, char *i2c_dev_path) | ||||
| void set_fan(int fan, char *setting, struct card_info *card) | ||||
| { | ||||
| 	char fans_avail[ICX3_MAX_FANS] = {0}; | ||||
| 	 | ||||
| @ -256,16 +233,12 @@ void set_fan(int fan, char *setting, char *i2c_dev_path) | ||||
| 	int write_result; | ||||
| 	 | ||||
| 	/* Check to make sure we're setting a valid fan */ | ||||
| 	get_available_fans(i2c_dev_path, fans_avail); | ||||
| 	get_available_fans(fans_avail, card); | ||||
| 	if (fans_avail[fan] == 0) { | ||||
| 		printf("Fan %d does not exist on this card \n", fan); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	int fp = open_i2c_dev(i2c_dev_path); | ||||
| 	if (fp == -1) | ||||
| 		return; | ||||
| 	 | ||||
| 	fan_control.length = ICX3_FANCONTROL_SIZE - 1; | ||||
| 	if (strcmp(setting, "auto") == 0) { | ||||
| 		/* auto setting */ | ||||
| @ -283,16 +256,15 @@ void set_fan(int fan, char *setting, char *i2c_dev_path) | ||||
| 		fan_control.duty = atoi(setting); | ||||
| 	} | ||||
| 
 | ||||
| 	enable_write(1, i2c_dev_path); | ||||
| 	enable_write(1, card); | ||||
| 	 | ||||
|     i2c_smbus_write_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control); | ||||
|     i2c_smbus_write_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_control); | ||||
| 
 | ||||
| 	/* Read back data and verify we set the fan properly */ | ||||
|     i2c_smbus_read_i2c_block_data(fp, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback); | ||||
|     i2c_smbus_read_i2c_block_data(card->i2c_fd, reg, ICX3_FANCONTROL_SIZE, (char *)&fan_readback); | ||||
| 	if (fan_readback.fanmode    != fan_control.fanmode || | ||||
| 		fan_readback.rpm_offset != fan_control.rpm_offset || | ||||
| 		fan_readback.duty       != fan_control.duty) | ||||
| 		printf("Error setting fan %d on %s\n", fan, i2c_dev_path); | ||||
| 	close(fp); | ||||
| 		printf("Error setting fan %d on %s\n", fan, card->i2c_fd); | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										28
									
								
								icx3.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								icx3.h
									
									
									
									
									
								
							| @ -1,3 +1,8 @@ | ||||
| #ifndef ICX3_H | ||||
| #define ICX3_H | ||||
| 
 | ||||
| #include "evga-card.h" | ||||
| 
 | ||||
| #define ICX3_I2C_ADDR 0x2D | ||||
| 
 | ||||
| #define ICX3_REG_FANCONTROL 80 | ||||
| @ -111,14 +116,15 @@ static char *icx3_temp_sensor_names[] = { | ||||
| 	"PWR5", | ||||
| }; | ||||
| 
 | ||||
| enum icx3_product_id check_for_icx3(char *i2c_dev_path); | ||||
| void print_icx3_fans(char *i2c_dev_path); | ||||
| void print_icx3_fans_oneline(char *i2c_dev_path); | ||||
| void print_icx3_temps(char *i2c_dev_path); | ||||
| void print_icx3_temps_oneline(char *i2c_dev_path); | ||||
| void get_available_fans(char *i2c_dev_path, char *fans_avail); | ||||
| void get_fan_status(struct icx3_fan_control *fans, char *i2c_dev_path); | ||||
| void get_temp_sensors(float *temps, char *i2c_dev_path); | ||||
| int open_i2c_dev(char *i2c_dev_path); | ||||
| void enable_write(int enable, char *i2c_dev_path); | ||||
| void set_fan(int fan, char *setting, char *i2c_dev_path); | ||||
| int icx3_init(struct card_info *card); | ||||
| void print_icx3_fans(struct card_info *card); | ||||
| void print_icx3_fans_oneline(struct card_info *card); | ||||
| void print_icx3_temps(struct card_info *card); | ||||
| void print_icx3_temps_oneline(struct card_info *card); | ||||
| void get_available_fans(char *fans_avail, struct card_info *card); | ||||
| void get_fan_status(struct icx3_fan_control *fans, struct card_info *card); | ||||
| void get_temp_sensors(float *temps, struct card_info *card); | ||||
| void enable_write(int enable, struct card_info *card); | ||||
| void set_fan(int fan, char *setting, struct card_info *card); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user