[Linux:Kernel] 레귤레이터 드라이버 인터페이스

이 문서의 저작권은 GPL license를 따릅니다(This document is released under the GPL license).

Documentation/power/regulator/regulator.txt

번역: 양정석 <dasomoli@gmailREMOVETHIS.com>

레귤레이터 드라이버 인터페이스

==============================

레귤레이터 드라이버 인터페이스는 비교적 간단하고, 레귤레이터 드라이버가

그들의 서비스들을 코어 프레임워크에 등록하도록 디자인되었습니다.

등록

====

드라이버들은 레귤레이터를 다음 호출로 등록할 수 있습니다 :-

struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
const struct regulator_config *config);

이것은 그 레귤레이터 수용능력과 동작들을 레귤레이터 코어에 등록할 것입니다.

레귤레이터들은 다음 호출로 등록을 해제할 수 있습니다 :-

void regulator_unregister(struct regulator_dev *rdev);

레귤레이터 이벤트

=================

레귤레이터들은 이벤트들(예를 들면, 과열, 저전압, 기타)을 컨슈머 드라이버로

다음 호출을 통해 보낼 수 있습니다 :-

int regulator_notifier_call_chain(struct regulator_dev *rdev,
 unsigned long event, void *data);

[Linux:Kernel] 레귤레이터 머신 드라이버 인터페이스

이 문서의 저작권은 GPL license를 따릅니다(This document is released under the GPL license).
Documentation/power/regulator/machine.txt
번역: 양정석 <dasomoli@gmailREMOVETHIS.com>
레귤레이터 머신 드라이버 인터페이스
===================================
레귤레이터 머신 드라이버 인터페이스는 보드/머신 의존적인 초기화 코드가
레귤레이터 서브 시스템을 설정하도록 의도되었습니다.
다음 머신을 생각해봅시다 :-
  레귤레이터-1 -+-> 레귤레이터-2 –> [컨슈머 A @ 1.8 – 2.0V]
                |
                +-> [컨슈머 B @ 3.3V]
                
컨슈머 A 와 B 를 위한 드라이버는 그들의 전원 공급 제어에 따라 그에 맞는
레귤레이터에 맵핑되어야만 합니다. 이 맵핑은 각 레귤레이터를 위한
struct regulater_consumer_supply 생성에 의한 머신 초기화 코드 안에 담겨 있을
수 있습니다.
struct regulator_consumer_supply {
        const char *dev_name;   /* consumer dev_name() */
        const char *supply;     /* consumer supply – e.g. “vcc” */
};
예를 들면, 위의 머신을 위해서는
static struct regulator_consumer_supply regulator1_consumers[] = {
{
        .dev_name       = “dev_name(consumer B)”,
        .supply         = “Vcc”,
},};
static struct regulator_consumer_supply regulator2_consumers[] = {
{
        .dev    = “dev_name(consumer A”),
        .supply = “Vcc”,
},};
이 것은 레귤레이터-1을 ‘Vcc’ 공급원으로 컨슈머 B를 위해 맵핑하고,
레귤레이터-2를 ‘Vcc’ 공급원에 컨슈머 A를 위해 맵핑합니다.
각 레귤레이터 파워 도메인을 위한 제약 사항들은 바로 struct regulator_init_data를
정의함으로써 등록될 수 있습니다. 이 구조체는 또한 컨슈머를 그들의 공급
레귤레이터로 맵핑합니다 :-
static struct regulator_init_data regulator1_data = {
        .constraints = {
                .name = “Regulator-1”,
                .min_uV = 3300000,
                .max_uV = 3300000,
                .valid_modes_mask = REGULATOR_MODE_NORMAL,
        },
        .num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
        .consumer_supplies = regulator1_consumers,
};
그 name 필드는 다른 레귤레이터들을 위한 공급원들의 설정을 위해, 그리고
로그 기록과 다른 분석 출력 결과를 위한 용도를 위해서 그 보드를 실제로
설명하는 것으로 셋팅되어야 합니다. 보통 그 회로도 내의 공급 선로를 위한
이름이 좋습니다. name이 주어지지 않으면 서브 시스템이 하나를 선택할 것입니다.
레귤레이터-1은 레귤레이터-2로 전력을 공급합니다. 레귤레이터-1이 컨슈머 A가
그 공급원(레귤레이터-2)을 켤 때 켜질 수 있도록 이 관계는 그 코어에 반드시
등록되어야 합니다. 그 공급 레귤레이터는 아래의 supply_regulator 필드에 의해
셋팅됩니다:-
static struct regulator_init_data regulator2_data = {
        .supply_regulator = “Regulator-1”,
        .constraints = {
                .min_uV = 1800000,
                .max_uV = 2000000,
                .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
                .valid_modes_mask = REGULATOR_MODE_NORMAL,
        },
        .num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
        .consumer_supplies = regulator2_consumers,
};
마지막으로, 레귤레이터 디바이스들이 일반적인 관례대로 등록되어야만 합니다.
static struct platform_device regulator_devices[] = {
{
        .name = “regulator”,
        .id = DCDC_1,
        .dev = {
                .platform_data = &regulator1_data,
        },
},
{
        .name = “regulator”,
        .id = DCDC_2,
        .dev = {
                .platform_data = &regulator2_data,
        },
},
};
/* register regulator 1 device */
platform_device_register(&regulator_devices[0]);
/* register regulator 2 device */
platform_device_register(&regulator_devices[1]);

[Linux:Kernel] 레귤레이터 컨슈머 드라이버 인터페이스

이 문서의 저작권은 GPL license를 따릅니다(This document is released under the GPL license).

Documentation/power/regulator/consumer.txt

번역: 양정석 <dasomoli@gmailREMOVETHIS.com>

레귤레이터 컨슈머 드라이버 인터페이스
=====================================

이 문서는 컨슈머 디바이스 드라이버를 위한 레귤레이터 인터페이스에 대해
서술하고 있습니다. 이 문서 내에 사용된 용어의 설명은 overview.txt를 봐주세요.
1. 컨슈머 레귤레이터 접근 (정적 & 동적 드라이버)
================================================

컨슈머 드라이버는 그 공급 레귤레이터를 다음 호출로 접근 할 수 있습니다 :-

regulator = regulator_get(dev, “Vcc”);

컨슈머는 그 struct device 포인터와 전원 공급자 ID를 넘깁니다. 코어는 해당하는
레귤레이터를 머신 의존적인 탐색 테이블을 뒤져서 찾습니다. 탐색이 성공하면 이
호출은 이 컨슈머에 전원을 공급하는 struct regulator의 포인터를 반환할 것입니다.

레귤레이터를 컨슈머 드라이버에서 제거하기 위해서는 다음을 호출해야 합니다 :-

regulator_put(regulator);

컨슈머들은 하나 이상의 레귤레이터에 의해 전원이 공급될 수 있습니다. 예를 들면,
아날로그와 디지털 전원 공급을 함께 받는 코덱 컨슈머 :-

digital = regulator_get(dev, “Vcc”);  /* digital core */
analog = regulator_get(dev, “Avdd”);  /* analog */

그 레귤레이터 접근 함수 regulator_get()과 regulator_put() 는 일반적으로
여러분의 디바이스 드라이버의 probe() 와 remove() 함수 안에서 각각 호출됩니다.
2. 레귤레이터 출력 켜고 끄기 (정적 & 동적 드라이버)
===================================================

컨슈머는 그 전원 공급을 다음을 통해 켤 수 있습니다:-

int regulator_enable(regulator);

알림: 그 공급자는 이미 regulator_enabled()가 호출되기 전에 켜져 있을 겁니다.
그 컨슈머가 레귤레이터를 공유하거나 그 레귤레이터가 이전에 부트로더나 커널 보드
초기화 코드에 의해서 켜져 있다만 이렇게 될 수 있습니다.

