48
48
#include <trace/events/power.h>
49
49
#include <linux/sched.h>
50
50
#include <linux/sched/smt.h>
51
+ #include <linux/mutex.h>
51
52
#include <linux/notifier.h>
52
53
#include <linux/cpu.h>
53
54
#include <linux/moduleparam.h>
55
+ #include <linux/sysfs.h>
54
56
#include <asm/cpuid.h>
55
57
#include <asm/cpu_device_id.h>
56
58
#include <asm/intel-family.h>
@@ -92,9 +94,15 @@ struct idle_cpu {
92
94
*/
93
95
unsigned long auto_demotion_disable_flags ;
94
96
bool disable_promotion_to_c1e ;
97
+ bool c1_demotion_supported ;
95
98
bool use_acpi ;
96
99
};
97
100
101
+ static bool c1_demotion_supported ;
102
+ static DEFINE_MUTEX (c1_demotion_mutex );
103
+
104
+ static struct device * sysfs_root __initdata ;
105
+
98
106
static const struct idle_cpu * icpu __initdata ;
99
107
static struct cpuidle_state * cpuidle_state_table __initdata ;
100
108
@@ -1549,18 +1557,21 @@ static const struct idle_cpu idle_cpu_gmt __initconst = {
1549
1557
static const struct idle_cpu idle_cpu_spr __initconst = {
1550
1558
.state_table = spr_cstates ,
1551
1559
.disable_promotion_to_c1e = true,
1560
+ .c1_demotion_supported = true,
1552
1561
.use_acpi = true,
1553
1562
};
1554
1563
1555
1564
static const struct idle_cpu idle_cpu_gnr __initconst = {
1556
1565
.state_table = gnr_cstates ,
1557
1566
.disable_promotion_to_c1e = true,
1567
+ .c1_demotion_supported = true,
1558
1568
.use_acpi = true,
1559
1569
};
1560
1570
1561
1571
static const struct idle_cpu idle_cpu_gnrd __initconst = {
1562
1572
.state_table = gnrd_cstates ,
1563
1573
.disable_promotion_to_c1e = true,
1574
+ .c1_demotion_supported = true,
1564
1575
.use_acpi = true,
1565
1576
};
1566
1577
@@ -1599,12 +1610,14 @@ static const struct idle_cpu idle_cpu_snr __initconst = {
1599
1610
static const struct idle_cpu idle_cpu_grr __initconst = {
1600
1611
.state_table = grr_cstates ,
1601
1612
.disable_promotion_to_c1e = true,
1613
+ .c1_demotion_supported = true,
1602
1614
.use_acpi = true,
1603
1615
};
1604
1616
1605
1617
static const struct idle_cpu idle_cpu_srf __initconst = {
1606
1618
.state_table = srf_cstates ,
1607
1619
.disable_promotion_to_c1e = true,
1620
+ .c1_demotion_supported = true,
1608
1621
.use_acpi = true,
1609
1622
};
1610
1623
@@ -2324,6 +2337,88 @@ static void __init intel_idle_cpuidle_devices_uninit(void)
2324
2337
cpuidle_unregister_device (per_cpu_ptr (intel_idle_cpuidle_devices , i ));
2325
2338
}
2326
2339
2340
+ static void intel_c1_demotion_toggle (void * enable )
2341
+ {
2342
+ unsigned long long msr_val ;
2343
+
2344
+ rdmsrl (MSR_PKG_CST_CONFIG_CONTROL , msr_val );
2345
+ /*
2346
+ * Enable/disable C1 undemotion along with C1 demotion, as this is the
2347
+ * most sensible configuration in general.
2348
+ */
2349
+ if (enable )
2350
+ msr_val |= NHM_C1_AUTO_DEMOTE | SNB_C1_AUTO_UNDEMOTE ;
2351
+ else
2352
+ msr_val &= ~(NHM_C1_AUTO_DEMOTE | SNB_C1_AUTO_UNDEMOTE );
2353
+ wrmsrl (MSR_PKG_CST_CONFIG_CONTROL , msr_val );
2354
+ }
2355
+
2356
+ static ssize_t intel_c1_demotion_store (struct device * dev ,
2357
+ struct device_attribute * attr ,
2358
+ const char * buf , size_t count )
2359
+ {
2360
+ bool enable ;
2361
+ int err ;
2362
+
2363
+ err = kstrtobool (buf , & enable );
2364
+ if (err )
2365
+ return err ;
2366
+
2367
+ mutex_lock (& c1_demotion_mutex );
2368
+ /* Enable/disable C1 demotion on all CPUs */
2369
+ on_each_cpu (intel_c1_demotion_toggle , (void * )enable , 1 );
2370
+ mutex_unlock (& c1_demotion_mutex );
2371
+
2372
+ return count ;
2373
+ }
2374
+
2375
+ static ssize_t intel_c1_demotion_show (struct device * dev ,
2376
+ struct device_attribute * attr , char * buf )
2377
+ {
2378
+ unsigned long long msr_val ;
2379
+
2380
+ /*
2381
+ * Read the MSR value for a CPU and assume it is the same for all CPUs. Any other
2382
+ * configuration would be a BIOS bug.
2383
+ */
2384
+ rdmsrl (MSR_PKG_CST_CONFIG_CONTROL , msr_val );
2385
+ return sysfs_emit (buf , "%d\n" , !!(msr_val & NHM_C1_AUTO_DEMOTE ));
2386
+ }
2387
+ static DEVICE_ATTR_RW (intel_c1_demotion );
2388
+
2389
+ static int __init intel_idle_sysfs_init (void )
2390
+ {
2391
+ int err ;
2392
+
2393
+ if (!c1_demotion_supported )
2394
+ return 0 ;
2395
+
2396
+ sysfs_root = bus_get_dev_root (& cpu_subsys );
2397
+ if (!sysfs_root )
2398
+ return 0 ;
2399
+
2400
+ err = sysfs_add_file_to_group (& sysfs_root -> kobj ,
2401
+ & dev_attr_intel_c1_demotion .attr ,
2402
+ "cpuidle" );
2403
+ if (err ) {
2404
+ put_device (sysfs_root );
2405
+ return err ;
2406
+ }
2407
+
2408
+ return 0 ;
2409
+ }
2410
+
2411
+ static void __init intel_idle_sysfs_uninit (void )
2412
+ {
2413
+ if (!sysfs_root )
2414
+ return ;
2415
+
2416
+ sysfs_remove_file_from_group (& sysfs_root -> kobj ,
2417
+ & dev_attr_intel_c1_demotion .attr ,
2418
+ "cpuidle" );
2419
+ put_device (sysfs_root );
2420
+ }
2421
+
2327
2422
static int __init intel_idle_init (void )
2328
2423
{
2329
2424
const struct x86_cpu_id * id ;
@@ -2374,6 +2469,8 @@ static int __init intel_idle_init(void)
2374
2469
auto_demotion_disable_flags = icpu -> auto_demotion_disable_flags ;
2375
2470
if (icpu -> disable_promotion_to_c1e )
2376
2471
c1e_promotion = C1E_PROMOTION_DISABLE ;
2472
+ if (icpu -> c1_demotion_supported )
2473
+ c1_demotion_supported = true;
2377
2474
if (icpu -> use_acpi || force_use_acpi )
2378
2475
intel_idle_acpi_cst_extract ();
2379
2476
} else if (!intel_idle_acpi_cst_extract ()) {
@@ -2387,6 +2484,10 @@ static int __init intel_idle_init(void)
2387
2484
if (!intel_idle_cpuidle_devices )
2388
2485
return - ENOMEM ;
2389
2486
2487
+ retval = intel_idle_sysfs_init ();
2488
+ if (retval )
2489
+ pr_warn ("failed to initialized sysfs" );
2490
+
2390
2491
intel_idle_cpuidle_driver_init (& intel_idle_driver );
2391
2492
2392
2493
retval = cpuidle_register_driver (& intel_idle_driver );
@@ -2411,6 +2512,7 @@ static int __init intel_idle_init(void)
2411
2512
intel_idle_cpuidle_devices_uninit ();
2412
2513
cpuidle_unregister_driver (& intel_idle_driver );
2413
2514
init_driver_fail :
2515
+ intel_idle_sysfs_uninit ();
2414
2516
free_percpu (intel_idle_cpuidle_devices );
2415
2517
return retval ;
2416
2518
0 commit comments