@@ -137,6 +137,72 @@ static const struct attribute_group power_limit_attribute_group = {
137137 .name = "power_limits"
138138};
139139
140+ static ssize_t tcc_offset_degree_celsius_show (struct device * dev ,
141+ struct device_attribute * attr , char * buf )
142+ {
143+ u64 val ;
144+ int err ;
145+
146+ err = rdmsrl_safe (MSR_IA32_TEMPERATURE_TARGET , & val );
147+ if (err )
148+ return err ;
149+
150+ val = (val >> 24 ) & 0xff ;
151+ return sprintf (buf , "%d\n" , (int )val );
152+ }
153+
154+ static int tcc_offset_update (int tcc )
155+ {
156+ u64 val ;
157+ int err ;
158+
159+ if (!tcc )
160+ return - EINVAL ;
161+
162+ err = rdmsrl_safe (MSR_IA32_TEMPERATURE_TARGET , & val );
163+ if (err )
164+ return err ;
165+
166+ val &= ~GENMASK_ULL (31 , 24 );
167+ val |= (tcc & 0xff ) << 24 ;
168+
169+ err = wrmsrl_safe (MSR_IA32_TEMPERATURE_TARGET , val );
170+ if (err )
171+ return err ;
172+
173+ return 0 ;
174+ }
175+
176+ static int tcc_offset_save ;
177+
178+ static ssize_t tcc_offset_degree_celsius_store (struct device * dev ,
179+ struct device_attribute * attr , const char * buf ,
180+ size_t count )
181+ {
182+ u64 val ;
183+ int tcc , err ;
184+
185+ err = rdmsrl_safe (MSR_PLATFORM_INFO , & val );
186+ if (err )
187+ return err ;
188+
189+ if (!(val & BIT (30 )))
190+ return - EACCES ;
191+
192+ if (kstrtoint (buf , 0 , & tcc ))
193+ return - EINVAL ;
194+
195+ err = tcc_offset_update (tcc );
196+ if (err )
197+ return err ;
198+
199+ tcc_offset_save = tcc ;
200+
201+ return count ;
202+ }
203+
204+ static DEVICE_ATTR_RW (tcc_offset_degree_celsius );
205+
140206static int stored_tjmax ; /* since it is fixed, we can have local storage */
141207
142208static int get_tjmax (void )
@@ -332,6 +398,7 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
332398 acpi_remove_notify_handler (proc_priv -> adev -> handle ,
333399 ACPI_DEVICE_NOTIFY , proc_thermal_notify );
334400 int340x_thermal_zone_remove (proc_priv -> int340x_zone );
401+ sysfs_remove_file (& proc_priv -> dev -> kobj , & dev_attr_tcc_offset_degree_celsius .attr );
335402 sysfs_remove_group (& proc_priv -> dev -> kobj ,
336403 & power_limit_attribute_group );
337404}
@@ -355,8 +422,15 @@ static int int3401_add(struct platform_device *pdev)
355422
356423 dev_info (& pdev -> dev , "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n" );
357424
358- return sysfs_create_group (& pdev -> dev .kobj ,
359- & power_limit_attribute_group );
425+ ret = sysfs_create_file (& pdev -> dev .kobj , & dev_attr_tcc_offset_degree_celsius .attr );
426+ if (ret )
427+ return ret ;
428+
429+ ret = sysfs_create_group (& pdev -> dev .kobj , & power_limit_attribute_group );
430+ if (ret )
431+ sysfs_remove_file (& pdev -> dev .kobj , & dev_attr_tcc_offset_degree_celsius .attr );
432+
433+ return ret ;
360434}
361435
362436static int int3401_remove (struct platform_device * pdev )
@@ -588,8 +662,15 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev,
588662
589663 dev_info (& pdev -> dev , "Creating sysfs group for PROC_THERMAL_PCI\n" );
590664
591- return sysfs_create_group (& pdev -> dev .kobj ,
592- & power_limit_attribute_group );
665+ ret = sysfs_create_file (& pdev -> dev .kobj , & dev_attr_tcc_offset_degree_celsius .attr );
666+ if (ret )
667+ return ret ;
668+
669+ ret = sysfs_create_group (& pdev -> dev .kobj , & power_limit_attribute_group );
670+ if (ret )
671+ sysfs_remove_file (& pdev -> dev .kobj , & dev_attr_tcc_offset_degree_celsius .attr );
672+
673+ return ret ;
593674}
594675
595676static void proc_thermal_pci_remove (struct pci_dev * pdev )
@@ -615,6 +696,8 @@ static int proc_thermal_resume(struct device *dev)
615696 proc_dev = dev_get_drvdata (dev );
616697 proc_thermal_read_ppcc (proc_dev );
617698
699+ tcc_offset_update (tcc_offset_save );
700+
618701 return 0 ;
619702}
620703#else
0 commit comments