컨슈머는 다음 호출을 통해 레귤레이터가 켜져 있는지 알아볼 수 있습니다 :-

int regulator_is_enabled(regulator);

이것은 레귤레이터가 켜져 있으면, 0보다 큰 값을 반환할 것입니다.
컨슈머는 그 전원 공급이 더이상 필요없을 때 다음을 통해 끌 수 있습니다 :-

int regulator_disable(regulator);

알림: 이것은 만약 그것을 다른 컨슈머와 공유하고 있으면, 그 전원 공급을 끄지
않을 것입니다. 그 레귤레이터는 켜진 것의 참조 카운트가 0일 때만 끌 것입니다.

마지막으로, 레귤레이터는 긴급한 경우에 강제로 끌 수 있습니다 :-

int regulator_force_disable(regulator);

알림: 이것은 즉시 그리고 강제로 레귤레이터 출력을 끌 겁니다. 모든 컨슈머는
전원이 꺼질 것입니다.

3. 레귤레이터 전압 제어 & 상태(동적 드라이버)
=============================================

어떤 컨슈머 드라이버는 시스템 동작 시점에 맞게 동적으로 그들의 전압 공급을
바꾸고 싶을 수 있습니다. 예를 들면, CPUfreq 드라이버들은 전력을 아끼기 위해서
주파수와 함께 전압을 조정할 수 있고, SD 드라이버들은 해당하는 카드 전압을
선택할 필요가 있을 수 있고, 기타 등등.

컨슈머들은 그들의 전압 공급을 다음을 통해 제어할 수 있습니다 :-

int regulator_set_voltage(regulator, min_uV, max_uV);

여기서 min_uV 와 max_uV 는 최소 그리고 최대 허용가능한 마이크로 볼트 전압입니다.

알림: 이것은 레귤레이터가 켜져있거나 꺼져 있을 때, 호출될 수 있습니다. 켜져
있을 때 호출되면, 전압은 즉시 바뀔 것이고, 아니라면, 전압 설정이 바뀌고
레귤레이터가 다음에 켜질 때 전압이 물리적으로 셋팅됩니다.

설정된 레귤레이터의 출력 전압은 다음을 통해 얻을 수 있습니다 :-

int regulator_get_voltage(regulator);

알림: get_voltage() 는 레귤레이터가 켜져있건 꺼져있건 설정된 전압을 반환합니다.
그리고 레귤레이터 출력 상태를 알아내는데는 사용하지 말아야 합니다. 그러나
그 레귤레이터의 물리적 출력 전압을 알아내기 위해서 이것은 is_enabled() 와의
조합으로 사용할 수 있습니다.
4. 레귤레이터 전류 제한 제어 & 상태(동적 드라이버)
==================================================

어떤 컨슈머 드라이버는 그 공급 전류 제한을 시스템 동작 시점에 맞춰 바꿔야 할
수도 있습니다. 예를 들면, LCD 백라이트 드라이버는 다양한 백라이트 밝기에 맞게
전류 제한을 바꿀 수 있고, USB 드라이버는 전원 공급 때 500mA 로 제한하기를 원할
겁니다.

컨슈머들은 그 공급 전류 제한을 다음으로 제어할 수 있습니다 :-

int regulator_set_current_limit(regulator, min_uA, max_uA);

여기서 min_uA 와 max_uA 는 최소, 최대 허용가능한 마이크로 암페어 전류 제한입니다.

알림: 이것은 레귤레이터가 켜져 있거나 꺼져 있을 때 호출 될 수 있습니다. 만약 켜져
있을 때 호출되면, 그 전류 제한은 즉시 바뀔 것이고, 아니면, 그 전류 제한 설정이
바뀌고 다음에 켜질 때 물리적으로 전류 제한이 셋팅됩니다.

레귤레이터는 전류 제한 값을 다음으로 얻을 수 있습니다 :-

int regulator_get_current_limit(regulator);

알림: get_current_limit() 는 그 레귤레이터가 켜져 있거나 꺼져 있거나 상관없이
전류 제한값을 반환할 것입니다. 그리고 레귤레이터 전류 로드값을 알아내기 위해서는
사용되어서는 안됩니다.
5. 레귤레이터 동작 모드 제어 & 상태(동적 드라이버)
==================================================

어떤 컨슈머들은 컨슈머들의 동작 상태 변경 때 더 효율적이도록 전원 공급
레귤레이터의 동작 모드를 바꿈으로써 더 많은 시스템 전력을 절약할 수 있습니다.
예를 들면, 컨슈머 드라이버는 대기 상태이고 그 후에는 더 적은 전류를 먹습니다.

레귤레이터 동작 모드는 직접 혹은 간접적으로 변경될 수 있습니다.

간접 동작 모드 제어
——————-
컨슈머 드라이버는 그 공급 레귤레이터 동작 모드의 변경을 다음을 통해 요청할 수
있습니다 :-

int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);

이것은 코어가 레귤레이터 상의 (모든 그 컨슈머에 기초해서) 총 부하를 재계산하도록
하는 원인이 될 것이고, 그 전류 동작 부하에 가장 알맞은 동작 모드로 (필요하고
허용된다면) 변경할 것입니다.

load_uA 값은 컨슈머 데이터시트로부터 결정될 수 있습니다. 예를 들면, 대부분의
데이터시트는 특정 상태에서 최대 전류 소모량을 보여주는 표를 가집니다.

대부분의 컨슈머는 그들이 레귤레이터에 대해 모를 때 또는 그 레귤레이터가
다른 컨슈머와 공유되는지 모를 때는 간접 동작 모드 제어를 사용할 것입니다.

직접 동작 모드 제어
——————-
맞추어진 또는 강하게 결합된 드라이버들은 직접 레귤레이터 동작 모드를 그들의
동작 시점에 따라 제어하기를 원할 것입니다. 이것은 다음을 통해 모을 수
있습니다 :-

int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);

직접 모드는 그 레귤레이터에 대해서, 그리고 다른 컨슈머들과 공유되지 않음을
*아는* 컨슈머에 의해서만 사용될 것입니다.
6. 레귤레이터 이벤트
====================
레귤레이터들은 컨슈머들에게 외부 이벤트를 알릴 수 있습니다. 이벤트들은 컨슈머에
의해서 레귤레이터 부하 또는 실패 컨디션 하에서 수신될 수 있습니다.

컨슈머들은 다음 호출을 통해 레귤레이터 이벤트에 대한 관심을 등록할 수 있습니다 :-

int regulator_register_notifier(struct regulator *regulator,
     struct notifier_block *nb);

컨슈머들은 다음 호출을 통해 그들의 관심을 해제할 수 있습니다 :-

int regulator_unregister_notifier(struct regulator *regulator,
struct notifier_block *nb);

레귤레이터들은 그들에게 관심있어 하는 컨슈머들에게 이벤트를 보내는데 커널
노티파이어 프레임워크를 사용합니다.

[Linux:Kernel] 레귤레이터 API 디자인 노트

이 문서의 저작권은 GPL license를 따릅니다(This document is released under the GPL license).

Documentation/power/regulator/design.txt

번역: 양정석 <dasomoli@gmailREMOVETHIS.com>

레귤레이터 API 디자인 노트

==========================

이 문서는 부분적으로 구조화된 요약, 레귤레이터 API 디자인에 영향을 준

디자인 고려점들의 개요를 제공합니다.

안전성

