리눅스(TM) 커널 내의 CPU 주파수와 전압 조정 코드
L i n u x C P U F r e q
C P U D r i v e r s
– 개발자를 위한 정보 –
Dominik Brodowski <linux@brodo.de>
번역: 양정석 <dasomoli@gmailREMOVETHIS.com>
Clock scaling allows you to change the clock speed of the CPUs on the
fly. This is a nice method to save battery power, because the lower
the clock speed, the less power the CPU consumes.
차례:
—–
1. 뭘 해야 하나요?
1.1 초기화
1.2 Per-CPU 초기화
1.3 검증
1.4 target을 쓸까, setpolicy를 쓸까?
1.5 target 호출
1.6 setpolicy 호출
2. 주파수 테이블 헬퍼
1. 뭘 해야 하나요?
==================
그래, 여러분이 막 새 브랜드의 CPU / 칩셋을 데이터 시트와 함께 얻게 됐고,
이 CPU / 칩셋을 위한 cpufreq 지원을 추가하고 싶다고요? 좋습니다. 여기에
필요한 것들에 대한 몇 가지 힌트들이 있어요:
1.1 초기화
———-
무엇보다 먼저, __initcall 레벨 7 (module_init()) 이나 그 이후의 함수 안에서
이 커널이 맞는 CPU와 맞는 칩셋 상에서 실행되는지를 확인하세요. 그렇다면,
struct cpufreq_driver 를 CPUfreq 코어와 함께 cpufreq_register_driver()를
사용해서 등록하세요.
이 struct cpufreq_driver 는 무엇을 포함해야 할까요?
cpufreq_driver.name – 이 드라이버의 이름.
cpufreq_driver.owner – THIS_MODULE;
cpufreq_driver.init – per-CPU 초기화 함수로의 포인터.
cpufreq_driver.verify – “검증” 함수로의 포인터.
cpufreq_driver.setpolicy _또는_
cpufreq_driver.target – 아래에서 차이에 대해 살펴보세요.
그리고 옵션으로
cpufreq_driver.exit – per-CPU 클린업 함수로의 포인터.
cpufreq_driver.resume – A pointer to a per-CPU resume function
which is called with interrupts disabled
and _before_ the pre-suspend frequency
and/or policy is restored by a call to
->target or ->setpolicy.
cpufreq_driver.resume – pre-suspend 주파수와(또는) 정책이 ->target
이나 ->setpolicy 호출로 복구되기 _전에_
인터럽트가 꺼진 상태에서 호출되는 per-CPU
resume 함수의 포인터.
cpufreq_driver.attr – sysfs 로 값을 노출시킬 “struct freq_attr”의
NULL로 끝나는 리스트의 포인터.
1.2 Per-CPU 초기화
——————
새 CPU가 디바이스 모델과 등록될 때, 또는 cpufreq 드라이버가 그 스스로를
등록한 후에, per-CPU 초기화 함수 cpufreq_driver.init이 호출됩니다.
그건 struct cpufreq_poliy *policy를 인자로 가져옵니다. 이제 뭘 하죠?
필요하면, 여러분의 CPU 상의 CPUfreq 지원을 활성화하세요.
그러면, 그 드라이버가 다음 값들을 채워넣어야만 합니다:
policy->cpuinfo.min_freq _와_
policy->cpuinfo.max_freq – 이 CPU 가 지원하는 최저/최고 주파수(kHZ)
policy->cpuinfo.transition_latency 이 CPU 상에서 두 주파수 사이에
변환되는데 걸리는 나노초 시간(적절하다면
맞지만, 아니면 CPUFREQ_ETERNAL 지정).
policy->cur (적절하다면) 이 CPU의 현재 동작 주파수
policy->min,
policy->max,
policy->policy 그리고, 필요하다면,
policy->governor 이 CPU를 위한 “기본 정책”을 반드시 포함해야
함. 조금 지나면, cpufreq_driver.verify와
다음 둘 cpufreq_driver.setpolicy 나
cpufreq_driver.target 중 하나가 이 값들과
함께 호출됩니다.
이들 값들 중 몇을 셋팅하기 위해서 주파수 테이블 헬퍼가 도움이 될 겁니다.
자세한 사항은 섹션 2를 보시면 됩니다.
1.3 검증
——–
사용자가 셋팅하려는 (“policy,governor,min,max”로 구성된) 새로운 정책을
결정하면, 이 정책은 맞지않는 값들이 교정될 수 있도록, 반드시 유효성이
검사되어야 합니다. 이들 값의 검증을 위해서 주파수 테이블 헬퍼와(또는)
cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned
int min_freq, unsigned int max_freq) 함수가 도움이 될 겁니다. 주파수
테이블 헬퍼에 대한 자세항 사항은 섹션 2를 보시면 됩니다.
여러분은 적어도 한 유효한 주파수(또는 동작 범위)를 policy->min 과
policy->max 안에서 확인할 필요가 있습니다. 필요하다면 policy->max 를
먼저 증가시키고, 이게 해결 방법이 아닐 때만 policy->min 을 감소시키세요.
1.4 target을 쓸까, setpolicy를 쓸까?
————————————
대부분의 cpufreq 드라이버나 대부분의 CPU 주파수 조정 알고리즘조차도
한 주파수로만 CPU를 셋팅할 수 있습니다. 이를 위해서 여러분은
->target 함수를 사용합니다.
어떤 cpufreq 가능한 프로세서들은 주파수를 확실한 그들만의 제약사항 사이에서
변환합니다. 이들은 ->setpolicy 함수를 사용하는 것이 좋습니다.
1.4. target 호출
—————-
target 호출은 세가지 인자를 가집니다: struct cpufreq_policy *policy,
unsigned int target_frequency, unsigned int relation.
CPUfreq 드라이버는 여기에서 불려지는 때에 새 주파수를 반드시 셋팅해야
합니다. 실제 주파수는 다음 규칙을 사용해서 결정되어야만 합니다:
– “target_freq” 에 가깝게 유지
– policy->min <= new_freq <= policy->max (이건 반드시 유효해야 합니다!!!)
– relation==CPUFREQ_REL_L 라면, new_freq를 target_freq와 같거나 더 높게 선택
하도록 시도합니다. (“더 낮은 이 아닌, 최저(lowest)를 위한 L”)
– relation==CPUFREQ_REL_H 라면, new_freq를 target_freq와 같거나 더 낮게 선택
하도록 시도합니다. (“더 높은 이 아닌, 최고(highest)를 위한 H”)
여기서 다시, 주파수 테이블 헬퍼는 여러분을 도와줄 수 있습니다 – 자세한
사항은 섹션 2를 보세요.
1.5 setpolicy 호출
——————
setpolicy 호출은 오직 struct cpufreq_policy *policy 만 인자로 가집니다.
여러분은 가장 낮은 프로세서 내부나 칩셋 내부 동적 주파수 변환의 더 낮은
제약사항을 policy->min으로, 더 높은 제약사항을 policy->max로, 그리고
-만약 지원한다면- policy->policy 가 CPUFREQ_POLICY_PERFORMANCE 일 때,
성능 지향형 셋팅을, 그리고 CPUFREQ_POLICY_POWERSAVE 일 때, 전력 절약
형 셋팅을 설정할 필요가 있습니다. 또한 drivers/cpufreq/longrun.c 안의
참고 구현을 확인하세요.
2. 주파수 테이블 헬퍼
=====================
대부분의 cpufreq 프로세서들이 몇 가지 지정된 주파수만 셋팅할 수 있는
것처럼, 이런 동작의 “주파수 테이블”은 그 프로세서 드라이버의 어떤 동작에
도움이 될 것입니다. 앞에서 언급된 “주파수 테이블”은 여러분이 사용하길
원하는 “index”내에 어떤 값을, 그리고 “frequency” 안에 해당하는 주파수로 된
struct cpufreq_freq_table 항목의 배열로 구성되어 있습니다. 테이블의 끝에,
여러분은 cpufreq_freq_table 항목의 frequency에 CPUFREQ_TABLE_END로 셋팅할
필요가 있습니다. 그리고 테이블 안의 한 항목을 그냥 넘기길 원한다면,
frequency를 CPUFREQ_ENTRY_INVALID로 셋팅하면 됩니다. 그 항목이 증가하는
순서로 있을 필요는 없습니다.
cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table); 의
호출을 통해 cpuinfo.min_freq와 cpuinfo.max_freq 값들이 검출됩니다. 그리고
policy->min 과 policy->max로 같은 값이 셋팅됩니다. 이것은 per-CPU 초기화
단계에서 유용합니다.
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
는 적어도 한 개의 유효한 주파수가 policy->min과 policy->max 안에 있고,
모든 다른 조건들을 만족한다는 것입니다. 이것은 ->verify 호출에서
유용합니다.
int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int target_freq,
unsigned int relation,
unsigned int *index);
는 ->target 단계를 위한 맞는 주파수 테이블 헬퍼입니다. 그냥 값들을
이 함수로 넘기면 되고, 그 CPU가 셋팅될 주파수를 포함하는 주파수
테이블 항목의 번호를 unsigned int index로 반환합니다. 알림: 이것은
이 cpufreq_table_entry.index 안의 “index”가 아니고,
cpufreq_table[index] 대신입니다. 그래서 새로운 주파수는
cpufreq_table[index].frequency 이고, 여러분이 주파수 테이블 “index”
필드로 저장한 그 값은 cpufreq_table[index].index 입니다. [*]