[Linux:Kernel] 원형 버퍼(Circular Buffer)

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

      =========
      원형 버퍼
      =========
작성: David Howells <dhowells@redhat.com>
      Paul E. McKenney <paulmck@linux.vnet.ibm.com>
번역: 양정석 <dasomoli@gmailREMOVETHIS.com>
리눅스는 원형 버퍼를 구현하는데 사용할 수 있는 많은 기능을 제공합니다.
다음의 두가지 셋이 있습니다:
 (1) 2의 거듭제곱 크기의 버퍼에 대한 정보를 결정하기 위한 편리한 함수들
 (2) 버퍼 안의 객체의 생산자와 소비자가 하나의 락(lock)을 공유하지 않기를
     원할 때를 위한 메모리 장벽
이들 기능을 사용하기 위해서, 아래에서 논의되는 것처럼, 적어도 하나의 생산자와
하나의 소비자가 있어야 합니다. 여러 생산자를 처리하는 것도 그들을 연속적으로
일렬로 늘어놓는 것으로, 여러 소비자를 처리하는 것도 그들을 연속적으로 일렬로
늘어놓는 것으로써 처리 가능합니다.
내용:
 (*) 원형 버퍼가 뭔가요?
 
 (*) 2의 거듭제곱 버퍼 측정.
 (*) 원형 버퍼와 함께 메모리 장벽 사용하기
     – 생산자.
     – 소비자.
===================
원형 버퍼가 뭔가요?
===================
가장 먼저, 원형 버퍼가 뭘까요? 원형 버퍼는 그 안에 두가지 인덱스가 있는 유한한
크기의 고정된 버퍼입니다:
 (1) ‘헤드(head)’ 인덱스 – 생산자가 항목을 버퍼로 집어넣는 곳
 (2) ‘테일(tail)’ 인덱스 – 소비자가 다음 항목을 버퍼에서 찾는 곳
일반적으로 테일 포인터가 헤드 포인터와 같을 때, 그 버퍼는 빈 것입니다; 그리고 그
버퍼는 헤드 포인터가 테일 포인터보다 하나 작을 때, 가득 찬 것입니다. 
헤드 인덱스는 아이템들이 추가될 때, 테일 인덱스는 아이템들이 제거될 때 증가합니다.
테일 인덱스는 헤드 인덱스를 절대로 넘어설 수 없고, 두 인덱스 모두 그들이 버퍼의
끝에 다다랐을 때, 0으로 다시 돌아와야 합니다. 그래서 무한한 양의 데이터가
그 버퍼를 통해 흐를 수 있습니다.
일반적으로 항목들은 모두 같은 단위 크기이지만, 아래 테크닉을 사용하는 것이
엄격하게 요구되지는 않습니다. 인덱스들은 여러 항목이나 가변 크기의 항목들이
두 인덱스 모두 다른 것을 추월하지 않도록 제공되는 그 버퍼 안으로 포함된다면,
1보다 더 많이 증가할 수 있습니다. 그러나 그 구현자는 한 단위 크기 이상의
한 부분은 버퍼의 끝을 돌 수 있고, 두 세그먼트로 쪼개질 수 있기 때문에 조심해야
합니다.
=======================
2의 거듭제곱 버퍼 측정
=======================
제멋대로인 크기의 원형 버퍼의 사용하거나 남아있는 양의 계산은 보통 나머지
(나누기) 명령의 사용을 필요로 하는 느린 동작이 됩니다. 그러나 버퍼가 2의
거듭제곱 크기라면, 훨씬 빠른 비트-앤드(bitwise-AND) 명령을 대신 사용할 수
있습니다.
리눅스는 2의 거듭 제곱 원형 버퍼를 처리하기 위한 매크로 셋을 제공합니다. 이들은
다음을 통해 사용할 수 있습니다:
#include <linux/circ_buf.h>
그 매크로들은:
  (*) 버퍼의 남은 양 측정:
CIRC_SPACE(head_index, tail_index, buffer_size);
     이것은 항목들이 넣어질 수 있는 그 버퍼[1] 안에 남은 공간의 양을 반환합니다.
 (*) 버퍼 안에 최대로 연이어 붙어있는 공간 측정:
CIRC_SPACE_TO_END(head_index, tail_index, buffer_size);
     이것은 항목들이 다시 그 버퍼의 처음으로 돌아가는 것 없이 즉시 삽입되어질
     수 있는 그 버퍼[1] 안에 남은 연이은 공간의 양을 반환합니다.
 (*) 버퍼의 사용량 측정:
CIRC_CNT(head_index, tail_index, buffer_size);
     이것은 현재 버퍼[2]를 사용하는 항목 수를 반환합니다
 (*) 처음으로 돌아가는 것이 없을 때(non-wrapping)의 버퍼 사용량 측정:
CIRC_CNT_TO_END(head_index, tail_index, buffer_size);
     이것은 다시 그 버퍼의 처음으로 돌아가는 것 없이 뽑아 낼 수 있는 연이은
     항목들[2]의 수를 반환합니다.