——

 – 레귤레이터 설정 내의 에러들은 잠재적으로 영구적인 하드웨어 손상을

   포함하는 시스템에 매우 심각한 결과를 가져올 수 있습니다.

 – 시스템의 전원 설정을 자동으로 결정하는 것은 불가능합니다 – 다른 전력

   요구사항을 가지는 같은 칩의 소프트웨어적으로 동등한 변종들과 전력

   요구사항을 가지는 일부 컴포넌트들은 소프트웨어에 보입니다.

   

  => 그 API 는 이들 변경이 이 특정 시스템 상에서 안전하게 수행될 수 있다는

     것을 알게 되기 전까지는 하드웨어 상태에 변경을 가하지 않습니다.

컨슈머 유즈 케이스

——————

 – 시스템 내의 디바이스들의 압도적인 수의 대부분은 그들의 전원을 켜고 끄는 것을

   넘는 어떤 런타임 설정을 하도록 하는 요구 사항을 갖지는 않을 겁니다.

 – 많은 시스템 내의 전원 공급자는 여러 다른 컨슈머들 사이에 공유될 겁니다.

  => 컨슈머 API는 이들 유즈 케이스가 처리되는데 매우 쉽도록, 그래서 컨슈머가

     공유된 공급원으로 별다른 추가적인 노력없이 동작하도록 구조화되어야

     합니다.

[Linux:Kernel] 리눅스 전압과 전류 레귤레이터 프레임워크

이 문서의 저작권은 GPL license를 따릅니다(This document is released under the GPL license).


Documentation/power/regulator/overview.txt


리눅스 전압과 전류 레귤레이터 프레임워크

========================================

이것에 관하여

=============

이 프레임워크는 전압과 전류 레귤레이터를 제어하기 위한 표준 커널 인터페이스를

제공하기 위해서 디자인 되었습니다.

그 의도는 시스템으로 하여금 전력을 절약하고 더 긴 배터리 수명을 위해 동적으로

레귤레이터의 전원 출력을 제어할 수 있도록 하는 데 있습니다. 이 것은 (전압 출력을

제어 가능한 곳에서)전압 조절 장치와 (전류 제한이 제어 가능한)전류 제어, 둘 다

적용합니다.

(C) 2008  Wolfson Microelectronics PLC.

저자: Liam Girdwood <lrg@slimlogic.co.uk>

번역: 양정석 <dasomoli@gmailREMOVETHIS.com>

용어

====

이 문서 안에서는 몇몇 용어가 사용됩니다:-

  o 레귤레이터   – 다른 디바이스로 전력을 공급하는 전자 장치.

                   어떤 것들은 그들의 출력 전압과 (또는) 전류를 제어할 수 있는

                   데 반해 대부분의 레귤레이터는 그들의 출력을 켜고 끌 수 있습니다.

                   입력 전압 -> 레귤레이터 -> 출력 전압

                   

  o PMIC         – 전력 관리 칩(Power Management IC). 한 IC는 여러개의 레귤레이터와

                   종종 다른 서브 시스템을 포함합니다.

  o 컨슈머       – 레귤레이터에 의해 전력이 공급되는 전자 장치.

                   컨슈머는 두가지 타입으로 분류할 수 있습니다:-

                   

                   정적: 컨슈머는 그 공급 전압이나 전류 제한을 바꾸지 않습니다.

                   그저 그 전원 공급을 켜거나 끄는 것만을 필요로 합니다. 그 공급

                   전압은 하드웨어, 부트로더, 펌웨어나 커널 보드 초기화 코드에

                   의해서 결정됩니다.

  o 파워 도메인  – 레귤레이터, 스위치의 출력 전원 또는 다른 파워 도메인에 의한

                   그 입력 전원이 공급되는 전자 회로.

                   

                   그 공급 레귤레이터는 스위치(들) 뒤에 있을 것입니다. 예를 들면,

                   

                   레귤레이터 -+-> 스위치-1 -+-> 스위치-2 –> [컨슈머 A]

                               |             |

                               |             +-> [컨슈머 B], [컨슈머 C]

                               |

                               +-> [컨슈머 D], [컨슈머 E]

                

                   저것은 하나의 레귤레이터와 세 개의 파워 도메인입니다:

                   

                   도메인 1: 스위치-1, 컨슈머 D와 E.

                   도메인 2: 스위치-2, 컨슈머 B와 C.

                   도메인 3: 컨슈머 A.

                   

                   그리고 이것은 “공급자들” 관계를 나타냅니다:

                   

                   도메인-1 –> 도메인-2 –> 도메인-3.

                   

                   하나의 파워 도메인은 다른 레귤레이터들에 의해 전원이 공급되는

                   레귤레이터들을 갖을 것입니다. 예를 들면,

                   

                   레귤레이터-1 -+-> 레귤레이터-2 -+-> [컨슈머 A]

                                 |

                                 +-> [컨슈머 B]

                                 

                   이 것은 우리에게 두 개의 레귤레이터와 두 개의 파워 도메인을 줍니다:

                   

                   도메인 1: 레귤레이터-2, 컨슈머 B

                   도메인 2: 컨슈머 A

                   

                   그리고 하나의 “공급자들” 관계:

                   

                   도메인-1 –> 도메인-2

  o 제약 사항    – 제약 사항은 성능과 하드웨어 보호를 위한 전원 레벨을 정의하는데

                   사용되고는 합니다. 제약 사항은 세 개의 레벨이 존재합니다:

                   

                   레귤레이터 레벨: 이것은 레귤레이터 하드웨어 동작 파라미터에

                   의해서 정의되고, 레귤레이터 데이터 시트 내에서 정해집니다.

                   예를 들면,

                   

                     – 전압 출력은 800mV -> 3500mV 범위 안 입니다.

                     – 레귤레이터 전류 출력 제한은 20mA @ 5V 아니면 10mA @10V 입니다.

                     

                   파워 도메인 레벨: 이것은 커널 레벨 보드 초기화 코드에 의해서

                   소프트웨어 내에서 정의됩니다. 그것은 파워 도메인을 특정 전원

                   범위로 제약하는데 사용되곤 합니다. 예를 들면,

                   

                     – 도메인-1 전압은 3300mV

                     – 도메인-2 전압은 1400mV -> 1600mV

                     – 도메인-3 전류 제한은 0mA -> 20mA.

                     

                   컨슈머 레벨: 이것은 컨슈머 드라이버가 동적으로 전압이나 전류 제한

                   레벨을 셋팅함에 의해서 정의됩니다.

                   

                   예를 들면, 컨슈머 백라이트 드라이버가 전류 증가를 위해 5mA 에서

                   10mA 로 LCD 광도 증가를 위해 요청을 합니다. 이 것은 다음과 같은

                   레벨을 통해 진행됩니다 :-

                   

                   컨슈머: LCD 밝기를 증가할 필요가 있다. 밝기 테이블(컨슈머 드라이버는

                   같은 레퍼런스 디바이스 상에서를 기초로 여러 다른 개인 설정을 사용하기도

                   한다) 안에서 살펴보고 다음 전류 mA 값을 요청하라.

                   

                   파워 도메인: 새로운 전류 제한이 이 도메인과 시스템 상태(예를 들면,

                   배터리 전원, USB 전원)를 위한 동작 제한들 내에 있는가

                   

                   레귤레이터 도메인: 새로운 전류 제한이 입력/출력 전압을 위한 레귤레이터

                   동작 파라미터 내에 있는가

                   

                   만약 그 레귤레이터가 모든 제약사항 테스트를 동과하면 새로운 레귤레이터

                   값이 적용됩니다.

디자인

======

프레임워크는 SoC 기반의 디바이스들을 대상으로 하고 디자인되었습니다만, SoC가

