Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branches 'pm-cpufreq', 'pm-cpuidle' and 'acpi-cppc'

* pm-cpufreq:
cpufreq: dt: Drop stale comment
cpufreq: intel_pstate: Documenation for structures
cpufreq: intel_pstate: fix inconsistency in setting policy limits
intel_pstate: Avoid extra invocation of intel_pstate_sample()
intel_pstate: Do not set utilization update hook too early

* pm-cpuidle:
intel_idle: Add KBL support
intel_idle: Add SKX support
intel_idle: Clean up all registered devices on exit.
intel_idle: Propagate hot plug errors.
intel_idle: Don't overreact to a cpuidle registration failure.
intel_idle: Setup the timer broadcast only on successful driver load.
intel_idle: Avoid a double free of the per-CPU data.
intel_idle: Fix dangling registration on error path.
intel_idle: Fix deallocation order on the driver exit path.
intel_idle: Remove redundant initialization calls.
intel_idle: Fix a helper function's return value.
intel_idle: remove useless return from void function.

* acpi-cppc:
mailbox: pcc: Don't access an unmapped memory address space

+258 -52
-3
drivers/cpufreq/cpufreq-dt.c
··· 4 4 * Copyright (C) 2014 Linaro. 5 5 * Viresh Kumar <viresh.kumar@linaro.org> 6 6 * 7 - * The OPP code in function set_target() is reused from 8 - * drivers/cpufreq/omap-cpufreq.c 9 - * 10 7 * This program is free software; you can redistribute it and/or modify 11 8 * it under the terms of the GNU General Public License version 2 as 12 9 * published by the Free Software Foundation.
+189 -17
drivers/cpufreq/intel_pstate.c
··· 64 64 return ret; 65 65 } 66 66 67 + /** 68 + * struct sample - Store performance sample 69 + * @core_pct_busy: Ratio of APERF/MPERF in percent, which is actual 70 + * performance during last sample period 71 + * @busy_scaled: Scaled busy value which is used to calculate next 72 + * P state. This can be different than core_pct_busy 73 + * to account for cpu idle period 74 + * @aperf: Difference of actual performance frequency clock count 75 + * read from APERF MSR between last and current sample 76 + * @mperf: Difference of maximum performance frequency clock count 77 + * read from MPERF MSR between last and current sample 78 + * @tsc: Difference of time stamp counter between last and 79 + * current sample 80 + * @freq: Effective frequency calculated from APERF/MPERF 81 + * @time: Current time from scheduler 82 + * 83 + * This structure is used in the cpudata structure to store performance sample 84 + * data for choosing next P State. 85 + */ 67 86 struct sample { 68 87 int32_t core_pct_busy; 69 88 int32_t busy_scaled; ··· 93 74 u64 time; 94 75 }; 95 76 77 + /** 78 + * struct pstate_data - Store P state data 79 + * @current_pstate: Current requested P state 80 + * @min_pstate: Min P state possible for this platform 81 + * @max_pstate: Max P state possible for this platform 82 + * @max_pstate_physical:This is physical Max P state for a processor 83 + * This can be higher than the max_pstate which can 84 + * be limited by platform thermal design power limits 85 + * @scaling: Scaling factor to convert frequency to cpufreq 86 + * frequency units 87 + * @turbo_pstate: Max Turbo P state possible for this platform 88 + * 89 + * Stores the per cpu model P state limits and current P state. 90 + */ 96 91 struct pstate_data { 97 92 int current_pstate; 98 93 int min_pstate; ··· 116 83 int turbo_pstate; 117 84 }; 118 85 86 + /** 87 + * struct vid_data - Stores voltage information data 88 + * @min: VID data for this platform corresponding to 89 + * the lowest P state 90 + * @max: VID data corresponding to the highest P State. 91 + * @turbo: VID data for turbo P state 92 + * @ratio: Ratio of (vid max - vid min) / 93 + * (max P state - Min P State) 94 + * 95 + * Stores the voltage data for DVFS (Dynamic Voltage and Frequency Scaling) 96 + * This data is used in Atom platforms, where in addition to target P state, 97 + * the voltage data needs to be specified to select next P State. 98 + */ 119 99 struct vid_data { 120 100 int min; 121 101 int max; ··· 136 90 int32_t ratio; 137 91 }; 138 92 93 + /** 94 + * struct _pid - Stores PID data 95 + * @setpoint: Target set point for busyness or performance 96 + * @integral: Storage for accumulated error values 97 + * @p_gain: PID proportional gain 98 + * @i_gain: PID integral gain 99 + * @d_gain: PID derivative gain 100 + * @deadband: PID deadband 101 + * @last_err: Last error storage for integral part of PID calculation 102 + * 103 + * Stores PID coefficients and last error for PID controller. 104 + */ 139 105 struct _pid { 140 106 int setpoint; 141 107 int32_t integral; ··· 158 100 int32_t last_err; 159 101 }; 160 102 103 + /** 104 + * struct cpudata - Per CPU instance data storage 105 + * @cpu: CPU number for this instance data 106 + * @update_util: CPUFreq utility callback information 107 + * @pstate: Stores P state limits for this CPU 108 + * @vid: Stores VID limits for this CPU 109 + * @pid: Stores PID parameters for this CPU 110 + * @last_sample_time: Last Sample time 111 + * @prev_aperf: Last APERF value read from APERF MSR 112 + * @prev_mperf: Last MPERF value read from MPERF MSR 113 + * @prev_tsc: Last timestamp counter (TSC) value 114 + * @prev_cummulative_iowait: IO Wait time difference from last and 115 + * current sample 116 + * @sample: Storage for storing last Sample data 117 + * 118 + * This structure stores per CPU instance data for all CPUs. 119 + */ 161 120 struct cpudata { 162 121 int cpu; 163 122 ··· 193 118 }; 194 119 195 120 static struct cpudata **all_cpu_data; 121 + 122 + /** 123 + * struct pid_adjust_policy - Stores static PID configuration data 124 + * @sample_rate_ms: PID calculation sample rate in ms 125 + * @sample_rate_ns: Sample rate calculation in ns 126 + * @deadband: PID deadband 127 + * @setpoint: PID Setpoint 128 + * @p_gain_pct: PID proportional gain 129 + * @i_gain_pct: PID integral gain 130 + * @d_gain_pct: PID derivative gain 131 + * 132 + * Stores per CPU model static PID configuration data. 133 + */ 196 134 struct pstate_adjust_policy { 197 135 int sample_rate_ms; 198 136 s64 sample_rate_ns; ··· 216 128 int i_gain_pct; 217 129 }; 218 130 131 + /** 132 + * struct pstate_funcs - Per CPU model specific callbacks 133 + * @get_max: Callback to get maximum non turbo effective P state 134 + * @get_max_physical: Callback to get maximum non turbo physical P state 135 + * @get_min: Callback to get minimum P state 136 + * @get_turbo: Callback to get turbo P state 137 + * @get_scaling: Callback to get frequency scaling factor 138 + * @get_val: Callback to convert P state to actual MSR write value 139 + * @get_vid: Callback to get VID data for Atom platforms 140 + * @get_target_pstate: Callback to a function to calculate next P state to use 141 + * 142 + * Core and Atom CPU models have different way to get P State limits. This 143 + * structure is used to store those callbacks. 144 + */ 219 145 struct pstate_funcs { 220 146 int (*get_max)(void); 221 147 int (*get_max_physical)(void); ··· 241 139 int32_t (*get_target_pstate)(struct cpudata *); 242 140 }; 243 141 142 + /** 143 + * struct cpu_defaults- Per CPU model default config data 144 + * @pid_policy: PID config data 145 + * @funcs: Callback function data 146 + */ 244 147 struct cpu_defaults { 245 148 struct pstate_adjust_policy pid_policy; 246 149 struct pstate_funcs funcs; ··· 258 151 static struct pstate_funcs pstate_funcs; 259 152 static int hwp_active; 260 153 154 + 155 + /** 156 + * struct perf_limits - Store user and policy limits 157 + * @no_turbo: User requested turbo state from intel_pstate sysfs 158 + * @turbo_disabled: Platform turbo status either from msr 159 + * MSR_IA32_MISC_ENABLE or when maximum available pstate 160 + * matches the maximum turbo pstate 161 + * @max_perf_pct: Effective maximum performance limit in percentage, this 162 + * is minimum of either limits enforced by cpufreq policy 163 + * or limits from user set limits via intel_pstate sysfs 164 + * @min_perf_pct: Effective minimum performance limit in percentage, this 165 + * is maximum of either limits enforced by cpufreq policy 166 + * or limits from user set limits via intel_pstate sysfs 167 + * @max_perf: This is a scaled value between 0 to 255 for max_perf_pct 168 + * This value is used to limit max pstate 169 + * @min_perf: This is a scaled value between 0 to 255 for min_perf_pct 170 + * This value is used to limit min pstate 171 + * @max_policy_pct: The maximum performance in percentage enforced by 172 + * cpufreq setpolicy interface 173 + * @max_sysfs_pct: The maximum performance in percentage enforced by 174 + * intel pstate sysfs interface 175 + * @min_policy_pct: The minimum performance in percentage enforced by 176 + * cpufreq setpolicy interface 177 + * @min_sysfs_pct: The minimum performance in percentage enforced by 178 + * intel pstate sysfs interface 179 + * 180 + * Storage for user and policy defined limits. 181 + */ 261 182 struct perf_limits { 262 183 int no_turbo; 263 184 int turbo_disabled; ··· 1045 910 cpu->prev_aperf = aperf; 1046 911 cpu->prev_mperf = mperf; 1047 912 cpu->prev_tsc = tsc; 1048 - return true; 913 + /* 914 + * First time this function is invoked in a given cycle, all of the 915 + * previous sample data fields are equal to zero or stale and they must 916 + * be populated with meaningful numbers for things to work, so assume 917 + * that sample.time will always be reset before setting the utilization 918 + * update hook and make the caller skip the sample then. 919 + */ 920 + return !!cpu->last_sample_time; 1049 921 } 1050 922 1051 923 static inline int32_t get_avg_frequency(struct cpudata *cpu) ··· 1126 984 * enough period of time to adjust our busyness. 1127 985 */ 1128 986 duration_ns = cpu->sample.time - cpu->last_sample_time; 1129 - if ((s64)duration_ns > pid_params.sample_rate_ns * 3 1130 - && cpu->last_sample_time > 0) { 987 + if ((s64)duration_ns > pid_params.sample_rate_ns * 3) { 1131 988 sample_ratio = div_fp(int_tofp(pid_params.sample_rate_ns), 1132 989 int_tofp(duration_ns)); 1133 990 core_busy = mul_fp(core_busy, sample_ratio); ··· 1241 1100 intel_pstate_get_cpu_pstates(cpu); 1242 1101 1243 1102 intel_pstate_busy_pid_reset(cpu); 1244 - intel_pstate_sample(cpu, 0); 1245 1103 1246 1104 cpu->update_util.func = intel_pstate_update_util; 1247 - cpufreq_set_update_util_data(cpunum, &cpu->update_util); 1248 1105 1249 1106 pr_debug("intel_pstate: controlling: cpu %d\n", cpunum); 1250 1107 ··· 1261 1122 return get_avg_frequency(cpu); 1262 1123 } 1263 1124 1125 + static void intel_pstate_set_update_util_hook(unsigned int cpu_num) 1126 + { 1127 + struct cpudata *cpu = all_cpu_data[cpu_num]; 1128 + 1129 + /* Prevent intel_pstate_update_util() from using stale data. */ 1130 + cpu->sample.time = 0; 1131 + cpufreq_set_update_util_data(cpu_num, &cpu->update_util); 1132 + } 1133 + 1134 + static void intel_pstate_clear_update_util_hook(unsigned int cpu) 1135 + { 1136 + cpufreq_set_update_util_data(cpu, NULL); 1137 + synchronize_sched(); 1138 + } 1139 + 1140 + static void intel_pstate_set_performance_limits(struct perf_limits *limits) 1141 + { 1142 + limits->no_turbo = 0; 1143 + limits->turbo_disabled = 0; 1144 + limits->max_perf_pct = 100; 1145 + limits->max_perf = int_tofp(1); 1146 + limits->min_perf_pct = 100; 1147 + limits->min_perf = int_tofp(1); 1148 + limits->max_policy_pct = 100; 1149 + limits->max_sysfs_pct = 100; 1150 + limits->min_policy_pct = 0; 1151 + limits->min_sysfs_pct = 0; 1152 + } 1153 + 1264 1154 static int intel_pstate_set_policy(struct cpufreq_policy *policy) 1265 1155 { 1266 1156 if (!policy->cpuinfo.max_freq) 1267 1157 return -ENODEV; 1268 1158 1269 - if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && 1270 - policy->max >= policy->cpuinfo.max_freq) { 1271 - pr_debug("intel_pstate: set performance\n"); 1159 + intel_pstate_clear_update_util_hook(policy->cpu); 1160 + 1161 + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { 1272 1162 limits = &performance_limits; 1273 - if (hwp_active) 1274 - intel_pstate_hwp_set(policy->cpus); 1275 - return 0; 1163 + if (policy->max >= policy->cpuinfo.max_freq) { 1164 + pr_debug("intel_pstate: set performance\n"); 1165 + intel_pstate_set_performance_limits(limits); 1166 + goto out; 1167 + } 1168 + } else { 1169 + pr_debug("intel_pstate: set powersave\n"); 1170 + limits = &powersave_limits; 1276 1171 } 1277 1172 1278 - pr_debug("intel_pstate: set powersave\n"); 1279 - limits = &powersave_limits; 1280 1173 limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq; 1281 1174 limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100); 1282 1175 limits->max_policy_pct = DIV_ROUND_UP(policy->max * 100, ··· 1334 1163 limits->max_perf = div_fp(int_tofp(limits->max_perf_pct), 1335 1164 int_tofp(100)); 1336 1165 1166 + out: 1167 + intel_pstate_set_update_util_hook(policy->cpu); 1168 + 1337 1169 if (hwp_active) 1338 1170 intel_pstate_hwp_set(policy->cpus); 1339 1171 ··· 1361 1187 1362 1188 pr_debug("intel_pstate: CPU %d exiting\n", cpu_num); 1363 1189 1364 - cpufreq_set_update_util_data(cpu_num, NULL); 1365 - synchronize_sched(); 1190 + intel_pstate_clear_update_util_hook(cpu_num); 1366 1191 1367 1192 if (hwp_active) 1368 1193 return; ··· 1628 1455 get_online_cpus(); 1629 1456 for_each_online_cpu(cpu) { 1630 1457 if (all_cpu_data[cpu]) { 1631 - cpufreq_set_update_util_data(cpu, NULL); 1632 - synchronize_sched(); 1458 + intel_pstate_clear_update_util_hook(cpu); 1633 1459 kfree(all_cpu_data[cpu]); 1634 1460 } 1635 1461 }
+67 -30
drivers/idle/intel_idle.c
··· 660 660 .enter = NULL } 661 661 }; 662 662 663 + static struct cpuidle_state skx_cstates[] = { 664 + { 665 + .name = "C1-SKX", 666 + .desc = "MWAIT 0x00", 667 + .flags = MWAIT2flg(0x00), 668 + .exit_latency = 2, 669 + .target_residency = 2, 670 + .enter = &intel_idle, 671 + .enter_freeze = intel_idle_freeze, }, 672 + { 673 + .name = "C1E-SKX", 674 + .desc = "MWAIT 0x01", 675 + .flags = MWAIT2flg(0x01), 676 + .exit_latency = 10, 677 + .target_residency = 20, 678 + .enter = &intel_idle, 679 + .enter_freeze = intel_idle_freeze, }, 680 + { 681 + .name = "C6-SKX", 682 + .desc = "MWAIT 0x20", 683 + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 684 + .exit_latency = 133, 685 + .target_residency = 600, 686 + .enter = &intel_idle, 687 + .enter_freeze = intel_idle_freeze, }, 688 + { 689 + .enter = NULL } 690 + }; 691 + 663 692 static struct cpuidle_state atom_cstates[] = { 664 693 { 665 694 .name = "C1E-ATM", ··· 847 818 * driver in this case 848 819 */ 849 820 dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu); 850 - if (!dev->registered) 851 - intel_idle_cpu_init(hotcpu); 821 + if (dev->registered) 822 + break; 823 + 824 + if (intel_idle_cpu_init(hotcpu)) 825 + return NOTIFY_BAD; 852 826 853 827 break; 854 828 } ··· 936 904 .disable_promotion_to_c1e = true, 937 905 }; 938 906 907 + static const struct idle_cpu idle_cpu_skx = { 908 + .state_table = skx_cstates, 909 + .disable_promotion_to_c1e = true, 910 + }; 939 911 940 912 static const struct idle_cpu idle_cpu_avn = { 941 913 .state_table = avn_cstates, ··· 981 945 ICPU(0x56, idle_cpu_bdw), 982 946 ICPU(0x4e, idle_cpu_skl), 983 947 ICPU(0x5e, idle_cpu_skl), 948 + ICPU(0x8e, idle_cpu_skl), 949 + ICPU(0x9e, idle_cpu_skl), 950 + ICPU(0x55, idle_cpu_skx), 984 951 ICPU(0x57, idle_cpu_knl), 985 952 {} 986 953 }; ··· 1026 987 icpu = (const struct idle_cpu *)id->driver_data; 1027 988 cpuidle_state_table = icpu->state_table; 1028 989 1029 - if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ 1030 - lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; 1031 - else 1032 - on_each_cpu(__setup_broadcast_timer, (void *)true, 1); 1033 - 1034 990 pr_debug(PREFIX "v" INTEL_IDLE_VERSION 1035 991 " model 0x%X\n", boot_cpu_data.x86_model); 1036 992 1037 - pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n", 1038 - lapic_timer_reliable_states); 1039 993 return 0; 1040 994 } 1041 995 1042 996 /* 1043 997 * intel_idle_cpuidle_devices_uninit() 1044 - * unregister, free cpuidle_devices 998 + * Unregisters the cpuidle devices. 1045 999 */ 1046 1000 static void intel_idle_cpuidle_devices_uninit(void) 1047 1001 { ··· 1045 1013 dev = per_cpu_ptr(intel_idle_cpuidle_devices, i); 1046 1014 cpuidle_unregister_device(dev); 1047 1015 } 1048 - 1049 - free_percpu(intel_idle_cpuidle_devices); 1050 - return; 1051 1016 } 1052 1017 1053 1018 /* ··· 1140 1111 * intel_idle_cpuidle_driver_init() 1141 1112 * allocate, initialize cpuidle_states 1142 1113 */ 1143 - static int __init intel_idle_cpuidle_driver_init(void) 1114 + static void __init intel_idle_cpuidle_driver_init(void) 1144 1115 { 1145 1116 int cstate; 1146 1117 struct cpuidle_driver *drv = &intel_idle_driver; ··· 1192 1163 drv->state_count += 1; 1193 1164 } 1194 1165 1195 - if (icpu->auto_demotion_disable_flags) 1196 - on_each_cpu(auto_demotion_disable, NULL, 1); 1197 - 1198 1166 if (icpu->byt_auto_demotion_disable_flag) { 1199 1167 wrmsrl(MSR_CC6_DEMOTION_POLICY_CONFIG, 0); 1200 1168 wrmsrl(MSR_MC6_DEMOTION_POLICY_CONFIG, 0); 1201 1169 } 1202 - 1203 - if (icpu->disable_promotion_to_c1e) /* each-cpu is redundant */ 1204 - on_each_cpu(c1e_promotion_disable, NULL, 1); 1205 - 1206 - return 0; 1207 1170 } 1208 1171 1209 1172 ··· 1214 1193 1215 1194 if (cpuidle_register_device(dev)) { 1216 1195 pr_debug(PREFIX "cpuidle_register_device %d failed!\n", cpu); 1217 - intel_idle_cpuidle_devices_uninit(); 1218 1196 return -EIO; 1219 1197 } 1220 1198 ··· 1238 1218 if (retval) 1239 1219 return retval; 1240 1220 1221 + intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); 1222 + if (intel_idle_cpuidle_devices == NULL) 1223 + return -ENOMEM; 1224 + 1241 1225 intel_idle_cpuidle_driver_init(); 1242 1226 retval = cpuidle_register_driver(&intel_idle_driver); 1243 1227 if (retval) { 1244 1228 struct cpuidle_driver *drv = cpuidle_get_driver(); 1245 1229 printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", 1246 1230 drv ? drv->name : "none"); 1231 + free_percpu(intel_idle_cpuidle_devices); 1247 1232 return retval; 1248 1233 } 1249 - 1250 - intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); 1251 - if (intel_idle_cpuidle_devices == NULL) 1252 - return -ENOMEM; 1253 1234 1254 1235 cpu_notifier_register_begin(); 1255 1236 1256 1237 for_each_online_cpu(i) { 1257 1238 retval = intel_idle_cpu_init(i); 1258 1239 if (retval) { 1240 + intel_idle_cpuidle_devices_uninit(); 1259 1241 cpu_notifier_register_done(); 1260 1242 cpuidle_unregister_driver(&intel_idle_driver); 1243 + free_percpu(intel_idle_cpuidle_devices); 1261 1244 return retval; 1262 1245 } 1263 1246 } 1264 1247 __register_cpu_notifier(&cpu_hotplug_notifier); 1265 1248 1249 + if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ 1250 + lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; 1251 + else 1252 + on_each_cpu(__setup_broadcast_timer, (void *)true, 1); 1253 + 1266 1254 cpu_notifier_register_done(); 1255 + 1256 + pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n", 1257 + lapic_timer_reliable_states); 1267 1258 1268 1259 return 0; 1269 1260 } 1270 1261 1271 1262 static void __exit intel_idle_exit(void) 1272 1263 { 1273 - intel_idle_cpuidle_devices_uninit(); 1274 - cpuidle_unregister_driver(&intel_idle_driver); 1264 + struct cpuidle_device *dev; 1265 + int i; 1275 1266 1276 1267 cpu_notifier_register_begin(); 1277 1268 ··· 1290 1259 on_each_cpu(__setup_broadcast_timer, (void *)false, 1); 1291 1260 __unregister_cpu_notifier(&cpu_hotplug_notifier); 1292 1261 1262 + for_each_possible_cpu(i) { 1263 + dev = per_cpu_ptr(intel_idle_cpuidle_devices, i); 1264 + cpuidle_unregister_device(dev); 1265 + } 1266 + 1293 1267 cpu_notifier_register_done(); 1294 1268 1295 - return; 1269 + cpuidle_unregister_driver(&intel_idle_driver); 1270 + free_percpu(intel_idle_cpuidle_devices); 1296 1271 } 1297 1272 1298 1273 module_init(intel_idle_init);
+2 -2
drivers/mailbox/pcc.c
··· 361 361 struct acpi_generic_address *db_reg; 362 362 struct acpi_pcct_hw_reduced *pcct_ss; 363 363 pcc_mbox_channels[i].con_priv = pcct_entry; 364 - pcct_entry = (struct acpi_subtable_header *) 365 - ((unsigned long) pcct_entry + pcct_entry->length); 366 364 367 365 /* If doorbell is in system memory cache the virt address */ 368 366 pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry; ··· 368 370 if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) 369 371 pcc_doorbell_vaddr[i] = acpi_os_ioremap(db_reg->address, 370 372 db_reg->bit_width/8); 373 + pcct_entry = (struct acpi_subtable_header *) 374 + ((unsigned long) pcct_entry + pcct_entry->length); 371 375 } 372 376 373 377 pcc_mbox_ctrl.num_chans = count;