이들 매크로 각각은 명목상으로 0 에서 buffer_size-1 사이의 값을 반환할 것입니다.
그러나:
 [1] CIRC_SPACE*() 들은 생산자 안에서 사용되도록 의도되었습니다. 생산자에게
     그들은 생산자가 헤드 인덱스를 제어하기 때문에 하한값을 반환할 것입니다.
     그러나 소비자는 여전히 다른 CPU 상에서 그 버퍼를 감소시키고, 테일 인덱스를
     옮기고 있을 수 있습니다.
     생산자가 그 공간을 바쁘게 감소시킬 수 있기 때문에, 소비자에게 그것은
     상한값을 보여줄 것입니다.
 [2] CIRC_CNT*() 들은 소비자 안에서 사용되도록 의도되었습니다. 소비자에게
     그들은 소비자가 테일 인덱스를 제어하기 때문에 하한값을 반환할 것입니다.
     그러나 생산자는 여전히 다른 CPU 상에서 그 버퍼를 채우고, 헤드 인덱스를
     옮기고 있을 수 있습니다.
     소비자가 그 버퍼를 바쁘게 비울 수 있기 때문에, 생산자에게 그것은 상한값을
     보여줄 것입니다.
 [3] 서드 파티에게는, 생산자와 소비자가 보여질 수 있게 되어감에 의해, 그
     인덱스들에 쓰는 순서는 그들이 독립적이고, 다른 CPU 상에서 생성될 있기 때문에
     보장될 수 없습니다. 그래서 이런 상황에서의 결과는 그저 추정이 될 것이고, 아예
     틀릴 수도 있습니다.
=======================================
원형 버퍼와 함께 메모리 장벽 사용하기
=======================================
원형 버퍼와 함께 메모리 장벽을 사용함으로써, 여러분은 다음을 위한 욕구를
피할 수 있습니다.
 (1) 그 버퍼의 양 끝으로의 접근을 다스리기 위한 단일 락(lock) 사용, 그래서
     그 버퍼가 동시에 채우고 비울 수 있는; 그리고
 (2) 어토믹(atomic) 카운터 연산 사용
이를 위한 두 편이 있습니다: 그 버퍼를 채우는 생산자, 그를 비우는 소비자.
어느 한번에 하나만 버퍼를 채워야 하고, 어느 한번에 하나만 버퍼를 비워야 합니다만,
두 편은 동시에 수행할 수 있습니다.
생산자
——
생산자는 이처럼 보일 것입니다:
spin_lock(&producer_lock);
unsigned long head = buffer->head;
unsigned long tail = ACCESS_ONCE(buffer->tail);
if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
/* 버퍼로 아이템 하나를 넣어라 */
struct item *item = buffer[head];
produce_item(item);
smp_wmb(); /* 헤드를 증가시키기 전에 항목을 넣어라 */
buffer->head = (head + 1) & (buffer->size – 1);
/* wake_up() 은 어느 하나가 깨기 전에 헤드가 제출됐음을 확인할
* 것이다 */
wake_up(consumer);
}
spin_unlock(&producer_lock);
이는 CPU가 새로운 항목의 내용을 헤드 인덱스가 소비자에게 사용가능하게 만들기
전에 반드시 쓰여져야 한다는 것을 지시할 것이고, 그 후 그 CPU가 소비자가 깨기
전에 바뀐 헤드 인덱스가 쓰여져야만 함을 지시합니다.
wake_up() 이 꼭 사용하는 그 메카니즘일 필요는 없지만, 만약 상태 변경이 일어난다면,
사용되는 아무 것이나 헤드 인덱스의 갱신과 소비자의 상태 변경 사이에 반드시 한번의
(쓰기) 메모리 장벽을 보장해야 함을 명심하세요.
소비자
——
소비자는 이처럼 보일 것입니다:
spin_lock(&consumer_lock);
unsigned long head = ACCESS_ONCE(buffer->head);
unsigned long tail = buffer->tail;
if (CIRC_CNT(head, tail, buffer->size) >= 1) {
/* 그 인덱스에 있는 내용을 읽기 전에 인덱스를 읽어라 */
smp_read_barrier_depends();
/* 버퍼로부터 하나의 항목을 꺼내라 */
struct item *item = buffer[tail];
consume_item(item);
smp_mb(); /* 테일을 증가시키기 전에 서술자 읽기를 끝내라 */
buffer->tail = (tail + 1) & (buffer->size – 1);
}
spin_unlock(&consumer_lock);
이는 CPU가 새로운 항목을 읽기 전에 그 인덱스가 올라갔음을 확인할 것을 지시할
것이고, 그 후 CPU가 그 항목을 지울 새로운 테일 포인터를 쓰기 전에 그 항목
읽기를 끝냈음을 확인하도록 합니다.
반대 인덱스를 읽기 위한 두 알고리듬 안에 ACCESS_ONCE() 의 사용에 주의하세요.
이것은 컴파일러가 그들의 캐시된 값-어떤 컴파일러는 smp_read_barrier_depends()를
가로질러 수행하는-을 버리고 재로딩하는 것을 막습니다. 여러분이 반대 인덱스가
한 번만 사용될 거라고 알 수 있다면, 이것이 엄격히 필요하지는 않습니다.
=============
더 읽을 거리
=============
리눅스의 메모리 장벽 기능에 대한 설명을 위해 Documentation/memory-barriers.txt도
보세요.

[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);

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