아닌 디바이스들과도 관련이 있고, 다음 네가지 인터페이스에 따라 나뉩니다:-

   1. 컨슈머 드라이버 인터페이스

      이것은 컨슈머 드라이버가 레귤레이터를 (클럭 atm으로 할 수 있는 것 같이)

      얻거나 내려 놓을 수 있고, 전류 제한, 모드, 켜고 끄기, 전압을 읽고/셋팅할

      수 있다는 것에서 커널 클럭 인터페이스와 비슷한 API 를 사용합니다. 컨슈머

      에게 그 공급 전압과 전류 제한의 완전한 제어를 허용하여야 합니다. 또한

      사용 중이 아니면 꺼져서 드라이버들이 전원 제어를 위한 레귤레이터 없이

      시스템 안에서 재사용될 수 있도록 합니다.

      

        Documentation/power/regulator/consumer.txt 를 보세요.

        

   2. 레귤레이터 드라이버 인터페이스

      이것은 레귤레이터 드라이버가 그들의 레귤레이터를 등록하고, 그 코어에

      동작을 제공할 수 있도록 합니다. 또한 레귤레이터 이벤트를 클라이언트에게

      퍼뜨리기 위한 노티파이어 호출 체인을 가집니다.

      

        Documentation/power/regulator/regulator.txt 를 보세요.

        

   3. 머신 인터페이스

      이 인터페이스는 머신 의존적인 코드를 위해서 존재하고, 각 레귤레이터를

      위한 전압/전류 도메인의 (제약사항과 함께) 생성을 가능하도록 합니다.

      버그가 있는 클라이언트 드라이버에 의한 과전압 또는 과전류에 따른

      디바이스 손상을 막는 레귤레이터 제약사항을 제공할 수 있습니다. 또한

      어떤 레귤레이터가 다른 것들에 의해 공급되는지를 나타내는 (클럭 트리와

      비슷한) 레귤레이터 트리의 생성을 하도록 합니다.

      

        Documentation/power/regulator/machine.txt 를 보세요.

        

   4. 유저스페이스 ABI.

      그 프레임워크는 또한 많은 유용한 전압/전류/동작모드 데이터를 유저스페이스에

      sysfs를 통해 드러냅니다. 이것은 디바이스 전원 소비와 상태를 들여다 보는데

      사용될 수 있습니다.

      

        Documentation/ABI/testing/sysfs-class-regulator 를 보세요.

[Linux:Kernel] worker thread 의 work function 확인

https://lkml.org/lkml/2011/3/31/68 를 참고하면 된다.

첫번째 방법은 다음을 실행한 후

$ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event

다음을 실행해서 trace 결과를 파일로 저장하는 것이다.

$ cat /sys/kernel/debug/tracing/trace_pipe > out.txt

파일로 저장하는 것은 android 에서 adb 를 이용한다면 다음과 같이 adb pull 로 /sys/kernel/debug/tracing/trace_pipe 를 가져오도록 해도 될 것이다.

adb pull /sys/kernel/debug/tracing/trace_pipe out.txt

두번째 방법은 해당 workqueue의 pid로 다음과 같이 얻어내는 것이다.

$ cat /proc/<pid>/stack

 

[Linux:Kernel] strncpy 대신 strlcpy

이 글에 있는 모든 코드는 GPL License를 따릅니다(All code attached is released under the GPL License in this article).

strncpy 에서는 source의 길이가 destination의 버퍼 길이와 같거나 더 길 경우, NUL-terminate되지 않는다. 구현이 다음과 같기 때문이다.

/**
 * strncpy – Copy a length-limited, %NUL-terminated string
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 * @count: The maximum number of bytes to copy
 *
 * The result is not %NUL-terminated if the source exceeds
 * @count bytes.
 *
 * In the case where the length of @src is less than  that  of
 * count, the remainder of @dest will be padded with %NUL.
 *
 */
char *strncpy(char *dest, const char *src, size_t count)
{
        char *tmp = dest;
        while (count) {
                if ((*tmp = *src) != 0)
                        src++;
                tmp++;
                count–;
        }
        return dest;
}

그래서 NUL-terminate를 보장하기 위한 함수가 있다 strlcpy 이다. 이 함수는 size-1 만큼의 string 복사와 함께 NULL로 끝남을 보장해 준다.

/**
 * strlcpy – Copy a %NUL terminated string into a sized buffer
 * @dest: Where to copy the string to
 * @src: Where to copy the string from
 * @size: size of destination buffer
 *
 * Compatible with *BSD: the result is always a valid
 * NUL-terminated string that fits in the buffer (unless,
 * of course, the buffer size is zero). It does not pad
 * out the result like strncpy() does.
 */
size_t strlcpy(char *dest, const char *src, size_t size)
{
        size_t ret = strlen(src);
        if (size) {
                size_t len = (ret >= size) ? size – 1 : ret;
                memcpy(dest, src, len);
                dest[len] = ‘\0’;
        }
        return ret;
}

strncpy를 strlcpy로 교체해야 할 것 같지만, 현재 커널에서는 둘 다 많이 사용되고 있다.
커널에서의 두 함수의 구현은 lib/string.c 에 있다.

참고 : http://lwn.net/Articles/33812/

[Linux:Kernel] 리눅스(tm) 커널 내의 CPU 핫플러그 지원

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under the GPL license.).


                리눅스(tm) 커널 내의 CPU 핫플러그 지원

                메인테이너:

                CPU 핫플러그 코어:

                        Rusty Russell <rusty@rustcorp.com.au>

                        Srivatsa Vaddagiri <vatsa@in.ibm.com>

                i386:

                        Zwane Mwaikambo <zwane@arm.linux.org.uk>

                ppc64:

                        Nathan Lynch <nathanl@austin.ibm.com>

                        Joel Schopp <jschopp@austin.ibm.com>

                ia64/x86_64:

                        Ashok Raj <ashok.raj@intel.com>

                s390:

                        Heiko Carstens <heiko.carstens@de.ibm.com>

저자: Ashok Raj <ashok.raj@intel.com>

많은 피드백: Nathan Lynch <nathanl@austin.ibm.com>,

             Joel Schopp <jschopp@austin.ibm.com>

번역: 양정석 <dasomoli@gmailREMOVETHIS.com>

소개

시스템 아키턱처 내의 현대 발달은 고급 에러 리포팅과 프로세서 내의 교정 능력

도입하였습니다. CPU 아키텍처들은 하나의 CPU의 계산 자원을 가상 머신 환경이

이용 가능하도록 파티셔닝을 지원합니다. 물리적 노드 추가와 제거
가 CPU 핫플러그
지원이 필요한 곳에서는 핫 플러그가 잘 되는 NUMA 
하드웨어를 지원하는 몇몇의
OEM들이 있습니다.

이러한 발달은 커널에게 공급 이유들이나 RAS 목적들 중 하나를 위해 시스템 실행

경로를 차단하는데 대한 문제를 막기 위해서 CPU들이 제거될 수 있어야 함을 필요로

합니다. 그래서 리눅스 커널 내에 CPU 핫플러그 지원이 필요합니다.

더 새로운 CPU-핫플러그 지원의 용도는 오늘날에 SMP 를 위한 suspend resume 지원

내의 그 사용입니다. 듀얼 코어와 HT 지원은 랩탑조차 이런 방법을 지원하지 않는

SMP 커널을 실행하도록 만들었습니다. suspend/resume을 위한 SMP 지원은 계속

진행되고 있습니다.

CPU 핫플러그에 대한 일반적인 사항

———————————

커맨드 라인 스위치

——————

maxcpus=n    부팅 타임 CPU를 n으로 제한함. 여러분이 4 CPU를 가지고 있을 때,

             maxcpus=2를 사용하면 2개만 부팅합니다. 다른 CPU들은 나중에 온라인

             상태로 가져오도록 선택할 수 있습니다. 더 많은 정보는 FAQ를

             읽어보세요.

             

additional_cpus=n (*)   핫플러그 가능한 CPU들을 제한하는데 사용. 이 옵션은

                        cpu_possible_mask = cpu_present_mask + additional_cpus

                        를 셋팅합니다.

cede_offline={“off”,”on”}  이 옵션은 오프라인된 프로세서를 확장 H_CEDE 상태로

                           두는 것을 이를 지원하는 p시리즈 플랫폼 상에서

                           끄고/켜는데 사용됩니다.

                           만약 이 옵션이 지정되지 않으면, cede_offline은 “on”

                           으로 셋팅됩니다.

(*) 다음 아키텍처에서만 옵션이 유효

– ia64

ia64 는 잠재적으로 핫플러그될 수 있는 CPU의 숫자를 결정하기 위해서 ACPI 테이블

MADT 안의 꺼진 로컬 apics의 숫자를 사용합니다. 그 구현은 오직 CPU의 개수를

세는데만 의존적이지만 *반드시* 꺼진 apics를 위한 이들 테이블의 apicid 값에

의존하지는 않습니다. BIOS 가 이들 핫플러그 가능한 CPU를 꺼진 항목으로 표시하지

않는 상황에서는, cpu_possible_mask 안의 이들 CPU를 나타내기 위해서 누군가

이 파라미터 “additional_cpus=x”를 사용할 수 있습니다.

possible_cpus=n         [s390,x86_64] 핫플러그 가능한 CPU를 셋팅하기 위해 이것을

                        사용합니다. 이 옵션은 cpu_possible_mask 안의 possible_cpus

                        비트들을 셋팅합니다. 그래서 비트의 수를 유지하는 것은

                        그 머신이 재부팅된다 하더라도 변하지 않습니다.

CPU 맵들과 그 들

—————-

[cpumaps 상의 더 많은 것과 조작을 위한 기본적인 것들은 더 자세한 글을 가진

include/linux/cpumask.h를 확인해 보세요.]

cpu_possible_mask: 시스템 내에서 이용 가능할 수 있는 가능한 CPU들의 비트맵.

이 것은 어떤 부팅 타임 메모리를 CPU들을 사용 가능하게 만들거나 제거되는 것과

같이 늘어나거나/줄어들지 않는 것으로 설계되지 않은 per_cpu 변수로 할당하는데

사용됩니다. 부팅 타임 탐색 단계에서 셋팅되고 나면 그 맵은 변하지 않습니다.

즉, 어느 시점의 비트의 추가나 제거가 되지 않습니다. 여러분의 시스템의 다가올

수요를 위해 정확하게 그것을 다듬는 것은 부팅 타임 메모리를 절약할 수 있습니다.

어떻게 우리가 x86_64 경우에 이 것의 하한 검사를 막기 위해 휴리스틱을 사용하는

지 아래에서 보세요.

cpu_online_mask: 현재 온라인인 모든 CPU들의 비트맵. 한 CPU가 커널 스케줄링과

디바이스들로부터 인터럽트를 받을 수 있도록 하는 준비가 이용가능해진 이후에

__cpu_up() 내에서 그 셋팅이 됩니다. 한 CPU가 인터럽트를 다른 목표하는 CPU로

옮겨놓는 것을 포함하는 모든 OS 서비스 전에 __cpu_disable()을 사용해서

꺼질 때, 클리어 됩니다.

cpu_present_mask: 시스템 내에 현제 존재하는 CPU들의 비트맵. 그들 모두가

온라인이지는 않습니다. 물리적 핫플러그가 처리될 때 관련된 서브 시스템

(예로, ACPI)이 바꾸거나 새로운 비트가 그 이벤트가 핫-추가/핫-제거임에

따라 관련된 맵으로부터 추가 또는 제거됩니다. 지금은 현재 락킹 규칙이 없습니다.

일반적인 사용은 핫플러그가 꺼진 시간인 부팅 동안 토폴리지를 초기화하는

것입니다.

여러분은 그 시스템 CPU 맵들의 어떤 조작이 정말로 필요하지는 않습니다. 그들은

대부분의 용도를 위해 읽기-전용이 되어야 합니다. per-cpu 자원을 셋팅할 때 거의

어느때나 cpu_possible_mask/(반복을 위해)for_each_possible_cpu() 를 사용하세요.

CPU들의 비트맵을 표현하기 위해 cpumask_t 말고 절대 어떤 다른 것을 사용하지 마세요.

        #include <linux/cpumask.h>

        for_each_possible_cpu     – cpu_possible_mask 상의 반복

        for_each_online_cpu       – cpu_online_mask 상의 반복

        for_each_present_cpu      – cpu_present_mask 상의 반복

        for_each_cpu_mask(x,mask) – CPU mask의 어떤 무작위 모음 상의 반복

        #include <linux/cpu.h>

        get_online_cpus() 와 put_online_cpus():

위의 호출들은 CPU 핫플러그 연산을 금하기 위해 사용됩니다. cpu_hotplug.refcount

가 0이 아닌 동안, cpu_online_mask는 바뀌지 않을 것입니다. 만약 여러분이

드물게 CPU들이 없어지는 것을 막을 필요가 있다면, 여러분은 또한

preempt_disable() 과 preempt_enable()을 그 부분에서 사용할 수 있습니다.

크리티컬 섹션은 이 프로세스를 떠나 슬립되거나 스케줄링될 수 있는 함수를 부를

수 없다는 것을 기억하세요. preempt_disable()은 CPU를 끄기 위해 사용되는

stop_machine_run() 이 사용되는 시간만큼 동작할 것입니다.

CPU 핫플러그 – 자주 묻는 질문과 답변(FAQ)

Q: 어떻게 내 커널이 CPU 핫플러그를 지원하도록 할 수 있나요?

A: make defconfig할 때, CPU 핫플러그 지원을 켜세요.

   “Processor type and Features” -> Support for Hotpluggable CPUs

여러분이 CONFIG_SMP 를 잘 켜놨는지 확인하시고요.

여러분은 SMP suspend/resume이 잘 지원되도록 CONFIG_HOTPLUG_CPU를 켤 필요가

있을 겁니다.

Q: 어떤 아키텍처가 CPU 핫플러그를 지원하나요?

A: 2.6.14에서, 다음 아키텍처가 CPU 핫플러그를 지원합니다.

i386 (인텔), ppc, ppc64, parisc, s390, ia64 그리고 x86_64

Q: 새로 빌드된 커널 상에서 핫플러그가 지원되는지 어떻게 테스트할 수 있나요?

A: sysfs 상의 한 항목이 현재 있어야 합니다.

“mount” 명령을 사용해서, sysfs 가 마운트되었는지 확인하세요. 여러분은

그 출력 안에 아래에서 보이는 것 같은 항목이 보여야 합니다.

        ….

        none on /sys type sysfs (rw)

        ….

마운트 되어 있지 않다면, 다음을 실행하세요.

         #mkdir /sysfs

        #mount -t sysfs sys /sys

그러면 모든 존재하는 CPU를 위한 항목들이 보여야 합니다. 다음은 8-way 시스템

내의 예제입니다.

        #pwd

        #/sys/devices/system/cpu

        #ls -l

        total 0

        drwxr-xr-x  10 root root 0 Sep 19 07:44 .

        drwxr-xr-x  13 root root 0 Sep 19 07:45 ..

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu0

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu1

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu2

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu3

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu4

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu5

        drwxr-xr-x   3 root root 0 Sep 19 07:44 cpu6

        drwxr-xr-x   3 root root 0 Sep 19 07:48 cpu7

각 디렉토리 아래에서 여러분은 프로세서를 논리적으로 온라인/오프라인 상태로

제어하는 파일인 “online” 파일을 찾을 수 있을 겁니다.

Q: 핫-추가/핫-제거가 CPU들의 물리적인 추가/제거를 참조하나요?

A: 핫-추가/제거의 사용은 코드 안에서 매우 일관적이지 않습니다.

CONFIG_HOTPLUG_CPU는 커널 내에서 논리적인 온라인/오프라인 능력을 켭니다.

물리적인 추가/제거를 지원하기 위해서는, 어떤 BIOS 훅들이 필요하고, 플랫폼은

PCI 핫플러그 내에 차렷 버튼 같은 어떤 것을 가지고 있어야 할 겁니다.

CONFIG_ACPI_HOTPLUG_CPU 는 CPU들의 물리적인 추가/제거를 위한 ACPI 지원을

켭니다.

Q: 한 CPU를 논리적으로 오프라인시키려면 어떻게 해야 하나요?

A: 다음을 수행하세요.

        #echo 0 > /sys/devices/system/cpu/cpuX/online

논리적 오프라인이 성공하고나면, 다음을 검사하세요

        #cat /proc/interrupts

여러분은 제거된 CPU를 이제부터 볼 수 없어야 합니다. 또한 온라인 파일은

CPU가 오프라인일 때는 그 상태를 0으로, 온라인일 때는 1로 보고할 겁니다.

        #현재 CPU 상태를 보이기 위해서.

        #cat /sys/devices/system/cpu/cpuX/online

Q: 어떤 시스템 상에서는 왜 CPU0를 제거할 수 없나요?

A: 어떤 아키텍처는 어떤 CPU상에서는 어떤 특별한 의존성을 가지고 있습니다.

IA64 플랫폼을 예로 들자면, 우리는 교정된 플랫폼 에러 인터럽트 (Corrected

Platform Error Interrupts:CPEI)로 알려진 플랫폼 인터럽트를 OS로 보낼 수 있는

능력이 있습니다. 그 목표하는 CPU를 바꾸는 방법은 없습니다. 그래서 현재 ACPI

버전이 리다이렉션 같은 것을 지원하지 않으면, 우리는 제거 가능하지 않게

만듦으로써 그 CPU를 끕니다.

이런 경우에는 여러분은 그 온라인 파일이 cpu0 아래에 없는 것을 볼 수 있을 겁니다.

Q: X86 상에서는 CPU0가 제거 가능한가요?

A: 네. 커널이 CONFIG_BOOTPARAM_HOTPLUG_CPU0=y로 컴파일되었다면, CPU0 는

기본값으로 제거가능합니다. 아니면, CPU0 는 커널 옵션 cpu0_hotplug 로 또한

제거가능합니다.

그러나 CPU0에 의존하는 어떤 기능이 있습니다. 두가지 알려진 의존은:

1. CPU0 상에 의존하는 하이버네이션/suspend 로부터의 resume. 하이버네이션/suspend

는 CPU0가 오프라인이면 실패할 것이고, 하이버네이션/suspend 가 계속되기 전에

CPU0를 온라인시킬 필요가 있습니다.

2. CPU0에 또한 의존하는 PIC 인터럽트들. CPU0는 PIC 인터럽트가 검출되면 제거될

수 없습니다.

그것은 내가 어떤 몇 개의 테스팅된 머신 상에서는 CPU0가 offline 이 된 후에 어떤

전원 끄기/재부팅 실패를 보지 못했더라도 어떤 머신 상에서는 전원 끄기/재부팅이

CPU0 에 의존할 것임을 말합니다.

CPU0의 다른 어떤 의존을 보거나 알게된다면 알려주세요.

그 의존이 여러분의 제어 아래에 있다면, 여러분은 CPU0 핫플러그 기능을

CONFIG_BOOTPARAM_HOTPLUG_CPU0 나 커널 파라미터 cpu0_hotplug를 통해 켤 수

있습니다.

–Fenghua Yu <fenghua.yu@intel.com>

Q: 특정한 CPU가 제거 가능하지 않은지 어떻게 알아낼 수 있나요?

A: 구현에 따라, 어떤 아키텍처는 이 것을 “online” 파일을 없앰으로써 보여주기도

합니다. 이 CPU 가 제거될 수 없는 시간보다 먼저 결정될 수 있다면 가능합니다.

어떤 상황에서는 이것은 런타임 검사가 될 수 있습니다. 즉, 여러분이 마지막 CPU를

제거하려고 하면, 이 동작은 거부될 것입니다. 여러분은 “echo” 명령의 반환 값을

조사함으로써 이런 실패를 찾을 수 있습니다.

Q: CPU가 논리적으로 오프라인되고 있을 때는 무슨 일이 일어나나요?

A: 특정 순서 없이 나열된 다음 일들이 일어납니다. 🙂

– 커널내부에 등록된 모듈들로 suspend 동작으로 인해 작업들이 멈춰지는 동안에

  그 CPU 가 오프라인 되고 있는지, 아닌지에 따라 CPU_DOWN_PREPARE 또는

  CPU_DOWN_PREPARE_FROZEN 이벤트를 보냄으로써 알려집니다.

– 모든 프로세스들이 이 없어지는 CPU에서 새로운 CPU들로 이전됩니다.

  새로운 CPU는 각 프로세스의 모든 온라인 CPU의 부분 집합이 될 현재 cpuset

  으로부터 선택됩니다.

– 이 CPU로 오던 모든 인터럽트들은 새로운 CPU로 이전됩니다.

– 타이머/보톰하프/태스크릿들 역시 새로운 CPU로 이전됩니다.

– 모든 서비스가 이전되고 나면, 커널은 아키텍처 종속적인 클린업을 수행하기 위해서

  아키텍처 종속적 루틴인 __cpu_disable() 을 호출합니다.

– Once this is successful, an event for successful cleanup is sent by an event

  CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the

  CPU is being offlined).

– 이 것이 성공하고 나면, 성공적인 클린업을 알리는 이벤트가 CPU_DEAD (또는

  태스크가 CPU가 오프라인이 되는 동안 suspend로 인해 멈춘다면 CPU_DEAD_FROZEN)

  을 보내집니다.

  

  “이것은 각 서비스가 CPU_DOWN_PREPARE 노티파이어가 호출되었을 때 클린업되었다고

  여겨집니다. CPU_DEAD가 호출되었을 때 그것은 오프라인 되었을 이 CPU 상에

  실행되는 것이 없을 것으로 여겨집니다.”

Q: CPU 도착과 출발을 알 수 있는 어떤 커널 코드는 가지고 있다면 어떻게 적절히

   알려주기 위해 조정해야 하나요?

A: 이것은 여러분이 여러분의 커널 코드 안에 알림을 받기 위해 필요할 그 무엇입니다.

        #include <linux/cpu.h>

        static int foobar_cpu_callback(struct notifier_block *nfb,

                                       unsigned long action, void *hcpu)

        {

                unsigned int cpu = (unsigned long)hcpu;

                switch (action) {

                case CPU_ONLINE:

                case CPU_ONLINE_FROZEN:

                        foobar_online_action(cpu);

                        break;

                case CPU_DEAD:

                case CPU_DEAD_FROZEN:

                        foobar_dead_action(cpu);

                        break;

                }

                return NOTIFY_OK;

        }

        static struct notifier_block foobar_cpu_notifer =

        {

           .notifier_call = foobar_cpu_callback,

        };

여러분은 여러분의 init 함수로부터 register_cpu_notifier()를 호출할 필요가

있습니다. Init 함수는 두가지 종류가 될 수 있습니다:

1. early init (부트 프로세서가 온라인일 때만 호출되는 init 함수)

2. late init (모든 CPU가 온라인이 된 _후에_ 호출되는 init 함수)

첫번째 경우를 위해, 여러분은 다음을 여러분의 init 함수에 추가해야 합니다.

        register_cpu_notifier(&foobar_cpu_notifier);

두번째 경우를 위해서, 여러분은 여러분의 init 함수에 다음을 추가해야 합니다.

        register_hotcpu_notifier(&foobar_cpu_notifier);

여러분은 어떤 것이 자원을 준비하는데 동작하지 않으면 PREPARE 노티파이어를 실패할

수 있습니다. 이것은 그 동작을 멈추고 다음 CANCELED 이벤트를 다시 보낼 것입니다.

CPU_DEAD 는 그 좋지않은 징후만으로 실패되면 안됩니다. 그러나 경로 내의

노티파이어가 BAD 알림 코드를 보내면 나쁜 일들이 일어날 겁니다.

Q: 나는 모든 CPU가 모두 올라가고 실행되기 위해 호출하는 나의 동작들을 보지 않나요?

A: 네, CPU 노티파이어들은 새로운 CPU 들이 온라인되거나 오프라인될 때만 호출됩니다.

   여러분이 그 시스템 내의 각 CPU에 대한 어떤 동작을 수행할 필요가 있다면,

        for_each_online_cpu(i) {

                foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);

                foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);

        }

Q: 새로운 아키텍처를 위한 CPU 핫플러그 지원을 개발하고 싶다면, 최소한 무엇이

   필요한가요?

A: 다음에 있는 것들이 정확히 동작하기 위해서 CPU 핫플러그 인프라스트럭쳐에

   필요한 것들입니다.

    – CONFIG_HOTPLUG_CPU가 Kconfig 내에 켜져 있는지 확인하세요.

    – __cpu_up()        – CPU를 켜기 위한 Arch 인터페이스

    – __cpu_disable()   – CPU를 끄기 위한 Arch 인터페이스, 이 루틴이 반환하고

                          난 후에는 더이상 인터럽트들이 커널에 의해서 처리될 수

                          없습니다. 로컬 APIC 타이머를 포함한 기타의 것들이

                          꺼집니다.

     – __cpu_die()      – 이것은 실제로 CPU가 죽은 것을 보장하기 위해 제공합니다.

                          CPU 핫플러그를 구현한 다른 아키텍처 내의 어떤 예제

                          코드를 실제로 보세요. 그 프로세서는 지정된 아키텍처를

                          위한 idle() 루프로부터 꺼집니다. __cpu_die()는

                          일반적으로 그 프로세서의 죽는 루틴이 분명히

                          호출되었음을 확인하기 위해서 셋팅되는 어떤 per_cpu

                          상태를 기다립니다.

Q: 이 CPU 로 지정된 어떤 일이 진행 중일 때, 특정 CPU가 제거되지 않음을 보장할

   필요가 있습니다.

A: 두가지 방법이 있습니다. 여러분의 코드가 인터럽트 컨텍스트 내에서 실행될 수

   있다면, smp_call_function_single() 을 사용하고, 아니라면 work_on_cpu() 를

   사용하세요. work_on_cpu는 느리고, 메모리 부족으로 실패할 수 있음을

   알아두시고요:

        int my_func_on_cpu(int cpu)

        {

                int err;

                get_online_cpus();

                if (!cpu_online(cpu))

                        err = -EINVAL;

                else

#if NEEDS_BLOCKING

                        err = work_on_cpu(cpu, __my_func_on_cpu, NULL);

#else

                        smp_call_function_single(cpu, __my_func_on_cpu, &err,

                                                 true);

#endif

                put_online_cpus();

                return err;

        }

Q: 핫플러그를 위해 얼마나 많은 CPU가 이용가능한지 어떻게 결정할 수 있나요?

A: 최근의 정보를 우리에게 줄 수 있는 ACPI 로부터 방법이 정의된 명확한 스펙은

   없습니다. Unisys의 Natalie 로부터의 어떤 입력에 기초하여, ACPI MADT(Multiple

   APIC Description Tables)는 시스템 내에 꺼진 상태로 있는 가능한 CPU들을

   표시합니다.

   Andi 는 핫플러그 가능한 CPU들로 MADT 안에서 꺼진 CPU들의 숫자를 세는 간단한

   휴리스틱으로 구현했습니다. 꺼진 CPU가 없는 경우에는 핫플러그 가능한 현재

   존재하는 CPU를 1/2 개수로 가정합니다.

   경고: ACPI MADT 는 ACPI 2.0c 또는 그 이전의 ACPI 버전을 지원하는 시스템

   안에서는 그 MADT 안의 apicd 필드가 8비트이기 때문에 256개의 항목만 지원할 수

   있습니다. ACPI 3.0 이후부터 이 제한은 x2APIC가 소개되면서 apicid 필드가

   32비트로 확장된 이후로 제거되었습니다.

유저 공간 알림

디바이스를 위한 핫플러그 지원은 리눅스 안에서 오늘날 일반적입니다. 그것은 

네트워크, USB, 그리고 PCI 디바이스들의 자동 설정을 지원하는데 오늘날 사용되고

있습니다. 핫플러그 이벤트는 설정 태스크를 수행하기 위한 에이전트 스크립트를

호출하는데 사용될 수 있습니다.

여러분은 /etc/hotplug/cpu.agent 를 핫플러그 알림 유저 공간 스크립트를 처리하기

위해서 추가할 수 있습니다.

        #!/bin/bash

        # $Id: cpu.agent

        # Kernel hotplug params include:

        #ACTION=%s [online or offline]

        #DEVPATH=%s

        #

        cd /etc/hotplug

        . ./hotplug.functions

        case $ACTION in

                online)

                        echo `date` “:cpu.agent” add cpu >> /tmp/hotplug.txt

                        ;;

                offline)

                        echo `date` “:cpu.agent” remove cpu >>/tmp/hotplug.txt

                        ;;

                *)

                        debug_mesg CPU $ACTION event not supported

        exit 1

        ;;

        esac

[Linux:Kernel] cpufreq.c 안의 cpu_policy_rwsem 에 관련된 규칙

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under the GPL license).

 cpu_policy_rwsem 은 락 이슈와 관련된 모든 cpufreq/핫플러그/워크 큐/기타를
 해결하기 위한 per CPU reader-writer 세마포어입니다.
 
 이 세마포어를 위한 규칙은 다음과 같습니다:
 – policy 구조체로부터 읽기를 원하는 어떤 루틴은 이 세마포어를 down_read해야
   할 것입니다.
 – policy 구조체로 쓸 것이고(또는) 함께 그 policy를 취해갈(예를 들면, CPU
   핫플러그) 어떤 루틴은 쓰기 전에 쓰기 모드에서 이 락을 잡아야 할 것입니다.
    
 추가적인 규칙:
 – 모든 이 락을 잡고 있는 자들은 그들이 락을 잡은 후에 그들이 신경쓰는 CPU가
   온라인임을 확인하기 위해 검사하여야 합니다.
 – cpufreq 핫플러그 패스에서 호출될 수 있는 가버너 루틴은 이를 취하는 최고 레벨
   핫플러그 노티파이어 핸들러로서 이 세마포어를 취하지 말아야 합니다.
 – __cpufreq_governor(data, CPUFREQ_GOV_STOP); 을 가로지르는 락은 잡지 말아야
   합니다

static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);

 

[Linux:Kernel] Linux CPUFreq User guide

이 문서의 저작권은 GPL을 따릅니다.(This document is released under the GPL license.)

            리눅스(TM) 커널 안의 CPU 주파수와 전압 조정 코드
                         L i n u x    C P U F r e q
                             U S E R   G U I D E
                    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 ARM
1.2 x86
1.3 sparc64
1.4 ppc
1.5 SuperH
1.6 Blackfin
2. “정책” / “가버너”?
2.1 정책
2.2 가버너
3. CPU cpufreq 정책과(또는) 속도를 어떻게 바꾸는지
3.1 선호되는 인터페이스: sysfs
1. 지원되는 아키텍처와 프로세서들
=================================
1.1 ARM
——-
다음의 ARM 프로세서들이 cpufreq 에 의해 지원됩니다:
ARM Integrator
ARM-SA1100
ARM-SA1110
Intel PXA
1.2 x86
——-
다음의 x86 아키텍처의 프로세서들이 cpufreq 에 의해 지원됩니다:
AMD Elan – SC400, SC410
AMD mobile K6-2+
AMD mobile K6-3+
AMD mobile Duron
AMD mobile Athlon
AMD Opteron
AMD Athlon 64
Cyrix Media GXm
Intel mobile PIII 와 확실한 칩셋 상의 Intel mobile PIII-M
Intel Pentium 4, Intel Xeon
Intel Pentium M (Centrino)
National Semiconductors Geode GX
Transmeta Crusoe
Transmeta Efficeon
VIA Cyrix 3 / C3
ACPI 2.0 호환 시스템 상의 다양한 프로세서들 [*]
[*] “ACPI 프로세서 성능 상태” 들이 ACPI<->BIOS 인터페이스로 이용
가능한 경우만.
1.3 sparc64
———–
다음의 sparc64 아키텍처의 프로세서들이 cpufreq 에 의해 지원됩니다:
UltraSPARC-III
1.4 ppc
——-
여러 “PowerBook” 과 “iBook2” 노트북들이 지원됩니다.
1.5 SuperH
———-
클럭 프레임워크를 통해 속도 반올림을 지원하는 모든 SuperH 프로세서가 
cpufreq 에 의해 지원됩니다.
1.6 Blackfin
————
다음의 Blackfin 프로세서들이 cpufreq 에 의해 지원됩니다:
BF522, BF523, BF524, BF525, BF526, BF527, Rev 0.1 또는 그 이상
BF531, BF532, BF533, Rev 0.3 또는 그 이상
BF534, BF536, BF537, Rev 0.2 또는 그 이상
BF561, Rev 0.3 또는 그 이상
BF542, BF544, BF547, BF548, BF549, Rev 0.1 또는 그 이상
2. “정책” / “가버너” ?
======================
몇몇 CPU 주파수 조정-가능 프로세서는 다양한 주파수들과 동작 전압 사이를
“실행 중에” 어떤 커널이나 사용자 간섭없이 변환합니다. 이것은 사용자가
필요로 하는 것을 해주기에 충분히 높은, 그러나 전력을 절약하기에 충분한
주파수로의 매우 빠른 변환을 보장합니다.
2.1 정책
——–
이들 시스템 상에서, 여러분이 할 수 있는 모든 것은 여러분이 더 공격적인
전력-절약을 원하는만큼 또는 더 즉각적인 처리 능력을 원하는지에 맞춰
높고 낮은 주파수 제한 사항을 선택하는 것입니다.
2.2 가버너
———-
모든 다른 cpufreq 구현 상에서, 이들 경계는 여전이 셋팅될 필요가 있습니다.
그럼 “가버너”가 반드시 선택되어야 합니다. 앞서 언급한 “가버너”는 프로세서가
어떤 속도를 경계안에서 사용할 것인지를 결정합니다. 이런 “가버너”는
“사용자공간” 가버너입니다. 이것은 사용자 – 또는 아직 구현되지 않은
사용자공간 프로그램이 그 프로세서가 어떤 지정된 속도로 실행할지를
결정하도록 할 수 있습니다.
3. CPU cpufreq 정책과(또는) 속도를 어떻게 바꾸는지
==================================================
3.1 선호되는 인터페이스: sysfs
——————————
선호되는 인터페이스는 sysfs 파일시스템 안에 위치합니다. 여러분이
/sys에 그것을 마운트하였다면, cpufreq 인터페이스는 cpu-device 디렉토리
안의 그 하위 디렉토리 “cpufreq” 에 위치합니다
(예를 들면, 첫번째 CPU를 위해 /sys/devices/system/cpu/cpu0/cpufreq).
cpuinfo_min_freq :              이 파일은 그 프로세서가 실행할 수 있는 최하
                                동작 주파수(hKz)를 보여줍니다.
cpuinfo_max_freq :              이 파일은 그 프로세서가 실행할 수 있는 최고
                                동작 주파수(kHZ)를 보여줍니다.
cpuinfo_transition_latency      이 CPU 상에서 두 주파수 사이에 변환되는데
                                걸리는 나노초 시간. 알려져 있지 않거나,
                                ondemand 가버너로 그 드라이버가 동작하지
                                않는 높은 값으로 알려지면, -1
                                (CPUFREQ_ETERNAL) 이 반환될 것입니다.
                                이 정보를 사용하는 것은 커널 가버너나
                                사용자공간 대몬을 위한 주파수의 폴링을
                                선택하는데 유용합니다. 성능 저하 상 너무
                                잦은 결과치 산출로 주파수를 변환하지 않도록
                                하세요.
                                
scaling_driver :                이 파일은 이 CPU 상의 주파수를 셋팅하는데
                                무슨 cpufreq 드라이버가 사용되는지 보여줍니다.
scaling_available_governors :   이 파일은 이 커널 안의 사용가능한 CPUfreq
                                가버너들을 보여줍니다. 여러분은 현재 활성화된
                                가버너를 볼 수 있습니다.
scaling_governor,               그리고 다른 가버너의 이름을 “echo함”으로써,
                                여러분은 이를 바꿀 수 있습니다. 어떤 가버너는
                                로딩되지 않을 것임을 알아두세요 – 그들은 오직
                                어떤 지정된 아키텍처나 프로세스들 상에서만
                                동작합니다.
cpuinfo_cur_freq :              하드웨어로부터 얻은 그 CPU의 현재 주파수(kHZ).
                                이 것은 CPU가 실제로 실행되는 주파수입니다.
scaling_available_frequencies : 사용가능한 주파수의 목록(KHz)
scaling_min_freq 와
scaling_max_freq                현재의 “정책 제한 사항”을 보여줍니다(kHz).
                                새로운 값들을 이 파일에 echo함으로써,
                                여러분은 이들 제한 사항을 바꿀 수 있습니다.
                                알림: 여러분이 필요로 하는 정책을 셋팅할 때
                                먼저 scaling_max_freq를 셋팅하고, 그 다음
                                scaling_min_freq를 셋팅하세요.
affected_cpus :                 주파수의 소프트웨어 조정이 요구되는 CPU들의 목록
related_cpus :                  소프트웨어든 하드웨어든 일련의 주파수 조정이
                                필요한 CPU들의 목록
scaling_driver :                cpufreq를 위한 하드웨어 드라이버.
scaling_cur_freq :              가버너와 cpufreq 코어에 의해 결정된 그 CPU의
                                현재 주파수(kHz). 이것은 커널이 그 CPU가
                                실행한다고 생각하는 주파수입니다.
bios_limit :                    BIOS가 OS에게 CPU를 더 낮은 주파수로 제한하라고
                                이야기한다면, 사용자는 이 파일로부터 최고
                                사용가능 주파수를 읽을 수 있습니다. 이것은
                                일반적으로 (종종 의도되지 않은) BIOS 셋팅,
                                서비스 프로세서나 다른 BIOS/HW 기준 구현에
                                의해 발생하는 제약으로부터 발생할 수 있습니다. 
                                일반적인 서멀 드라이버로부터 검출될 수 있는
                                서멀 ACPI 제약 사항들을 포함하여 다루지 않습니다.
                                
여러분이 여러분에게 CPU 동작 주파수를 지정된 값으로 셋팅할 수 있는
“userspace” 가버너를 선택했다면, 여러분은 현재 주파수를 다음에서
읽을 수 있습니다.
scaling_setspeed.               새 주파수를 여기로 “echo함”으로써,
                                여러분은 그 CPU의 속도를 바꿀 수 있습니다.
                                그러나 scaling_min_freq와 scaling_max_freq
                                안의 제약사항안에 있어야 합니다.